/
evaluate-constructor-declaration.ts
68 lines (55 loc) · 2.67 KB
/
evaluate-constructor-declaration.ts
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
import type {EvaluatorOptions} from "./evaluator-options.js";
import type {LexicalEnvironment} from "../lexical-environment/lexical-environment.js";
import {pathInLexicalEnvironmentEquals, setInLexicalEnvironment} from "../lexical-environment/lexical-environment.js";
import {cloneLexicalEnvironment} from "../lexical-environment/clone-lexical-environment.js";
import type {IndexLiteral, Literal} from "../literal/literal.js";
import {evaluateParameterDeclarations} from "./evaluate-parameter-declarations.js";
import {THIS_SYMBOL} from "../util/this/this-symbol.js";
import {RETURN_SYMBOL} from "../util/return/return-symbol.js";
import type {TS} from "../../type/ts.js";
/**
* Evaluates, or attempts to evaluate, a ConstructorDeclaration
*/
export function evaluateConstructorDeclaration(options: EvaluatorOptions<TS.ConstructorDeclaration>): void {
const {node, environment, evaluate, stack, getCurrentError} = options;
/**
* An implementation of a constructor function
*/
function constructor(this: IndexLiteral, ...args: Literal[]) {
// Don't concern yourself with calling super here as this constructor is called immediately after calling super() in another memory representation of a class
// Prepare a lexical environment for the function context
const localLexicalEnvironment: LexicalEnvironment = cloneLexicalEnvironment(environment, node);
const nextOptions = {...options, environment: localLexicalEnvironment};
// Define a new binding for a return symbol within the environment
setInLexicalEnvironment({...nextOptions, path: RETURN_SYMBOL, value: false, newBinding: true});
// Define a new binding for the arguments given to the function
// eslint-disable-next-line prefer-rest-params
setInLexicalEnvironment({...nextOptions, path: "arguments", value: arguments, newBinding: true});
if (this != null) {
setInLexicalEnvironment({...nextOptions, path: THIS_SYMBOL, value: this, newBinding: true});
}
// Evaluate the parameters based on the given arguments
evaluateParameterDeclarations(
{
...nextOptions,
node: node.parameters
},
args,
this
);
// If the body is a block, evaluate it as a statement
if (node.body == null || getCurrentError() != null) return;
evaluate.statement(node.body, nextOptions);
if (getCurrentError() != null) {
return;
}
// If a 'return' has occurred within the block, pop the Stack and return that value
if (pathInLexicalEnvironmentEquals(node, localLexicalEnvironment, true, RETURN_SYMBOL)) {
return stack.pop();
}
// Otherwise, return 'undefined'. Nothing is returned from the function
else return undefined;
}
constructor.toString = () => "[Function: constructor]";
stack.push(constructor);
}