mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-15 16:01:30 +00:00
Support parameter properties; Minor formatting
This commit is contained in:
@ -1047,6 +1047,8 @@ export class ParameterNode extends Node {
|
||||
type: CommonTypeNode;
|
||||
/** Initializer expression, if present. */
|
||||
initializer: Expression | null;
|
||||
/** Implicit field declaration, if applicable. */
|
||||
implicitFieldDeclaration: FieldDeclaration | null = null;
|
||||
}
|
||||
|
||||
/** Represents a function signature. */
|
||||
@ -1583,6 +1585,9 @@ export class ExpressionStatement extends Statement {
|
||||
/** Represents a field declaration within a `class`. */
|
||||
export class FieldDeclaration extends VariableLikeDeclarationStatement {
|
||||
kind = NodeKind.FIELDDECLARATION;
|
||||
|
||||
/** Parameter index within the constructor, if applicable. */
|
||||
parameterIndex: i32 = -1;
|
||||
}
|
||||
|
||||
/** Represents a `for` statement. */
|
||||
|
@ -108,7 +108,8 @@ import {
|
||||
ArrayLiteralExpression,
|
||||
StringLiteralExpression,
|
||||
UnaryPostfixExpression,
|
||||
UnaryPrefixExpression
|
||||
UnaryPrefixExpression,
|
||||
FieldDeclaration
|
||||
} from "./ast";
|
||||
|
||||
import {
|
||||
@ -5999,21 +6000,25 @@ export function makeAllocate(compiler: Compiler, classInstance: Class, reportNod
|
||||
if (member.kind == ElementKind.FIELD) {
|
||||
let field = <Field>member;
|
||||
let fieldType = field.type;
|
||||
let nativeFieldType = fieldType.toNativeType();
|
||||
let fieldDeclaration = field.prototype.declaration;
|
||||
assert(!field.isAny(CommonFlags.CONST));
|
||||
if (fieldDeclaration.initializer) { // use initializer
|
||||
initializers.push(module.createStore(fieldType.byteSize,
|
||||
module.createGetLocal(tempLocal.index, nativeSizeType),
|
||||
compiler.compileExpression(fieldDeclaration.initializer, fieldType), // reports
|
||||
fieldType.toNativeType(),
|
||||
nativeFieldType,
|
||||
field.memoryOffset
|
||||
));
|
||||
} else { // initialize with zero
|
||||
// TODO: might be unnecessary if the ctor initializes the field
|
||||
initializers.push(module.createStore(field.type.byteSize,
|
||||
let parameterIndex = (<FieldDeclaration>field.prototype.declaration).parameterIndex;
|
||||
initializers.push(module.createStore(fieldType.byteSize,
|
||||
module.createGetLocal(tempLocal.index, nativeSizeType),
|
||||
field.type.toNativeZero(module),
|
||||
field.type.toNativeType(),
|
||||
parameterIndex >= 0 // initialized via parameter
|
||||
? module.createGetLocal(1 + parameterIndex, nativeFieldType)
|
||||
: fieldType.toNativeZero(module),
|
||||
nativeFieldType,
|
||||
field.memoryOffset
|
||||
));
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ export enum DiagnosticCode {
|
||||
Decorators_are_not_valid_here = 1206,
|
||||
_abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration = 1242,
|
||||
A_class_may_only_extend_another_class = 1311,
|
||||
A_parameter_property_cannot_be_declared_using_a_rest_parameter = 1317,
|
||||
Duplicate_identifier_0 = 2300,
|
||||
Cannot_find_name_0 = 2304,
|
||||
Module_0_has_no_exported_member_1 = 2305,
|
||||
@ -176,6 +177,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
||||
case 1206: return "Decorators are not valid here.";
|
||||
case 1242: return "'abstract' modifier can only appear on a class, method, or property declaration.";
|
||||
case 1311: return "A class may only extend another class.";
|
||||
case 1317: return "A parameter property cannot be declared using a rest parameter.";
|
||||
case 2300: return "Duplicate identifier '{0}'.";
|
||||
case 2304: return "Cannot find name '{0}'.";
|
||||
case 2305: return "Module '{0}' has no exported member '{1}'.";
|
||||
|
@ -65,6 +65,7 @@
|
||||
"Decorators are not valid here.": 1206,
|
||||
"'abstract' modifier can only appear on a class, method, or property declaration.": 1242,
|
||||
"A class may only extend another class.": 1311,
|
||||
"A parameter property cannot be declared using a rest parameter.": 1317,
|
||||
|
||||
"Duplicate identifier '{0}'.": 2300,
|
||||
"Cannot find name '{0}'.": 2304,
|
||||
|
@ -799,8 +799,11 @@ export class ASTBuilder {
|
||||
sb.push(" {\n");
|
||||
let indentLevel = ++this.indentLevel;
|
||||
for (let i = 0, k = members.length; i < k; ++i) {
|
||||
indent(sb, indentLevel);
|
||||
this.visitNodeAndTerminate(members[i]);
|
||||
let member = members[i];
|
||||
if (member.kind != NodeKind.FIELDDECLARATION || (<FieldDeclaration>member).parameterIndex < 0) {
|
||||
indent(sb, indentLevel);
|
||||
this.visitNodeAndTerminate(member);
|
||||
}
|
||||
}
|
||||
indent(sb, --this.indentLevel);
|
||||
sb.push("}");
|
||||
@ -1368,6 +1371,10 @@ export class ASTBuilder {
|
||||
serializeParameter(node: ParameterNode): void {
|
||||
var sb = this.sb;
|
||||
var kind = node.parameterKind;
|
||||
var implicitFieldDeclaration = node.implicitFieldDeclaration;
|
||||
if (implicitFieldDeclaration) {
|
||||
this.serializeAccessModifiers(implicitFieldDeclaration);
|
||||
}
|
||||
if (kind == ParameterKind.REST) {
|
||||
sb.push("...");
|
||||
}
|
||||
|
115
src/parser.ts
115
src/parser.ts
@ -967,7 +967,8 @@ export class Parser extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
parseParameters(
|
||||
tn: Tokenizer
|
||||
tn: Tokenizer,
|
||||
isConstructor: bool = false
|
||||
): ParameterNode[] | null {
|
||||
|
||||
// at '(': (Parameter (',' Parameter)*)? ')'
|
||||
@ -979,7 +980,7 @@ export class Parser extends DiagnosticEmitter {
|
||||
|
||||
if (tn.peek() != Token.CLOSEPAREN) {
|
||||
do {
|
||||
let param = this.parseParameter(tn);
|
||||
let param = this.parseParameter(tn, isConstructor);
|
||||
if (!param) return null;
|
||||
if (seenRest && !reportedRest) {
|
||||
this.error(
|
||||
@ -1022,17 +1023,63 @@ export class Parser extends DiagnosticEmitter {
|
||||
|
||||
parseParameter(
|
||||
tn: Tokenizer,
|
||||
suppressErrors: bool = false
|
||||
isConstructor: bool = false
|
||||
): ParameterNode | null {
|
||||
|
||||
// before: '...'? Identifier '?'? (':' Type)? ('=' Expression)?
|
||||
// before: ('public' | 'private' | 'protected' | '...')? Identifier '?'? (':' Type)? ('=' Expression)?
|
||||
|
||||
var isRest = false;
|
||||
var isOptional = false;
|
||||
var startRange: Range | null = null;
|
||||
if (tn.skip(Token.DOT_DOT_DOT)) {
|
||||
isRest = true;
|
||||
var accessFlags: CommonFlags = CommonFlags.NONE;
|
||||
if (tn.skip(Token.PUBLIC)) {
|
||||
startRange = tn.range();
|
||||
if (!isConstructor) {
|
||||
this.error(
|
||||
DiagnosticCode._0_modifier_cannot_be_used_here,
|
||||
startRange, "public"
|
||||
);
|
||||
}
|
||||
accessFlags |= CommonFlags.PUBLIC;
|
||||
} else if (tn.skip(Token.PROTECTED)) {
|
||||
startRange = tn.range();
|
||||
if (!isConstructor) {
|
||||
this.error(
|
||||
DiagnosticCode._0_modifier_cannot_be_used_here,
|
||||
startRange, "protected"
|
||||
);
|
||||
}
|
||||
accessFlags |= CommonFlags.PROTECTED;
|
||||
} else if (tn.skip(Token.PRIVATE)) {
|
||||
startRange = tn.range();
|
||||
if (!isConstructor) {
|
||||
this.error(
|
||||
DiagnosticCode._0_modifier_cannot_be_used_here,
|
||||
startRange, "private"
|
||||
);
|
||||
}
|
||||
accessFlags |= CommonFlags.PRIVATE;
|
||||
}
|
||||
if (tn.skip(Token.READONLY)) {
|
||||
if (!startRange) startRange = tn.range();
|
||||
if (!isConstructor) {
|
||||
this.error(
|
||||
DiagnosticCode._0_modifier_cannot_be_used_here,
|
||||
startRange, "readonly"
|
||||
);
|
||||
}
|
||||
accessFlags |= CommonFlags.READONLY;
|
||||
}
|
||||
if (tn.skip(Token.DOT_DOT_DOT)) {
|
||||
if (accessFlags) {
|
||||
this.error(
|
||||
DiagnosticCode.A_parameter_property_cannot_be_declared_using_a_rest_parameter,
|
||||
tn.range()
|
||||
);
|
||||
} else {
|
||||
startRange = tn.range();
|
||||
}
|
||||
isRest = true;
|
||||
}
|
||||
if (tn.skip(Token.IDENTIFIER)) {
|
||||
if (!isRest) startRange = tn.range();
|
||||
@ -1071,7 +1118,7 @@ export class Parser extends DiagnosticEmitter {
|
||||
initializer = this.parseExpression(tn, Precedence.COMMA + 1);
|
||||
if (!initializer) return null;
|
||||
}
|
||||
return Node.createParameter(
|
||||
let param = Node.createParameter(
|
||||
identifier,
|
||||
type,
|
||||
initializer,
|
||||
@ -1082,6 +1129,8 @@ export class Parser extends DiagnosticEmitter {
|
||||
: ParameterKind.DEFAULT,
|
||||
Range.join(<Range>startRange, tn.range())
|
||||
);
|
||||
param.flags |= accessFlags;
|
||||
return param;
|
||||
} else {
|
||||
this.error(
|
||||
DiagnosticCode.Identifier_expected,
|
||||
@ -1400,14 +1449,7 @@ export class Parser extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
var members = new Array<DeclarationStatement>();
|
||||
if (!tn.skip(Token.CLOSEBRACE)) {
|
||||
do {
|
||||
let member = this.parseClassMember(tn, flags);
|
||||
if (!member) return null;
|
||||
members.push(<DeclarationStatement>member);
|
||||
} while (!tn.skip(Token.CLOSEBRACE));
|
||||
}
|
||||
return Node.createClassDeclaration(
|
||||
var declaration = Node.createClassDeclaration(
|
||||
identifier,
|
||||
typeParameters,
|
||||
extendsType,
|
||||
@ -1417,11 +1459,20 @@ export class Parser extends DiagnosticEmitter {
|
||||
flags,
|
||||
tn.range(startPos, tn.pos)
|
||||
);
|
||||
if (!tn.skip(Token.CLOSEBRACE)) {
|
||||
do {
|
||||
let member = this.parseClassMember(tn, declaration);
|
||||
if (!member) return null;
|
||||
member.parent = declaration;
|
||||
members.push(<DeclarationStatement>member);
|
||||
} while (!tn.skip(Token.CLOSEBRACE));
|
||||
}
|
||||
return declaration;
|
||||
}
|
||||
|
||||
parseClassMember(
|
||||
tn: Tokenizer,
|
||||
parentFlags: CommonFlags
|
||||
parent: ClassDeclaration
|
||||
): DeclarationStatement | null {
|
||||
|
||||
// before:
|
||||
@ -1440,7 +1491,7 @@ export class Parser extends DiagnosticEmitter {
|
||||
decorators.push(<DecoratorNode>decorator);
|
||||
}
|
||||
|
||||
var flags = parentFlags & CommonFlags.AMBIENT; // inherit
|
||||
var flags = parent.flags & CommonFlags.AMBIENT; // inherit
|
||||
|
||||
if (tn.skip(Token.PUBLIC)) {
|
||||
flags |= CommonFlags.PUBLIC;
|
||||
@ -1466,7 +1517,7 @@ export class Parser extends DiagnosticEmitter {
|
||||
} else {
|
||||
flags |= CommonFlags.INSTANCE;
|
||||
}
|
||||
if (parentFlags & CommonFlags.GENERIC) {
|
||||
if (parent.flags & CommonFlags.GENERIC) {
|
||||
flags |= CommonFlags.GENERIC_CONTEXT;
|
||||
}
|
||||
}
|
||||
@ -1575,10 +1626,32 @@ export class Parser extends DiagnosticEmitter {
|
||||
// method: '(' Parameters (':' Type)? '{' Statement* '}' ';'?
|
||||
if (tn.skip(Token.OPENPAREN)) {
|
||||
let signatureStart = tn.tokenPos;
|
||||
let parameters = this.parseParameters(tn);
|
||||
let parameters = this.parseParameters(tn, isConstructor);
|
||||
if (!parameters) return null;
|
||||
|
||||
if (isGetter) {
|
||||
if (isConstructor) {
|
||||
for (let i = 0, k = parameters.length; i < k; ++i) {
|
||||
let parameter = parameters[i];
|
||||
if (parameter.isAny(
|
||||
CommonFlags.PUBLIC |
|
||||
CommonFlags.PROTECTED |
|
||||
CommonFlags.PRIVATE |
|
||||
CommonFlags.READONLY
|
||||
)) {
|
||||
let implicitFieldDeclaration = Node.createFieldDeclaration(
|
||||
parameter.name,
|
||||
parameter.type,
|
||||
null, // initialized via parameter
|
||||
null,
|
||||
parameter.flags | CommonFlags.INSTANCE,
|
||||
parameter.range
|
||||
);
|
||||
implicitFieldDeclaration.parameterIndex = i;
|
||||
implicitFieldDeclaration.parent = parent;
|
||||
parameter.implicitFieldDeclaration = implicitFieldDeclaration;
|
||||
parent.members.push(implicitFieldDeclaration);
|
||||
}
|
||||
}
|
||||
} else if (isGetter) {
|
||||
if (parameters.length) {
|
||||
this.error(
|
||||
DiagnosticCode.A_get_accessor_cannot_have_parameters,
|
||||
|
Reference in New Issue
Block a user