mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-05-02 10:22:15 +00:00
Accessor parsing; Cleanup
This commit is contained in:
parent
99b0fdf7a8
commit
c6c36613e6
@ -68,16 +68,20 @@
|
||||
|
||||
import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER, PARENT_SUBST, STATIC_DELIMITER, INSTANCE_DELIMITER } from "./constants";
|
||||
import { Token, Tokenizer, operatorTokenToString, Range } from "./tokenizer";
|
||||
import { CharCode, I64, normalizePath, resolvePath } from "./util";
|
||||
import { CharCode } from "./util/charcode";
|
||||
import { I64 } from "./util/i64";
|
||||
import { normalize as normalizePath, resolve as resolvePath } from "./util/path";
|
||||
|
||||
export { Range } from "./tokenizer";
|
||||
|
||||
/** Base class of all AST nodes. */
|
||||
export abstract class Node {
|
||||
|
||||
kind: NodeKind;
|
||||
range: Range;
|
||||
parent: Node | null = null;
|
||||
|
||||
/** Serializes this node to its TypeScript representation. */
|
||||
abstract serialize(sb: string[]): void;
|
||||
}
|
||||
|
||||
@ -1374,7 +1378,7 @@ export class FunctionDeclaration extends DeclarationStatement {
|
||||
sb.push(", ");
|
||||
this.parameters[i].serialize(sb);
|
||||
}
|
||||
if (this.returnType) {
|
||||
if (this.returnType && !hasModifier(ModifierKind.SET, this.modifiers)) {
|
||||
sb.push("): ");
|
||||
(<TypeNode>this.returnType).serialize(sb);
|
||||
} else
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Compiler, Target, typeToNativeType, typeToNativeOne } from "./compiler";
|
||||
import { Compiler, Target, typeToNativeType, typeToNativeOne, typeToNativeZero } from "./compiler";
|
||||
import { DiagnosticCode } from "./diagnostics";
|
||||
import { Node, Expression } from "./ast";
|
||||
import { Type } from "./types";
|
||||
@ -490,15 +490,26 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
|
||||
|
||||
case "assert": // assert(isTrue: bool) -> void
|
||||
compiler.currentType = Type.void;
|
||||
if (!validateCall(compiler, typeArguments, 0, operands, 1, reportNode))
|
||||
if (typeArguments.length != 0) {
|
||||
compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, "0", typeArguments.length.toString(10));
|
||||
return module.createUnreachable();
|
||||
}
|
||||
if (operands.length < 1) {
|
||||
compiler.error(DiagnosticCode.Expected_at_least_0_arguments_but_got_1, reportNode.range, "1", operands.length.toString(10));
|
||||
return module.createUnreachable();
|
||||
}
|
||||
if (operands.length > 2) {
|
||||
compiler.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range, "2", operands.length.toString(10));
|
||||
return module.createUnreachable();
|
||||
}
|
||||
arg0 = compiler.compileExpression(operands[0], Type.i32); // reports
|
||||
arg1 = operands.length > 1 ? compiler.compileExpression(operands[1], usizeType) : typeToNativeZero(module, usizeType); // TODO: string type
|
||||
compiler.currentType = Type.void;
|
||||
return compiler.options.noAssert
|
||||
? module.createNop()
|
||||
: module.createIf(
|
||||
module.createUnary(UnaryOp.EqzI32, arg0),
|
||||
module.createUnreachable()
|
||||
module.createUnreachable() // TODO: report message to embedder
|
||||
);
|
||||
|
||||
case "parseInt": // takes a pointer to the string
|
||||
@ -541,7 +552,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Validates a call to a built-in function. */
|
||||
/** Pre-validates a call to a built-in function. */
|
||||
function validateCall(compiler: Compiler, typeArguments: Type[], expectedTypeArguments: i32, operands: Expression[], expectedOperands: i32, reportNode: Node): bool {
|
||||
if (typeArguments.length != expectedTypeArguments) {
|
||||
compiler.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, reportNode.range, expectedTypeArguments.toString(10), typeArguments.length.toString(10));
|
||||
|
@ -31,7 +31,6 @@ import {
|
||||
EnumValue
|
||||
|
||||
} from "./program";
|
||||
import { I64, U64, sb } from "./util";
|
||||
import { Token } from "./tokenizer";
|
||||
import {
|
||||
|
||||
@ -103,7 +102,10 @@ import {
|
||||
TypeKind,
|
||||
|
||||
} from "./types";
|
||||
import { I64, U64 } from "./util/i64";
|
||||
import { sb } from "./util/sb";
|
||||
|
||||
/** Compilation target. */
|
||||
export enum Target {
|
||||
/** WebAssembly with 32-bit pointers. */
|
||||
WASM32,
|
||||
@ -111,6 +113,7 @@ export enum Target {
|
||||
WASM64
|
||||
}
|
||||
|
||||
/** Compiler options. */
|
||||
export class Options {
|
||||
/** WebAssembly target. Defaults to {@link Target.WASM32}. */
|
||||
target: Target = Target.WASM32;
|
||||
@ -122,6 +125,7 @@ export class Options {
|
||||
noAssert: bool = false;
|
||||
}
|
||||
|
||||
/** Indicates the desired kind of a conversion. */
|
||||
const enum ConversionKind {
|
||||
/** No conversion. */
|
||||
NONE,
|
||||
@ -131,6 +135,7 @@ const enum ConversionKind {
|
||||
EXPLICIT
|
||||
}
|
||||
|
||||
/** Compiler interface. */
|
||||
export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
/** Program reference. */
|
||||
@ -323,8 +328,10 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (!type) {
|
||||
if (!declaration)
|
||||
throw new Error("unexpected missing declaration");
|
||||
if (!declaration.type)
|
||||
return false; // TODO: infer type? currently reported by parser
|
||||
if (!declaration.type) { // TODO: infer type
|
||||
this.error(DiagnosticCode.Type_expected, declaration.identifier.range);
|
||||
return false;
|
||||
}
|
||||
type = this.program.resolveType(declaration.type); // reports
|
||||
if (!type)
|
||||
return false;
|
||||
@ -336,6 +343,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
let initializer: ExpressionRef;
|
||||
let initializeInStart: bool = false;
|
||||
if (global.hasConstantValue) {
|
||||
assert(type != null);
|
||||
if (type.isLongInteger)
|
||||
initializer = global.constantIntegerValue ? this.module.createI64(global.constantIntegerValue.lo, global.constantIntegerValue.hi) : this.module.createI64(0, 0);
|
||||
else if (type.kind == TypeKind.F32)
|
||||
@ -513,17 +521,17 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// create the function type
|
||||
let k: i32 = instance.parameters.length;
|
||||
const binaryenResultType: NativeType = typeToNativeType(instance.returnType);
|
||||
const binaryenParamTypes: NativeType[] = new Array(k);
|
||||
const nativeResultType: NativeType = typeToNativeType(instance.returnType);
|
||||
const nativeParamTypes: NativeType[] = new Array(k);
|
||||
const signatureNameParts: string[] = new Array(k + 1);
|
||||
for (let i: i32 = 0; i < k; ++i) {
|
||||
binaryenParamTypes[i] = typeToNativeType(instance.parameters[i].type);
|
||||
nativeParamTypes[i] = typeToNativeType(instance.parameters[i].type);
|
||||
signatureNameParts[i] = typeToSignatureNamePart(instance.parameters[i].type);
|
||||
}
|
||||
signatureNameParts[k] = typeToSignatureNamePart(instance.returnType);
|
||||
let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(binaryenResultType, binaryenParamTypes);
|
||||
let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(nativeResultType, nativeParamTypes);
|
||||
if (!typeRef)
|
||||
typeRef = this.module.addFunctionType(signatureNameParts.join(""), binaryenResultType, binaryenParamTypes);
|
||||
typeRef = this.module.addFunctionType(signatureNameParts.join(""), nativeResultType, nativeParamTypes);
|
||||
|
||||
// create the function
|
||||
const internalName: string = instance.internalName;
|
||||
@ -673,6 +681,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// memory
|
||||
|
||||
/** Adds a static memory segment with the specified data. */
|
||||
addMemorySegment(buffer: Uint8Array): MemorySegment {
|
||||
if (this.memoryOffset.lo & 7) { // align to 8 bytes so any native data type is aligned here
|
||||
this.memoryOffset.or32(7);
|
||||
@ -686,6 +695,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// types
|
||||
|
||||
// TODO: try to get rid of this
|
||||
determineExpressionType(expression: Expression, contextualType: Type): Type {
|
||||
const previousType: Type = this.currentType;
|
||||
const previousNoEmit: bool = this.module.noEmit;
|
||||
@ -945,6 +955,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (declaration.initializer)
|
||||
initializers.push(this.compileAssignment(declaration.identifier, <Expression>declaration.initializer, Type.void));
|
||||
}
|
||||
} else {
|
||||
this.error(DiagnosticCode.Type_expected, declaration.identifier.range);
|
||||
}
|
||||
}
|
||||
return initializers.length ? this.module.createBlock(null, initializers, NativeType.None) : this.module.createNop();
|
||||
@ -1160,11 +1172,14 @@ export class Compiler extends DiagnosticEmitter {
|
||||
expr = mod.createUnary(UnaryOp.ConvertI64_F32, expr);
|
||||
else
|
||||
expr = mod.createUnary(UnaryOp.ConvertU64_F32, expr);
|
||||
} else
|
||||
} else {
|
||||
if (!fromType.isSmallInteger)
|
||||
losesInformation = true;
|
||||
if (fromType.isSignedInteger)
|
||||
expr = mod.createUnary(UnaryOp.ConvertI32_F32, expr);
|
||||
else
|
||||
expr = mod.createUnary(UnaryOp.ConvertU32_F32, expr);
|
||||
}
|
||||
|
||||
// int to f64
|
||||
} else {
|
||||
@ -1205,8 +1220,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
else
|
||||
expr = mod.createUnary(UnaryOp.ExtendU32, expr);
|
||||
|
||||
// i32 to smaller/change of signage i32
|
||||
} else if (toType.isSmallInteger && (fromType.size > toType.size || (fromType.size == toType.size && fromType.kind != toType.kind))) {
|
||||
// i32 or smaller to even smaller int
|
||||
} else if (toType.isSmallInteger && fromType.size > toType.size) {
|
||||
losesInformation = true;
|
||||
if (toType.isSignedInteger) {
|
||||
expr = mod.createBinary(BinaryOp.ShlI32, expr, mod.createI32(toType.smallIntegerShift));
|
||||
@ -1813,7 +1828,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
return this.module.createI64(intValue.lo, intValue.hi);
|
||||
if (contextualType.isSmallInteger)
|
||||
return this.module.createI32(intValue.toI32());
|
||||
this.currentType = Type.i32;
|
||||
this.currentType = contextualType.isSignedInteger ? Type.i32 : Type.u32;
|
||||
return this.module.createI32(intValue.toI32());
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
readString
|
||||
|
||||
} from "./module";
|
||||
import { I64 } from "./util";
|
||||
import { I64 } from "./util/i64";
|
||||
|
||||
// TODO :-)
|
||||
|
||||
|
@ -20,6 +20,9 @@ export enum DiagnosticCode {
|
||||
Statements_are_not_allowed_in_ambient_contexts = 1036,
|
||||
Initializers_are_not_allowed_in_ambient_contexts = 1039,
|
||||
_0_modifier_cannot_be_used_here = 1042,
|
||||
A_set_accessor_must_have_exactly_one_parameter = 1049,
|
||||
A_set_accessor_parameter_cannot_have_an_initializer = 1052,
|
||||
A_get_accessor_cannot_have_parameters = 1054,
|
||||
Type_parameters_cannot_appear_on_a_constructor_declaration = 1092,
|
||||
Type_annotation_cannot_appear_on_a_constructor_declaration = 1093,
|
||||
An_accessor_cannot_have_type_parameters = 1094,
|
||||
@ -42,6 +45,7 @@ export enum DiagnosticCode {
|
||||
String_literal_expected = 1141,
|
||||
Line_break_not_permitted_here = 1142,
|
||||
Declaration_expected = 1146,
|
||||
_const_declarations_must_be_initialized = 1155,
|
||||
Unterminated_regular_expression_literal = 1161,
|
||||
Binary_digit_expected = 1177,
|
||||
Octal_digit_expected = 1178,
|
||||
@ -95,6 +99,9 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
||||
case 1036: return "Statements are not allowed in ambient contexts.";
|
||||
case 1039: return "Initializers are not allowed in ambient contexts.";
|
||||
case 1042: return "'{0}' modifier cannot be used here.";
|
||||
case 1049: return "A 'set' accessor must have exactly one parameter.";
|
||||
case 1052: return "A 'set' accessor parameter cannot have an initializer.";
|
||||
case 1054: return "A 'get' accessor cannot have parameters.";
|
||||
case 1092: return "Type parameters cannot appear on a constructor declaration.";
|
||||
case 1093: return "Type annotation cannot appear on a constructor declaration.";
|
||||
case 1094: return "An accessor cannot have type parameters.";
|
||||
@ -117,6 +124,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
||||
case 1141: return "String literal expected.";
|
||||
case 1142: return "Line break not permitted here.";
|
||||
case 1146: return "Declaration expected.";
|
||||
case 1155: return "'const' declarations must be initialized.";
|
||||
case 1161: return "Unterminated regular expression literal.";
|
||||
case 1177: return "Binary digit expected.";
|
||||
case 1178: return "Octal digit expected.";
|
||||
|
@ -19,6 +19,9 @@
|
||||
"Statements are not allowed in ambient contexts.": 1036,
|
||||
"Initializers are not allowed in ambient contexts.": 1039,
|
||||
"'{0}' modifier cannot be used here.": 1042,
|
||||
"A 'set' accessor must have exactly one parameter.": 1049,
|
||||
"A 'set' accessor parameter cannot have an initializer.": 1052,
|
||||
"A 'get' accessor cannot have parameters.": 1054,
|
||||
"Type parameters cannot appear on a constructor declaration.": 1092,
|
||||
"Type annotation cannot appear on a constructor declaration.": 1093,
|
||||
"An accessor cannot have type parameters.": 1094,
|
||||
@ -41,6 +44,7 @@
|
||||
"String literal expected.": 1141,
|
||||
"Line break not permitted here.": 1142,
|
||||
"Declaration expected.": 1146,
|
||||
"'const' declarations must be initialized.": 1155,
|
||||
"Unterminated regular expression literal.": 1161,
|
||||
"Binary digit expected.": 1177,
|
||||
"Octal digit expected.": 1178,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Range } from "./ast";
|
||||
import { CharCode, isLineBreak, sb } from "./util";
|
||||
import { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated";
|
||||
import { CharCode, isLineBreak } from "./util/charcode";
|
||||
import { sb } from "./util/sb";
|
||||
|
||||
export { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated";
|
||||
|
||||
@ -71,6 +72,12 @@ export class DiagnosticMessage {
|
||||
this.range = range;
|
||||
return this;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
if (this.range)
|
||||
return diagnosticCategoryToString(this.category) + " " + this.code + ": \"" + this.message + "\" in " + this.range.source.path + " @ " + this.range.start + "," + this.range.end;
|
||||
return diagnosticCategoryToString(this.category) + " " + this.code + ": " + this.message;
|
||||
}
|
||||
}
|
||||
|
||||
export function formatDiagnosticMessage(message: DiagnosticMessage, useColors: bool = false, showContext: bool = false): string {
|
||||
@ -146,6 +153,7 @@ export function formatDiagnosticContext(range: Range, useColors: bool = false):
|
||||
export abstract class DiagnosticEmitter {
|
||||
|
||||
diagnostics: DiagnosticMessage[];
|
||||
silentDiagnostics: bool = false;
|
||||
|
||||
constructor(diagnostics: DiagnosticMessage[] | null = null) {
|
||||
this.diagnostics = diagnostics ? <DiagnosticMessage[]>diagnostics : new Array();
|
||||
@ -154,8 +162,10 @@ export abstract class DiagnosticEmitter {
|
||||
emitDiagnostic(code: DiagnosticCode, category: DiagnosticCategory, range: Range, arg0: string | null = null, arg1: string | null = null) {
|
||||
const message: DiagnosticMessage = DiagnosticMessage.create(code, category, arg0, arg1).withRange(range);
|
||||
this.diagnostics.push(message);
|
||||
console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary
|
||||
console.log(<string>new Error("stack").stack);
|
||||
if (!this.silentDiagnostics) {
|
||||
console.log(formatDiagnosticMessage(message, true, true) + "\n"); // temporary
|
||||
console.log(<string>new Error("stack").stack);
|
||||
}
|
||||
}
|
||||
|
||||
error(code: DiagnosticCode, range: Range, arg0: string | null = null, arg1: string | null = null): void {
|
||||
|
@ -1,68 +0,0 @@
|
||||
// TODO: not yet decided whether we'll need this
|
||||
// https://github.com/WebAssembly/binaryen/pull/1294
|
||||
// https://github.com/WebAssembly/binaryen/pull/1295
|
||||
|
||||
import { Type } from "./types";
|
||||
import { I64 } from "./util";
|
||||
import {
|
||||
|
||||
NodeKind,
|
||||
|
||||
Expression,
|
||||
BinaryExpression,
|
||||
LiteralExpression,
|
||||
UnaryExpression,
|
||||
UnaryPostfixExpression,
|
||||
UnaryPrefixExpression
|
||||
|
||||
} from "./ast";
|
||||
|
||||
export class Evaluator {
|
||||
|
||||
success: bool = false;
|
||||
type: Type;
|
||||
integerValue: I64;
|
||||
floatValue: f64;
|
||||
stringValue: string;
|
||||
|
||||
constructor(initialType: Type) {
|
||||
this.type = initialType;
|
||||
}
|
||||
|
||||
evaluate(expression: Expression): this {
|
||||
switch (expression.kind) {
|
||||
|
||||
case NodeKind.BINARY:
|
||||
this.evaluateBinary(<BinaryExpression>expression);
|
||||
break;
|
||||
|
||||
case NodeKind.LITERAL:
|
||||
this.evaluateLiteral(<LiteralExpression>expression);
|
||||
break;
|
||||
|
||||
case NodeKind.UNARYPREFIX:
|
||||
this.evaluateUnaryPrefix(<UnaryPrefixExpression>expression);
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private evaluateBinary(expression: BinaryExpression): this {
|
||||
// TODO
|
||||
return this;
|
||||
}
|
||||
|
||||
private evaluateLiteral(expression: LiteralExpression): this {
|
||||
// TODO
|
||||
return this;
|
||||
}
|
||||
|
||||
private evaluateUnaryPrefix(expression: UnaryPrefixExpression): this {
|
||||
// TODO
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export function evaluate(expression: Expression, contextualType: Type): Evaluator {
|
||||
return new Evaluator(contextualType).evaluate(expression);
|
||||
}
|
@ -17,6 +17,9 @@
|
||||
|
||||
compile(parser) -> module
|
||||
|
||||
[check diagnostics again]
|
||||
[output module]
|
||||
|
||||
*/
|
||||
|
||||
import { Module } from "./module";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { I64, U64 } from "./util";
|
||||
import { Target } from "./compiler";
|
||||
import { I64, U64 } from "./util/i64";
|
||||
|
||||
export type ModuleRef = usize;
|
||||
export type FunctionTypeRef = usize;
|
||||
|
@ -10,7 +10,8 @@
|
||||
import { Program } from "./program";
|
||||
import { Tokenizer, Token, Range } from "./tokenizer";
|
||||
import { DiagnosticCode, DiagnosticEmitter } from "./diagnostics";
|
||||
import { normalizePath, I64 } from "./util";
|
||||
import { I64 } from "./util/i64";
|
||||
import { normalize as normalizePath } from "./util/path";
|
||||
import {
|
||||
|
||||
Node,
|
||||
@ -386,10 +387,8 @@ export class Parser extends DiagnosticEmitter {
|
||||
const identifier: IdentifierExpression = Expression.createIdentifier(tn.readIdentifier(), tn.range());
|
||||
|
||||
let type: TypeNode | null = null;
|
||||
if (tn.skip(Token.COLON)) {
|
||||
if (tn.skip(Token.COLON))
|
||||
type = this.parseType(tn);
|
||||
} else
|
||||
this.error(DiagnosticCode.Type_expected, tn.range(tn.pos)); // recoverable
|
||||
|
||||
let initializer: Expression | null = null;
|
||||
if (tn.skip(Token.EQUALS)) {
|
||||
@ -398,6 +397,11 @@ export class Parser extends DiagnosticEmitter {
|
||||
initializer = this.parseExpression(tn, Precedence.COMMA + 1);
|
||||
if (!initializer)
|
||||
return null;
|
||||
} else {
|
||||
if (hasModifier(ModifierKind.CONST, parentModifiers))
|
||||
this.error(DiagnosticCode._const_declarations_must_be_initialized, identifier.range);
|
||||
else if (!type) // neither type nor initializer
|
||||
this.error(DiagnosticCode.Type_expected, tn.range(tn.pos)); // recoverable
|
||||
}
|
||||
return Statement.createVariableDeclaration(identifier, type, initializer, parentModifiers, parentDecorators, Range.join(identifier.range, tn.range()));
|
||||
}
|
||||
@ -567,13 +571,28 @@ export class Parser extends DiagnosticEmitter {
|
||||
const parameters: Parameter[] | null = this.parseParameters(tn);
|
||||
if (!parameters)
|
||||
return null;
|
||||
let isSetter: bool = hasModifier(ModifierKind.SET, modifiers);
|
||||
if (isSetter) {
|
||||
if (parameters.length != 1)
|
||||
this.error(DiagnosticCode.A_set_accessor_must_have_exactly_one_parameter, identifier.range); // recoverable
|
||||
if (parameters.length && parameters[0].initializer)
|
||||
this.error(DiagnosticCode.A_set_accessor_parameter_cannot_have_an_initializer, identifier.range); // recoverable
|
||||
}
|
||||
let isGetter: bool = hasModifier(ModifierKind.GET, modifiers);
|
||||
if (isGetter && parameters.length)
|
||||
this.error(DiagnosticCode.A_get_accessor_cannot_have_parameters, identifier.range); // recoverable
|
||||
let returnType: TypeNode | null = null;
|
||||
if (tn.skip(Token.COLON)) {
|
||||
returnType = this.parseType(tn);
|
||||
returnType = this.parseType(tn, isSetter);
|
||||
if (!returnType)
|
||||
return null;
|
||||
} else
|
||||
this.error(DiagnosticCode.Type_expected, tn.range(tn.pos)); // recoverable
|
||||
} else {
|
||||
if (isSetter) {
|
||||
if (parameters.length)
|
||||
returnType = parameters[0].type;
|
||||
} else
|
||||
this.error(DiagnosticCode.Type_expected, tn.range(tn.pos)); // recoverable
|
||||
}
|
||||
const isDeclare: bool = hasModifier(ModifierKind.DECLARE, modifiers);
|
||||
let statements: Statement[] | null = null;
|
||||
if (tn.skip(Token.OPENBRACE)) {
|
||||
@ -675,10 +694,15 @@ export class Parser extends DiagnosticEmitter {
|
||||
else if (tn.skip(Token.ABSTRACT))
|
||||
modifiers = addModifier(Statement.createModifier(ModifierKind.ABSTRACT, tn.range()), modifiers);
|
||||
|
||||
if (tn.skip(Token.GET))
|
||||
let isGetter: bool = false;
|
||||
let isSetter: bool = false;
|
||||
if (tn.skip(Token.GET)) {
|
||||
modifiers = addModifier(Statement.createModifier(ModifierKind.GET, tn.range()), modifiers);
|
||||
else if (tn.skip(Token.SET))
|
||||
isGetter = true;
|
||||
} else if (tn.skip(Token.SET)) { // can't be both
|
||||
modifiers = addModifier(Statement.createModifier(ModifierKind.SET, tn.range()), modifiers);
|
||||
isSetter = true;
|
||||
}
|
||||
|
||||
if (tn.skip(Token.IDENTIFIER)) {
|
||||
const identifier: IdentifierExpression = Expression.createIdentifier(tn.readIdentifier(), tn.range());
|
||||
@ -695,13 +719,26 @@ export class Parser extends DiagnosticEmitter {
|
||||
let parameters = this.parseParameters(tn);
|
||||
if (!parameters)
|
||||
return null;
|
||||
if (isGetter && parameters.length)
|
||||
this.error(DiagnosticCode.A_get_accessor_cannot_have_parameters, identifier.range);
|
||||
if (isSetter) {
|
||||
if (parameters.length != 1)
|
||||
this.error(DiagnosticCode.A_set_accessor_must_have_exactly_one_parameter, identifier.range);
|
||||
if (parameters.length && parameters[0].initializer)
|
||||
this.error(DiagnosticCode.A_set_accessor_parameter_cannot_have_an_initializer, identifier.range);
|
||||
}
|
||||
let returnType: TypeNode | null = null;
|
||||
if (tn.skip(Token.COLON)) {
|
||||
returnType = this.parseType(tn);
|
||||
returnType = this.parseType(tn, isSetter);
|
||||
if (!returnType)
|
||||
return null;
|
||||
} else
|
||||
this.error(DiagnosticCode.Type_expected, tn.range()); // recoverable
|
||||
} else {
|
||||
if (isSetter) {
|
||||
if (parameters.length)
|
||||
returnType = parameters[0].type;
|
||||
} else
|
||||
this.error(DiagnosticCode.Type_expected, tn.range()); // recoverable
|
||||
}
|
||||
let statements: Statement[] | null = null;
|
||||
if (tn.skip(Token.OPENBRACE)) {
|
||||
if (parentIsDeclare)
|
||||
|
@ -3,7 +3,7 @@ import { Target, typeToNativeType } from "./compiler";
|
||||
import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER } from "./constants";
|
||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
||||
import { Type, typesToString } from "./types";
|
||||
import { I64 } from "./util";
|
||||
import { I64 } from "./util/i64";
|
||||
import {
|
||||
|
||||
ModifierKind,
|
||||
|
@ -21,7 +21,8 @@
|
||||
|
||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter, formatDiagnosticMessage } from "./diagnostics";
|
||||
import { Source } from "./ast";
|
||||
import { I64, CharCode, isLineBreak } from "./util";
|
||||
import { CharCode, isLineBreak } from "./util/charcode";
|
||||
import { I64 } from "./util/i64";
|
||||
|
||||
export enum Token {
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Class } from "./program";
|
||||
import { sb } from "./util";
|
||||
import { sb } from "./util/sb";
|
||||
|
||||
export const enum TypeKind {
|
||||
|
||||
@ -103,6 +103,7 @@ export class Type {
|
||||
static readonly f32: Type = new Type(TypeKind.F32, 32);
|
||||
static readonly f64: Type = new Type(TypeKind.F64, 64);
|
||||
static readonly void: Type = new Type(TypeKind.VOID, 0);
|
||||
static readonly infer: Type = Type.void;
|
||||
}
|
||||
|
||||
export function typesToString(types: Type[], prefix: string = "<", postfix: string = ">"): string {
|
||||
|
@ -1,4 +0,0 @@
|
||||
export { CharCode, isLineBreak} from "./util/charcode";
|
||||
export { I64, U64 } from "./util/i64";
|
||||
export { normalize as normalizePath, resolve as resolvePath, dirname } from "./util/path";
|
||||
export const sb: string[] = new Array(256); // shared string builder. 64-bit without growing: (4+4+8) + 8*256 = 16b + 2kb
|
2
src/util/sb.ts
Normal file
2
src/util/sb.ts
Normal file
@ -0,0 +1,2 @@
|
||||
/** Shared string builder. */
|
||||
export const sb: string[] = [];
|
2
std/assembly.d.ts
vendored
2
std/assembly.d.ts
vendored
@ -89,7 +89,7 @@ declare function isNaN<T = f32 | f64>(value: T): bool;
|
||||
/** Tests if a 32-bit or 64-bit float is finite, that is not NaN or +/-Infinity. */
|
||||
declare function isFinite<T = f32 | f64>(value: T): bool;
|
||||
/** Traps if the specified value evaluates to `false`. */
|
||||
declare function assert(isTrue: bool): void;
|
||||
declare function assert(isTrue: bool, message?: string): void;
|
||||
/** Parses an integer string to a 64-bit float. */
|
||||
declare function parseInt(str: string, radix?: i32): f64;
|
||||
/** Parses a string to a 64-bit float. */
|
||||
|
@ -2,6 +2,7 @@
|
||||
"extends": "../tsconfig-base.json",
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "commonjs",
|
||||
"noLib": true,
|
||||
"types": [],
|
||||
"rootDirs": [
|
||||
|
2
std/portable.d.ts
vendored
2
std/portable.d.ts
vendored
@ -51,7 +51,7 @@ declare function unreachable(): any; // sic
|
||||
/** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */
|
||||
declare function changetype<T1,T2>(value: T1): T2;
|
||||
/** Traps if the specified value evaluates to `false`. */
|
||||
declare function assert(isTrue: bool): void;
|
||||
declare function assert(isTrue: bool, message?: string): void;
|
||||
/** Parses an integer string to a 64-bit float. */
|
||||
declare function parseInt(str: string, radix?: i32): f64;
|
||||
/** Parses a floating point string to a 64-bit float. */
|
||||
|
@ -19,14 +19,14 @@ UnreachableError.prototype.message = "unreachable";
|
||||
|
||||
globalScope["unreachable"] = function unreachable() { throw new UnreachableError(); };
|
||||
|
||||
function AssertionError() {
|
||||
function AssertionError(message) {
|
||||
this.message = message || "assertion failed";
|
||||
this.stack = new Error().stack;
|
||||
}
|
||||
AssertionError.prototype = new Error;
|
||||
AssertionError.prototype.name = "AssertionError";
|
||||
AssertionError.prototype.message = "assertion failed";
|
||||
|
||||
globalScope["assert"] = function assert(isTrue) { if (!isTrue) throw new AssertionError(); };
|
||||
globalScope["assert"] = function assert(isTrue, message) { if (!isTrue) throw new AssertionError(message); };
|
||||
globalScope["changetype"] = function changetype(value) { return value; }
|
||||
|
||||
String["fromCharCodes"] = function fromCharCodes(arr) { return String.fromCharCode.apply(String, arr); }
|
||||
|
@ -2,8 +2,6 @@
|
||||
// Useful as a compiler test in this state, but nothing more.
|
||||
// based upon: https://github.com/mattconte/tlsf/blob/master/tlsf.c (BSD)
|
||||
|
||||
/// <reference path="../../assembly.d.ts" />
|
||||
|
||||
/** Finds the index of the least bit set. */
|
||||
function fls(word: u32): i32 {
|
||||
return !word ? -1: 31 - clz<i32>(word);
|
||||
|
6
tests/compiler/tsconfig.json
Normal file
6
tests/compiler/tsconfig.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../std/assembly.json",
|
||||
"include": [
|
||||
"./*.ts"
|
||||
]
|
||||
}
|
@ -18,12 +18,13 @@ glob.sync(filter, { cwd: __dirname + "/parser" }).forEach(filename => {
|
||||
console.log(chalk.default.whiteBright("Testing parser/" + filename));
|
||||
|
||||
var parser = new Parser();
|
||||
parser.silentDiagnostics = true;
|
||||
var sourceText = fs.readFileSync(__dirname + "/parser/" + filename, { encoding: "utf8" }).replace(/\r?\n/g, "\n").replace(/^\/\/.*\r?\n/mg, "");
|
||||
parser.parseFile(sourceText, filename, true);
|
||||
|
||||
var sb = [];
|
||||
parser.program.sources[0].serialize(sb);
|
||||
var actual = sb.join("");
|
||||
var actual = sb.join("") + parser.diagnostics.map(diagnostic => "// " + diagnostic + "\n").join("");;
|
||||
var fixture = filename + ".fixture.ts";
|
||||
|
||||
if (isCreate) {
|
||||
|
@ -4,8 +4,9 @@ export class Test<T> {
|
||||
static staticFunction(): void {
|
||||
}
|
||||
get instanceGetter(): i32 {
|
||||
return 0;
|
||||
}
|
||||
static set staticSetter(v: i32): i32 {
|
||||
static set staticSetter(v: i32) {
|
||||
}
|
||||
instanceField: i32;
|
||||
static staticField: i32;
|
||||
|
@ -4,8 +4,9 @@ instanceFunction(): void {
|
||||
static staticFunction(): void {
|
||||
}
|
||||
get instanceGetter(): i32 {
|
||||
return 0;
|
||||
}
|
||||
static set staticSetter(v: i32): i32 {
|
||||
static set staticSetter(v: i32) {
|
||||
}
|
||||
instanceField: i32;
|
||||
static staticField: i32;
|
||||
|
@ -2,7 +2,7 @@ declare namespace A {
|
||||
namespace B {
|
||||
export namespace C {
|
||||
let aVar: i32;
|
||||
const aConst: i32;
|
||||
const aConst: i32 = 0;
|
||||
function aFunc(): void {}
|
||||
enum AnEnum {}
|
||||
class AClass {}
|
||||
|
@ -2,7 +2,7 @@ declare namespace A {
|
||||
namespace B {
|
||||
export namespace C {
|
||||
let aVar: i32;
|
||||
const aConst: i32;
|
||||
const aConst: i32 = 0;
|
||||
function aFunc(): void {
|
||||
}
|
||||
enum AnEnum {
|
||||
|
6
tests/parser/tsconfig.json
Normal file
6
tests/parser/tsconfig.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../std/assembly.json",
|
||||
"include": [
|
||||
"./*.ts"
|
||||
]
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
var a: i32;
|
||||
let b: i32;
|
||||
const c: i32;
|
||||
const c: i32 = 0;
|
||||
let d = 2;
|
||||
|
||||
let e; // type expected
|
||||
const f: i32; // must be initialized
|
||||
|
@ -1,3 +1,8 @@
|
||||
let a: i32;
|
||||
let b: i32;
|
||||
const c: i32;
|
||||
const c: i32 = 0;
|
||||
let d = 2;
|
||||
let e;
|
||||
const f: i32;
|
||||
// ERROR 1110: "Type expected." in var.ts @ 59,59
|
||||
// ERROR 1155: "'const' declarations must be initialized." in var.ts @ 84,85
|
||||
|
Loading…
x
Reference in New Issue
Block a user