All files implementation.js

95% Statements 76/80
75% Branches 15/20
100% Functions 15/15
95% Lines 76/80

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208    1x 1x 1x 1x 1x 1x         2458x 2458x 2458x 2458x 2458x 2458x       3535x       2449x       45x       2449x       2449x       2449x                       2458x       2458x 2413x 2413x 2413x 2413x   2413x   45x   39x     6x               2413x 2413x 80x   2413x 2413x                     2404x 2404x 2404x 3504x 3504x   2404x 2404x 2404x 3504x   2404x 2404x 2404x       2404x                                   6x 6x 6x     6x     6x 6x 6x   6x     6x 6x 6x           6x     6x     6x     6x 6x 11x   6x 6x   5x       5x     5x     5x   1x 1x 1x                       39x 39x       39x             1x  
'use strict';
 
const builtins = require( './builtins.js' );
const { containsError, traverseZList } = require( './utils.js' );
const { ZWrapper } = require( './ZWrapper' );
const { convertItemArrayToZList, makeMappedResultEnvelope } = require( '../function-schemata/javascript/src/utils.js' );
const { error, normalError } = require( '../function-schemata/javascript/src/error.js' );
const { makeVoid } = require( '../function-schemata/javascript/src/utils' );
 
class Implementation {
 
	constructor( Z14 ) {
		this.invariants_ = null;
		this.scope_ = null;
		this.lazyVariables_ = new Set();
		this.lazyReturn_ = false;
		this.doValidate_ = true;
		this.Z14_ = Z14;
	}
 
	hasLazyVariable( variableName ) {
		return this.lazyVariables_.has( variableName );
	}
 
	returnsLazy() {
		return this.lazyReturn_;
	}
 
	async execute( zobject, argumentList ) {
		return ZWrapper.create( await this.executeInternal( zobject, argumentList ) );
	}
 
	setScope( scope ) {
		this.scope_ = scope;
	}
 
	setInvariants( invariants ) {
		this.invariants_ = invariants;
	}
 
	setDoValidate( doValidate ) {
		this.doValidate_ = doValidate;
	}
 
	/**
	 * Retrieves a function implementation (or an in-memory JS function if a
	 * built-in). Function implementation may be a function, a serializer for
	 * ZObjects, or a deserializer for ZObject.
	 *
	 * @param {Object} Z14 the implementation
	 * @return {Implementation} the implementation
	 */
	static create( Z14 ) {
		Iif ( typeof Z14 === 'undefined' ) {
			return null;
		}
 
		if ( Z14.Z14K4 !== undefined ) {
			const ZID = Z14.Z14K4.Z6K1;
			const builtin = builtins.getFunction( ZID );
			const lazyVariables = builtins.getLazyVariables( ZID );
			const lazyReturn = builtins.getLazyReturn( ZID );
			// eslint-disable-next-line no-use-before-define
			return new BuiltIn( Z14, builtin, lazyVariables, lazyReturn );
		}
		if ( Z14.Z14K2 !== undefined ) {
			// eslint-disable-next-line no-use-before-define
			return new Composition( Z14 );
		}
		// eslint-disable-next-line no-use-before-define
		return new Evaluated( Z14 );
	}
 
}
 
class BuiltIn extends Implementation {
 
	constructor( Z14, functor, lazyVariables, lazyReturn ) {
		super( Z14 );
		for ( const variable of lazyVariables ) {
			this.lazyVariables_.add( variable );
		}
		this.lazyReturn_ = lazyReturn;
		this.functor_ = functor;
	}
 
	/**
	 * Calls this implementation's functor with the provided arguments.
	 *
	 * @param {Object} zobject
	 * @param {Array} argumentList
	 * @return {Object} the result of calling this.functor_ with provided arguments
	 */
	async executeInternal( zobject, argumentList ) {
		const keys = [];
		const nameToArgument = new Map();
		for ( const argumentDict of argumentList ) {
			keys.push( argumentDict.name );
			nameToArgument.set( argumentDict.name, argumentDict.argument );
		}
		keys.sort();
		const callArgs = [];
		for ( const key of keys ) {
			callArgs.push( nameToArgument.get( key ) );
		}
		callArgs.push( this.invariants_ );
		callArgs.push( this.scope_ );
		return this.functor_( ...callArgs );
	}
 
