Skip to content

Commit

Permalink
fix(bug): fixes an issue where constructor arguments with a [public|p…
Browse files Browse the repository at this point in the history
…rotected|private] modifier wouldn't be set on the class instance as instance properties. Fixes #10
  • Loading branch information
wessberg committed Dec 30, 2018
1 parent 36f71a4 commit 2e091c0
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 6 deletions.
6 changes: 3 additions & 3 deletions src/interpreter/evaluator/evaluate-constructor-declaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {IEvaluatorOptions} from "./i-evaluator-options";
import {ConstructorDeclaration} from "typescript";
import {LexicalEnvironment, pathInLexicalEnvironmentEquals, setInLexicalEnvironment} from "../lexical-environment/lexical-environment";
import {cloneLexicalEnvironment} from "../lexical-environment/clone-lexical-environment";
import {Literal} from "../literal/literal";
import {IndexLiteral, Literal} from "../literal/literal";
import {evaluateParameterDeclarations} from "./evaluate-parameter-declarations";
import {THIS_SYMBOL} from "../util/this/this-symbol";
import {RETURN_SYMBOL} from "../util/return/return-symbol";
Expand All @@ -18,7 +18,7 @@ export function evaluateConstructorDeclaration ({node, environment, evaluate, st
* An implementation of a constructor function
* @param {Literal} args
*/
function constructor (this: Literal, ...args: Literal[]) {
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
Expand All @@ -42,7 +42,7 @@ export function evaluateConstructorDeclaration ({node, environment, evaluate, st
stack,
reporting,
...rest
}, args
}, args, this
);

// If the body is a block, evaluate it as a statement
Expand Down
23 changes: 20 additions & 3 deletions src/interpreter/evaluator/evaluate-parameter-declarations.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import {IEvaluatorOptions} from "./i-evaluator-options";
import {isIdentifier, NodeArray, ParameterDeclaration} from "typescript";
import {Literal} from "../literal/literal";
import {isIdentifier, NodeArray, ParameterDeclaration, SyntaxKind} from "typescript";
import {IndexLiteral, Literal} from "../literal/literal";
import {hasModifier} from "../util/modifier/has-modifier";
import {getFromLexicalEnvironment} from "../lexical-environment/lexical-environment";

/**
* Evaluates, or attempts to evaluate, a NodeArray of ParameterDeclarations
* @param {IEvaluatorOptions<NodeArray<ParameterDeclaration>>} options
* @param {Literal[]} boundArguments
* @param {IndexLiteral} [context]
*/
export function evaluateParameterDeclarations ({node, evaluate, environment, statementTraversalStack}: IEvaluatorOptions<NodeArray<ParameterDeclaration>>, boundArguments: Literal[]): void {
export function evaluateParameterDeclarations ({node, evaluate, environment, statementTraversalStack}: IEvaluatorOptions<NodeArray<ParameterDeclaration>>, boundArguments: Literal[], context?: IndexLiteral): void {
// 'this' is a special parameter which is removed from the emitted results
const parameters = node.filter(param => !(isIdentifier(param.name) && param.name.text === "this"));

Expand All @@ -23,6 +26,20 @@ export function evaluateParameterDeclarations ({node, evaluate, environment, sta

else {
evaluate.nodeWithArgument(parameter, environment, boundArguments[i], statementTraversalStack);

// If a context is given, and if a [public|protected|private] keyword is in front of the parameter, the initialized value should be
// set on the context as an instance property
if (context != null && isIdentifier(parameter.name) && (
hasModifier(parameter, SyntaxKind.PublicKeyword) ||
hasModifier(parameter, SyntaxKind.ProtectedKeyword) ||
hasModifier(parameter, SyntaxKind.PrivateKeyword)
)
) {
const value = getFromLexicalEnvironment(parameter, environment, parameter.name.text);
if (value != null) {
context[parameter.name.text] = value.literal;
}
}
}
}
}
23 changes: 23 additions & 0 deletions test/class-declaration/class-declaration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,4 +251,27 @@ test("Can handle SetAccessorDeclarations. #1", t => {
instance.prop = 2;
t.deepEqual(instance.prop, 2);
}
});

test("Can handle instances properties set via Constructor arguments. #1", t => {
const {evaluate} = prepareTest(
// language=TypeScript
`
class MyClass {
constructor (public foo = 2) {}
}
(() => MyClass)();
`,
"(() =>"
);

const result = evaluate();

if (!result.success) t.fail(result.reason.stack);
else if (result.value == null) t.fail();
else {
const instance = new (result.value as (new () => { foo: number }))();
t.deepEqual(instance.foo, 2);
}
});

0 comments on commit 2e091c0

Please sign in to comment.