Skip to content

Commit ba61a5e

Browse files
committed
Getters & setters (static); Instantiate compiler tests; Cleanup
1 parent 5c4bf1a commit ba61a5e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2358
-1951
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ See [the AssemblyScript wiki](https://github.com/AssemblyScript/assemblyscript/w
4646
Building
4747
--------
4848

49-
Building an UMD bundle to `dist/assemblyscript.js` (does not bundle [binaryen.js](https://github.com/AssemblyScript/binaryen.js) which remains an external dependency):
49+
Building an UMD bundle to `dist/assemblyscript.js` ([binaryen.js](https://github.com/AssemblyScript/binaryen.js) remains an external dependency):
5050

5151
```
5252
$> npm run build

examples/i64-polyfill/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
},
1313
"main": "index.js",
1414
"types": "index.d.ts",
15+
"engines": {
16+
"node": ">=8"
17+
},
1518
"scripts": {
1619
"build": "npm run build:untouched && npm run build:optimized",
1720
"build:untouched": "asc assembly/i64.ts -t i64.untouched.wast -b i64.untouched.wasm --noMemory --validate",

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
"bin": {
3838
"asc": "bin/asc"
3939
},
40+
"engines": {
41+
"node" : ">=8"
42+
},
4043
"scripts": {
4144
"build": "webpack",
4245
"clean": "rm dist/assemblyscript.*",

src/builtins.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import {
3434
Local
3535
} from "./program";
3636

37-
/** Initializes the specified program with built-in functions. */
37+
/** Initializes the specified program with built-in constants and functions. */
3838
export function initialize(program: Program): void {
3939

4040
// math
@@ -162,7 +162,7 @@ function addFunction(program: Program, name: string, isGeneric: bool = false): F
162162
}
163163

164164
/** Compiles a get of a built-in global. */
165-
export function compileGetGlobal(compiler: Compiler, global: Global): ExpressionRef {
165+
export function compileGetConstant(compiler: Compiler, global: Global): ExpressionRef {
166166
switch (global.internalName) {
167167

168168
case "NaN":

src/compiler.ts

Lines changed: 108 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
22
compileCall as compileBuiltinCall,
3-
compileGetGlobal as compileBuiltinGetGlobal
3+
compileGetConstant as compileBuiltinGetConstant
44
} from "./builtins";
55

66
import {
@@ -37,7 +37,8 @@ import {
3737
Local,
3838
Namespace,
3939
Parameter,
40-
EnumValue
40+
EnumValue,
41+
Property
4142
} from "./program";
4243

4344
import {
@@ -49,7 +50,8 @@ import {
4950
NodeKind,
5051
TypeNode,
5152
Source,
52-
// statements
53+
54+
Statement,
5355
BlockStatement,
5456
BreakStatement,
5557
ClassDeclaration,
@@ -70,7 +72,6 @@ import {
7072
ModifierKind,
7173
NamespaceDeclaration,
7274
ReturnStatement,
73-
Statement,
7475
SwitchCase,
7576
SwitchStatement,
7677
ThrowStatement,
@@ -79,12 +80,12 @@ import {
7980
VariableDeclaration,
8081
VariableStatement,
8182
WhileStatement,
82-
// expressions
83+
84+
Expression,
8385
AssertionExpression,
8486
BinaryExpression,
8587
CallExpression,
8688
ElementAccessExpression,
87-
Expression,
8889
FloatLiteralExpression,
8990
IdentifierExpression,
9091
IntegerLiteralExpression,
@@ -97,7 +98,7 @@ import {
9798
StringLiteralExpression,
9899
UnaryPostfixExpression,
99100
UnaryPrefixExpression,
100-
// utility
101+
101102
hasModifier
102103
} from "./ast";
103104

@@ -340,7 +341,7 @@ export class Compiler extends DiagnosticEmitter {
340341
}
341342

342343
compileGlobal(global: Global): bool {
343-
if (global.isCompiled || (global.isBuiltIn && compileBuiltinGetGlobal(this, global)))
344+
if (global.isCompiled || (global.isBuiltIn && compileBuiltinGetConstant(this, global)))
344345
return true;
345346

346347
const declaration: VariableLikeDeclarationStatement | null = global.declaration;
@@ -582,6 +583,21 @@ export class Compiler extends DiagnosticEmitter {
582583
return true;
583584
}
584585

586+
// compilePropertyUsingTypeArguments(prototype: PropertyPrototype, contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): Function | null {
587+
// let getter: Function | null = null;
588+
// let setter: Function | null = null;
589+
// if (prototype.getterPrototype) {
590+
// getter = prototype.getterPrototype.resolve([], contextualTypeArguments); // reports
591+
// if (prototype.setterPrototype)
592+
// setter = prototype.setterPrototype.resolve([], contextualTypeArguments); // reports
593+
// }
594+
595+
// }
596+
597+
// compileProperty(instance: Property): bool {
598+
599+
// }
600+
585601
// namespaces
586602

587603
compileNamespaceDeclaration(declaration: NamespaceDeclaration): void {
@@ -1625,37 +1641,83 @@ export class Compiler extends DiagnosticEmitter {
16251641
compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): ExpressionRef {
16261642
let element: Element | null = null;
16271643
switch (expression.kind) {
1644+
16281645
case NodeKind.IDENTIFIER:
16291646
element = this.program.resolveIdentifier(<IdentifierExpression>expression, this.currentFunction); // reports
16301647
break;
1648+
16311649
case NodeKind.PROPERTYACCESS:
16321650
element = this.program.resolvePropertyAccess(<PropertyAccessExpression>expression, this.currentFunction); // reports
16331651
break;
1652+
16341653
default:
16351654
this.error(DiagnosticCode.Operation_not_supported, expression.range);
16361655
}
16371656
if (!element)
16381657
return this.module.createUnreachable();
1658+
16391659
let type: Type | null = null;
16401660
switch (element.kind) {
1661+
16411662
case ElementKind.LOCAL:
16421663
type = (<Local>element).type;
16431664
break;
1665+
16441666
case ElementKind.GLOBAL:
16451667
if (this.compileGlobal(<Global>element))
16461668
type = (<Global>element).type;
16471669
break;
1670+
1671+
case ElementKind.PROPERTY:
1672+
const setterPrototype: FunctionPrototype | null = (<Property>element).setterPrototype;
1673+
if (setterPrototype) {
1674+
const setterInstance: Function | null = setterPrototype.resolve(); // reports
1675+
if (setterInstance) {
1676+
if (contextualType == Type.void) { // just set if dropped anyway
1677+
return this.compileCall(setterInstance, [ valueExpression ], expression);
1678+
} else { // otherwise do a set followed by a get
1679+
const getterPrototype: FunctionPrototype | null = (<Property>element).getterPrototype;
1680+
if (getterPrototype) {
1681+
const getterInstance: Function | null = getterPrototype.resolve(); // reports
1682+
if (getterInstance) {
1683+
return this.module.createBlock(null, [
1684+
this.compileCall(setterInstance, [ valueExpression ], expression),
1685+
this.compileCall(getterInstance, [], expression)
1686+
], getterInstance.returnType.toNativeType());
1687+
}
1688+
} else
1689+
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, expression.range, (<Property>element).simpleName, (<Property>element).parent.internalName);
1690+
}
1691+
}
1692+
} else
1693+
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, expression.range, (<Property>element).simpleName, (<Property>element).parent.internalName);
1694+
return this.module.createUnreachable();
1695+
16481696
default:
16491697
this.error(DiagnosticCode.Operation_not_supported, expression.range);
16501698
}
16511699
if (!type)
16521700
return this.module.createUnreachable();
1701+
16531702
this.currentType = type;
16541703
return this.compileAssignmentWithValue(expression, this.compileExpression(valueExpression, type, ConversionKind.IMPLICIT), contextualType != Type.void);
16551704
}
16561705

16571706
compileAssignmentWithValue(expression: Expression, valueWithCorrectType: ExpressionRef, tee: bool = false): ExpressionRef {
1658-
const element: Element | null = this.program.resolveElement(expression, this.currentFunction);
1707+
let element: Element | null = null;
1708+
switch (expression.kind) {
1709+
1710+
case NodeKind.IDENTIFIER:
1711+
element = this.program.resolveIdentifier(<IdentifierExpression>expression, this.currentFunction);
1712+
break;
1713+
1714+
case NodeKind.PROPERTYACCESS:
1715+
element = this.program.resolvePropertyAccess(<PropertyAccessExpression>expression, this.currentFunction);
1716+
break;
1717+
1718+
default:
1719+
this.error(DiagnosticCode.Operation_not_supported, expression.range);
1720+
}
16591721
if (!element)
16601722
return this.module.createUnreachable();
16611723

@@ -1693,7 +1755,21 @@ export class Compiler extends DiagnosticEmitter {
16931755
}
16941756

16951757
compileCallExpression(expression: CallExpression, contextualType: Type): ExpressionRef {
1696-
const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports
1758+
let element: Element | null = null;
1759+
switch (expression.expression.kind) {
1760+
// case NodeKind.SUPER:
1761+
1762+
case NodeKind.IDENTIFIER:
1763+
element = this.program.resolveIdentifier(<IdentifierExpression>expression.expression, this.currentFunction);
1764+
break;
1765+
1766+
case NodeKind.PROPERTYACCESS:
1767+
element = this.program.resolvePropertyAccess(<PropertyAccessExpression>expression.expression, this.currentFunction);
1768+
break;
1769+
1770+
default:
1771+
throw new Error("not implemented");
1772+
}
16971773
if (!element)
16981774
return this.module.createUnreachable();
16991775

@@ -1837,7 +1913,7 @@ export class Compiler extends DiagnosticEmitter {
18371913
// global
18381914
if (element.kind == ElementKind.GLOBAL) {
18391915
if (element.isBuiltIn)
1840-
return compileBuiltinGetGlobal(this, <Global>element);
1916+
return compileBuiltinGetConstant(this, <Global>element);
18411917

18421918
const global: Global = <Global>element;
18431919
if (!this.compileGlobal(global)) // reports
@@ -1984,16 +2060,17 @@ export class Compiler extends DiagnosticEmitter {
19842060
if (target.members) {
19852061
element = target.members.get(propertyName);
19862062
if (!element) {
1987-
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName);
2063+
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName, target.internalName);
19882064
return this.module.createUnreachable();
19892065
}
19902066

19912067
// handle enum values right away
19922068
if (element.kind == ElementKind.ENUMVALUE) {
19932069
this.currentType = Type.i32;
1994-
return (<EnumValue>element).hasConstantValue
1995-
? this.module.createI32((<EnumValue>element).constantValue)
1996-
: this.module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32);
2070+
if ((<EnumValue>element).hasConstantValue)
2071+
return this.module.createI32((<EnumValue>element).constantValue)
2072+
this.compileEnum((<EnumValue>element).enum);
2073+
return this.module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32);
19972074
}
19982075
} else {
19992076
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName, target.internalName);
@@ -2013,21 +2090,26 @@ export class Compiler extends DiagnosticEmitter {
20132090
return this.module.createUnreachable();
20142091
this.currentType = <Type>(<Global>element).type;
20152092
if ((<Global>element).hasConstantValue)
2016-
return this.currentType== Type.f32
2017-
? this.module.createF32((<Global>element).constantFloatValue)
2018-
: this.currentType == Type.f64
2019-
? this.module.createF64((<Global>element).constantFloatValue)
2020-
: this.currentType.isLongInteger
2021-
? this.module.createI64((<I64>(<Global>element).constantIntegerValue).lo, (<I64>(<Global>element).constantIntegerValue).hi)
2022-
: this.module.createI32((<I64>(<Global>element).constantIntegerValue).lo);
2093+
return this.currentType== Type.f32 ? this.module.createF32((<Global>element).constantFloatValue)
2094+
: this.currentType == Type.f64 ? this.module.createF64((<Global>element).constantFloatValue)
2095+
: this.currentType.isLongInteger
2096+
? this.module.createI64((<I64>(<Global>element).constantIntegerValue).lo, (<I64>(<Global>element).constantIntegerValue).hi)
2097+
: this.module.createI32((<I64>(<Global>element).constantIntegerValue).lo);
20232098
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
20242099

2025-
case ElementKind.FUNCTION: // getter
2026-
if (!(<Function>element).prototype.isGetter) {
2027-
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName, element.internalName);
2100+
case ElementKind.PROPERTY: // getter
2101+
const getterPrototype: FunctionPrototype | null = (<Property>element).getterPrototype;
2102+
if (getterPrototype) {
2103+
const getterInstance: Function | null = getterPrototype.resolve([], this.currentFunction.contextualTypeArguments);
2104+
if (getterInstance) {
2105+
return this.compileCall(getterInstance, [], propertyAccess);
2106+
} else {
2107+
return this.module.createUnreachable();
2108+
}
2109+
} else {
2110+
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName, target.internalName);
20282111
return this.module.createUnreachable();
20292112
}
2030-
return this.compileCall(<Function>element, [], propertyAccess);
20312113
}
20322114
this.error(DiagnosticCode.Operation_not_supported, propertyAccess.range);
20332115
throw new Error("not implemented");

src/diagnosticMessages.generated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export enum DiagnosticCode {
6666
Cannot_invoke_an_expression_whose_type_lacks_a_call_signature_Type_0_has_no_compatible_call_signatures = 2349,
6767
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
6868
The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access = 2364,
69+
_get_and_set_accessor_must_have_the_same_type = 2380,
6970
Constructor_implementation_is_missing = 2390,
7071
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
7172
Duplicate_function_implementation = 2393,
@@ -146,6 +147,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
146147
case 2349: return "Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.";
147148
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
148149
case 2364: return "The left-hand side of an assignment expression must be a variable or a property access.";
150+
case 2380: return "'get' and 'set' accessor must have the same type.";
149151
case 2390: return "Constructor implementation is missing.";
150152
case 2391: return "Function implementation is missing or not immediately following the declaration.";
151153
case 2393: return "Duplicate function implementation.";

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.": 2349,
6767
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
6868
"The left-hand side of an assignment expression must be a variable or a property access.": 2364,
69+
"'get' and 'set' accessor must have the same type.": 2380,
6970
"Constructor implementation is missing.": 2390,
7071
"Function implementation is missing or not immediately following the declaration.": 2391,
7172
"Duplicate function implementation.": 2393,

src/parser.ts

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -608,12 +608,8 @@ export class Parser extends DiagnosticEmitter {
608608
returnType = this.parseType(tn, isSetter);
609609
if (!returnType)
610610
return null;
611-
} else {
612-
if (isSetter) {
613-
if (parameters.length)
614-
returnType = parameters[0].type;
615-
} else
616-
this.error(DiagnosticCode.Type_expected, tn.range(tn.pos)); // recoverable
611+
} else if (!isSetter) {
612+
this.error(DiagnosticCode.Type_expected, tn.range(tn.pos)); // recoverable
617613
}
618614
const isDeclare: bool = hasModifier(ModifierKind.DECLARE, modifiers);
619615
let statements: Statement[] | null = null;
@@ -765,13 +761,8 @@ export class Parser extends DiagnosticEmitter {
765761
returnType = this.parseType(tn, identifier.kind == NodeKind.CONSTRUCTOR || isSetter);
766762
if (!returnType)
767763
return null;
768-
} else {
769-
if (isSetter) {
770-
if (parameters.length)
771-
returnType = parameters[0].type;
772-
} else if (identifier.kind != NodeKind.CONSTRUCTOR)
773-
this.error(DiagnosticCode.Type_expected, tn.range()); // recoverable
774-
}
764+
} else if (!isSetter && identifier.kind != NodeKind.CONSTRUCTOR)
765+
this.error(DiagnosticCode.Type_expected, tn.range()); // recoverable
775766
let statements: Statement[] | null = null;
776767
if (tn.skip(Token.OPENBRACE)) {
777768
if (parentIsDeclare)

0 commit comments

Comments
 (0)