	async execute( zobject, argumentList ) {
		return ZWrapper.create( await this.executeInternal( zobject, argumentList ) );
	}
 
}
 
class Evaluated extends Implementation {
 
	/**
	 * Calls this implementation's functor with the provided arguments.
	 *
	 * @param {Object} zobject
	 * @param {Array} argumentList
	 * @return {Object} the result of calling this.functor_ with provided arguments
	 */
	async executeInternal( zobject, argumentList ) {
		// Arguments should already be fully resolved, but any other attributes
		// of the Z7 which are Z9s/Z18s must be resolved before dispatching
		// to the function evaluator.
		const Z7 = {};
		Z7.Z1K1 = zobject.Z1K1.asJSON();
		await ( zobject.resolveKey(
			[ 'Z7K1', 'Z8K2' ], this.invariants_, this.scope_, /* ignoreList= */ null,
			/* resolveInternals= */ true, this.doValidate_ ) );
		const Z7K1Envelope = await ( zobject.Z7K1.resolve(
			this.invariants_, this.scope_, /* ignoreList= */ null,
			/* resolveInternals= */ true, this.doValidate_ ) );
		const Z7K1 = Z7K1Envelope.Z22K1;
		Z7.Z7K1 = Z7K1.asJSON();
		const Z8K4 = ZWrapper.create( await convertItemArrayToZList( [ this.Z14_.asJSON() ] ) );
 
		const implementation = this;
 
		// Implementation may need to be dereferenced.
		await traverseZList( Z8K4, async function ( tail ) {
			Eif ( tail.K1.Z14K3 !== undefined ) {
				await ( tail.resolveKey(
					[ 'K1', 'Z14K3', 'Z16K2' ], implementation.invariants_,
					implementation.scope_, /* ignoreList= */ null,
					/* resolveInternals= */ false, implementation.doValidate_ ) );
			}
		} );
		Z7.Z7K1.Z8K4 = Z8K4.asJSON();
 
		// Return type may be a function call and must be resolved to allow for serialization.
		const returnTypeEnvelope = await ( Z7K1.Z8K2.resolve(
			this.invariants_, this.scope_, /* ignoreList= */ null,
			/* resolveInternals= */ true, this.doValidate_ ) );
		Iif ( containsError( returnTypeEnvelope ) ) {
			return returnTypeEnvelope;
		}
		Z7.Z7K1.Z8K2 = returnTypeEnvelope.Z22K1.asJSON();
		for ( const argumentDict of argumentList ) {
			Z7[ argumentDict.name ] = argumentDict.argument.asJSON();
		}
		const fetchedResult = await this.invariants_.evaluator.evaluate( Z7 );
		if ( fetchedResult.ok ) {
			// Assume the evaluator is returning Z22s.
			const resultEnvelope = await fetchedResult.json();
			// Transitional code: replace Z23 with Z24 (void)
			// TODO (T285433): After function-schemata updates for this ticket,
			// remove transitional code
			Iif ( resultEnvelope.Z22K1 === 'Z23' || resultEnvelope.Z22K1.Z9K1 === 'Z23' ) {
				resultEnvelope.Z22K1 = makeVoid();
			}
			Iif ( resultEnvelope.Z22K2 === 'Z23' || resultEnvelope.Z22K2.Z9K1 === 'Z23' ) {
				resultEnvelope.Z22K2 = makeVoid();
			}
			return resultEnvelope;
		}
		const statusCode = fetchedResult.status;
		const errorText = await fetchedResult.text();
		return makeMappedResultEnvelope(
			null,
			normalError(
				[ error.error_in_evaluation ],
				[ `Function evaluation failed with status ${statusCode}: ${errorText}` ] ) );
	}
 
}
 
class Composition extends Implementation {
 
	constructor( Z14 ) {
		super( Z14 );
		this.composition_ = ZWrapper.create( Z14.Z14K2.asJSON() );
	}
 
	async executeInternal() {
		return await this.composition_.resolve(
			this.invariants_, this.scope_, /* ignoreList= */ null, /* resolveInternals= */ true,
			/* doValidate= */ this.doValidate_ );
	}
 
}
 
module.exports = { Composition, Evaluated, Implementation };