mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-16 00:11:28 +00:00
Operator overload preparations
This commit is contained in:
40
src/ast.ts
40
src/ast.ts
@ -351,6 +351,31 @@ export abstract class Node {
|
||||
if (stmt.arguments = args)
|
||||
for (var i: i32 = 0, k: i32 = (<Expression[]>args).length; i < k; ++i)
|
||||
(<Expression[]>args)[i].parent = stmt;
|
||||
if (expression.kind == NodeKind.IDENTIFIER) {
|
||||
switch ((<IdentifierExpression>expression).name) {
|
||||
|
||||
case "global":
|
||||
stmt.decoratorKind = DecoratorKind.GLOBAL;
|
||||
break;
|
||||
|
||||
case "operator":
|
||||
stmt.decoratorKind = DecoratorKind.OPERATOR;
|
||||
break;
|
||||
|
||||
case "struct":
|
||||
stmt.decoratorKind = DecoratorKind.STRUCT;
|
||||
break;
|
||||
|
||||
case "size":
|
||||
stmt.decoratorKind = DecoratorKind.SIZE;
|
||||
break;
|
||||
|
||||
default:
|
||||
stmt.decoratorKind = DecoratorKind.CUSTOM;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
stmt.decoratorKind = DecoratorKind.CUSTOM;
|
||||
return stmt;
|
||||
}
|
||||
|
||||
@ -1333,6 +1358,15 @@ export class ContinueStatement extends Statement {
|
||||
}
|
||||
}
|
||||
|
||||
/** Built-in decorator kinds. */
|
||||
export const enum DecoratorKind {
|
||||
CUSTOM,
|
||||
GLOBAL,
|
||||
OPERATOR,
|
||||
STRUCT,
|
||||
SIZE
|
||||
}
|
||||
|
||||
/** Depresents a decorator. */
|
||||
export class Decorator extends Statement {
|
||||
|
||||
@ -1342,6 +1376,8 @@ export class Decorator extends Statement {
|
||||
name: Expression;
|
||||
/** Argument expressions. */
|
||||
arguments: Expression[] | null;
|
||||
/** Built-in kind, if applicable. */
|
||||
decoratorKind: DecoratorKind;
|
||||
|
||||
serialize(sb: string[]): void {
|
||||
sb.push("@");
|
||||
@ -2153,7 +2189,7 @@ export function hasModifier(kind: ModifierKind, modifiers: Modifier[] | null): b
|
||||
}
|
||||
|
||||
/** Gets a specific decorator within the specified decorators, if present. */
|
||||
export function getDecorator(name: string, decorators: Decorator[] | null): Decorator | null {
|
||||
export function getFirstDecorator(name: string, decorators: Decorator[] | null): Decorator | null {
|
||||
if (decorators)
|
||||
for (var i = 0, k = decorators.length; i < k; ++i) {
|
||||
var decorator = decorators[i];
|
||||
@ -2166,7 +2202,7 @@ export function getDecorator(name: string, decorators: Decorator[] | null): Deco
|
||||
|
||||
/** Tests if a specific decorator is present within the specified decorators. */
|
||||
export function hasDecorator(name: string, decorators: Decorator[] | null): bool {
|
||||
return getDecorator(name, decorators) != null;
|
||||
return getFirstDecorator(name, decorators) != null;
|
||||
}
|
||||
|
||||
/** Serializes the specified node to its TypeScript representation. */
|
||||
|
@ -38,11 +38,17 @@ import {
|
||||
TypeNode,
|
||||
TypeParameter,
|
||||
Decorator,
|
||||
DecoratorKind,
|
||||
|
||||
Expression,
|
||||
ElementAccessExpression,
|
||||
IdentifierExpression,
|
||||
LiteralExpression,
|
||||
LiteralKind,
|
||||
PropertyAccessExpression,
|
||||
StringLiteralExpression,
|
||||
SuperExpression,
|
||||
ThisExpression,
|
||||
CallExpression,
|
||||
NewExpression,
|
||||
|
||||
@ -68,9 +74,7 @@ import {
|
||||
hasDecorator,
|
||||
hasModifier,
|
||||
mangleInternalName,
|
||||
ElementAccessExpression,
|
||||
ThisExpression,
|
||||
SuperExpression
|
||||
getFirstDecorator
|
||||
} from "./ast";
|
||||
|
||||
import {
|
||||
@ -354,6 +358,7 @@ export class Program extends DiagnosticEmitter {
|
||||
private initializeMethod(declaration: MethodDeclaration, classPrototype: ClassPrototype): void {
|
||||
var name = declaration.name.name;
|
||||
var internalName = declaration.internalName;
|
||||
var instancePrototype: FunctionPrototype | null = null;
|
||||
|
||||
// static methods become global functions
|
||||
if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) {
|
||||
@ -382,12 +387,56 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
} else
|
||||
classPrototype.instanceMembers = new Map();
|
||||
var instancePrototype = new FunctionPrototype(this, name, internalName, declaration, classPrototype);
|
||||
instancePrototype = new FunctionPrototype(this, name, internalName, declaration, classPrototype);
|
||||
// if (classPrototype.isStruct && instancePrototype.isAbstract) {
|
||||
// this.error( Structs cannot declare abstract methods. );
|
||||
// }
|
||||
classPrototype.instanceMembers.set(name, instancePrototype);
|
||||
}
|
||||
|
||||
// handle operator annotations. operators are instance methods taking a second argument of the
|
||||
// instance's type. return values vary depending on the operation.
|
||||
if (declaration.decorators) {
|
||||
for (var i = 0, k = declaration.decorators.length; i < k; ++i) {
|
||||
var decorator = declaration.decorators[i];
|
||||
if (decorator.decoratorKind == DecoratorKind.OPERATOR) {
|
||||
if (!instancePrototype) {
|
||||
this.error(DiagnosticCode.Operation_not_supported, decorator.range);
|
||||
continue;
|
||||
}
|
||||
var numArgs = decorator.arguments && decorator.arguments.length || 0;
|
||||
if (numArgs == 1) {
|
||||
var firstArg = (<Expression[]>decorator.arguments)[0];
|
||||
if (firstArg.kind == NodeKind.LITERAL && (<LiteralExpression>firstArg).literalKind == LiteralKind.STRING) {
|
||||
switch ((<StringLiteralExpression>firstArg).value) {
|
||||
|
||||
case "[]":
|
||||
classPrototype.opIndexedGet = instancePrototype;
|
||||
break;
|
||||
|
||||
case "[]=":
|
||||
classPrototype.opIndexedSet = instancePrototype;
|
||||
break;
|
||||
|
||||
case "+":
|
||||
classPrototype.opConcat = instancePrototype;
|
||||
break;
|
||||
|
||||
case "==":
|
||||
classPrototype.opEquals = instancePrototype;
|
||||
break;
|
||||
|
||||
default: // TBD: does it make sense to provide more, even though not JS/TS-compatible?
|
||||
this.error(DiagnosticCode.Operation_not_supported, firstArg.range);
|
||||
}
|
||||
} else
|
||||
this.error(DiagnosticCode.String_literal_expected, firstArg.range);
|
||||
} else
|
||||
this.error(DiagnosticCode.Expected_0_arguments_but_got_1, decorator.range, "1", numArgs.toString(0));
|
||||
} else if (decorator.decoratorKind != DecoratorKind.CUSTOM) // methods support @operator only
|
||||
this.error(DiagnosticCode.Operation_not_supported, decorator.range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private initializeAccessor(declaration: MethodDeclaration, classPrototype: ClassPrototype, isGetter: bool): void {
|
||||
@ -1449,6 +1498,7 @@ export class FunctionPrototype extends Element {
|
||||
}
|
||||
|
||||
// resolve parameters
|
||||
// TODO: 'this' type
|
||||
k = declaration.parameters.length;
|
||||
var parameters = new Array<Parameter>(k);
|
||||
var parameterTypes = new Array<Type>(k);
|
||||
@ -1466,6 +1516,7 @@ export class FunctionPrototype extends Element {
|
||||
}
|
||||
|
||||
// resolve return type
|
||||
// TODO: 'this' type
|
||||
var returnType: Type;
|
||||
if (this.isSetter) {
|
||||
returnType = Type.void; // not annotated
|
||||
@ -1770,6 +1821,15 @@ export class ClassPrototype extends Element {
|
||||
/** Instance member prototypes. */
|
||||
instanceMembers: Map<string,Element> | null = null;
|
||||
|
||||
/** Overloaded indexed get method, if any. */
|
||||
opIndexedGet: FunctionPrototype | null;
|
||||
/** Overloaded indexed set method, if any. */
|
||||
opIndexedSet: FunctionPrototype | null;
|
||||
/** Overloaded concatenation method, if any. */
|
||||
opConcat: FunctionPrototype | null;
|
||||
/** Overloaded equality comparison method, if any. */
|
||||
opEquals: FunctionPrototype | null;
|
||||
|
||||
constructor(program: Program, simpleName: string, internalName: string, declaration: ClassDeclaration | null = null) {
|
||||
super(program, simpleName, internalName);
|
||||
if (this.declaration = declaration) {
|
||||
|
Reference in New Issue
Block a user