More tests and fixes (unary, binary, globals)

This commit is contained in:
dcodeIO 2017-12-02 18:37:59 +01:00
parent ef859937a8
commit b9edfb5185
22 changed files with 2159 additions and 80 deletions

View File

@ -925,12 +925,13 @@ export abstract class Statement extends Node {
return stmt;
}
static createVariableDeclaration(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, range: Range): VariableDeclaration {
static createVariableDeclaration(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, modifiers: Modifier[] | null, range: Range): VariableDeclaration {
const elem: VariableDeclaration = new VariableDeclaration();
elem.range = range;
(elem.identifier = identifier).parent = elem;
if (elem.type = type) (<TypeNode>type).parent = elem;
if (elem.initializer = initializer) (<Expression>initializer).parent = elem;
elem.modifiers = modifiers;
return elem;
}
@ -1681,7 +1682,7 @@ export class TryStatement extends Statement {
export class VariableDeclaration extends VariableLikeDeclarationStatement {
kind = NodeKind.VARIABLEDECLARATION;
modifiers = null;
modifiers: Modifier[] | null;
serialize(sb: string[]): void {
this.identifier.serialize(sb);

View File

@ -90,6 +90,15 @@ export class Options {
noTreeShaking: bool = false;
}
const enum ConversionKind {
/** No conversion. */
NONE,
/** Implicit conversion. */
IMPLICIT,
/** Explicit conversion. */
EXPLICIT
}
export class Compiler extends DiagnosticEmitter {
/** Program reference. */
@ -141,7 +150,7 @@ export class Compiler extends DiagnosticEmitter {
compile(): Module {
const program: Program = this.program;
// initialize lookup maps
// initialize lookup maps, builtins, imports, exports, etc.
program.initialize(this.options.target);
// compile entry file (exactly one, usually)
@ -181,7 +190,7 @@ export class Compiler extends DiagnosticEmitter {
heapStartBuffer[7] = (initial.hi >>> 24) as u8;
} else {
if (!initial.fitsInU32)
throw new Error("memory size overflow");
throw new Error("static memory size overflows 32 bits");
heapStartBuffer = new Uint8Array(4);
heapStartOffset = 4;
heapStartBuffer[0] = (initial.lo ) as u8;
@ -299,6 +308,8 @@ export class Compiler extends DiagnosticEmitter {
return false;
element.type = type;
}
if (this.module.noEmit)
return true;
const nativeType: NativeType = typeToNativeType(<Type>type);
let initializer: ExpressionRef;
let initializeInStart: bool;
@ -331,10 +342,10 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("unexpected missing declaration or constant value");
const internalName: string = element.internalName;
if (initializeInStart) {
this.module.addGlobal(internalName, NativeType.I32, true, this.module.createI32(-1));
this.module.addGlobal(internalName, nativeType, true, this.module.createI32(-1));
this.startFunctionBody.push(this.module.createSetGlobal(internalName, initializer));
} else
this.module.addGlobal(internalName, NativeType.I32, element.isMutable, initializer);
this.module.addGlobal(internalName, nativeType, element.isMutable, initializer);
return element.isCompiled = true;
}
@ -350,7 +361,6 @@ export class Compiler extends DiagnosticEmitter {
compileEnum(element: Enum): void {
if (element.isCompiled)
return;
element.isCompiled = true;
let previousInternalName: string | null = null;
for (let [key, val] of element.members) {
if (val.hasConstantValue) {
@ -381,6 +391,7 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("unexpected missing declaration or constant value");
previousInternalName = val.internalName;
}
element.isCompiled = true;
}
// functions
@ -405,8 +416,8 @@ export class Compiler extends DiagnosticEmitter {
return;
const declaration: FunctionDeclaration | null = instance.template.declaration;
if (!declaration) // TODO: compile builtins
throw new Error("not implemented");
if (!declaration)
throw new Error("unexpected missing declaration");
if (!declaration.statements) {
this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, declaration.identifier.range);
@ -588,7 +599,7 @@ export class Compiler extends DiagnosticEmitter {
const previousType: Type = this.currentType;
const previousNoEmit: bool = this.module.noEmit;
this.module.noEmit = true;
this.compileExpression(expression, contextualType, false); // now performs a dry run
this.compileExpression(expression, contextualType, ConversionKind.NONE); // now performs a dry run
const type: Type = this.currentType;
this.currentType = previousType;
this.module.noEmit = previousNoEmit;
@ -698,7 +709,12 @@ export class Compiler extends DiagnosticEmitter {
}
compileExpressionStatement(statement: ExpressionStatement): ExpressionRef {
return this.compileExpression(statement.expression, Type.void);
let expr: ExpressionRef = this.compileExpression(statement.expression, Type.void, ConversionKind.NONE);
if (this.currentType != Type.void) {
expr = this.module.createDrop(expr);
this.currentType = Type.void;
}
return expr;
}
compileForStatement(statement: ForStatement): ExpressionRef {
@ -850,7 +866,7 @@ export class Compiler extends DiagnosticEmitter {
// expressions
compileExpression(expression: Expression, contextualType: Type, convert: bool = true): ExpressionRef {
compileExpression(expression: Expression, contextualType: Type, conversionKind: ConversionKind = ConversionKind.IMPLICIT): ExpressionRef {
this.currentType = contextualType;
let expr: ExpressionRef;
@ -912,19 +928,22 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("unexpected expression kind");
}
if (convert && this.currentType != contextualType) {
expr = this.convertExpression(expr, this.currentType, contextualType);
if (conversionKind != ConversionKind.NONE) {
expr = this.convertExpression(expr, this.currentType, contextualType, conversionKind, expression);
this.currentType = contextualType;
}
return expr;
}
convertExpression(expr: ExpressionRef, fromType: Type, toType: Type): ExpressionRef {
convertExpression(expr: ExpressionRef, fromType: Type, toType: Type, conversionKind: ConversionKind, reportNode: Node): ExpressionRef {
if (conversionKind == ConversionKind.NONE)
return expr;
// void to any
if (fromType.kind == TypeKind.VOID)
if (fromType.kind == TypeKind.VOID) {
this.error(DiagnosticCode.Operation_not_supported, reportNode.range);
throw new Error("unexpected conversion from void");
}
// any to void
if (toType.kind == TypeKind.VOID)
@ -1070,16 +1089,17 @@ export class Compiler extends DiagnosticEmitter {
}
}
if (losesInformation && conversionKind == ConversionKind.IMPLICIT)
this.error(DiagnosticCode.Conversion_from_type_0_to_1_requires_an_explicit_cast, reportNode.range, fromType.toString(), toType.toString());
return expr;
}
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef {
const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports
if (toType && toType != contextualType) {
const expr: ExpressionRef = this.compileExpression(expression.expression, <Type>toType, false);
return this.convertExpression(expr, this.currentType, <Type>toType);
}
return this.compileExpression(expression.expression, contextualType);
return toType && toType != contextualType
? this.compileExpression(expression.expression, <Type>toType, ConversionKind.EXPLICIT)
: this.compileExpression(expression.expression, contextualType);
}
compileBinaryExpression(expression: BinaryExpression, contextualType: Type): ExpressionRef {
@ -1091,7 +1111,7 @@ export class Compiler extends DiagnosticEmitter {
switch (expression.operator) {
case Token.LESSTHAN:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.LtF32
@ -1104,7 +1124,7 @@ export class Compiler extends DiagnosticEmitter {
break;
case Token.GREATERTHAN:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.GtF32
@ -1117,7 +1137,7 @@ export class Compiler extends DiagnosticEmitter {
break;
case Token.LESSTHAN_EQUALS:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.LeF32
@ -1130,7 +1150,7 @@ export class Compiler extends DiagnosticEmitter {
break;
case Token.GREATERTHAN_EQUALS:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.GeF32
@ -1144,7 +1164,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.EQUALS_EQUALS:
case Token.EQUALS_EQUALS_EQUALS:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.EqF32
@ -1162,7 +1182,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.PLUS_EQUALS:
compound = Token.EQUALS;
case Token.PLUS:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.AddF32
@ -1176,7 +1196,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.MINUS_EQUALS:
compound = Token.EQUALS;
case Token.MINUS:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.SubF32
@ -1190,7 +1210,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.ASTERISK_EQUALS:
compound = Token.EQUALS;
case Token.ASTERISK:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.MulF32
@ -1204,7 +1224,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.SLASH_EQUALS:
compound = Token.EQUALS;
case Token.SLASH:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType == Type.f32
? BinaryOp.DivF32
@ -1218,7 +1238,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.PERCENT_EQUALS:
compound = Token.EQUALS;
case Token.PERCENT:
left = this.compileExpression(expression.left, contextualType, false);
left = this.compileExpression(expression.left, contextualType, ConversionKind.NONE);
right = this.compileExpression(expression.right, this.currentType);
if (this.currentType.isAnyFloat)
throw new Error("not implemented"); // TODO: internal fmod, possibly simply imported from JS
@ -1230,7 +1250,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.LESSTHAN_LESSTHAN_EQUALS:
compound = Token.EQUALS;
case Token.LESSTHAN_LESSTHAN:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isLongInteger
? BinaryOp.ShlI64
@ -1240,7 +1260,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.GREATERTHAN_GREATERTHAN_EQUALS:
compound = Token.EQUALS;
case Token.GREATERTHAN_GREATERTHAN:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isSignedInteger
? this.currentType.isLongInteger
@ -1254,7 +1274,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS:
compound = Token.EQUALS;
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.u64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.u64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isLongInteger
? BinaryOp.ShrU64
@ -1264,7 +1284,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.AMPERSAND_EQUALS:
compound = Token.EQUALS;
case Token.AMPERSAND:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isLongInteger
? BinaryOp.AndI64
@ -1274,7 +1294,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.BAR_EQUALS:
compound = Token.EQUALS;
case Token.BAR:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isLongInteger
? BinaryOp.OrI64
@ -1284,7 +1304,7 @@ export class Compiler extends DiagnosticEmitter {
case Token.CARET_EQUALS:
compound = Token.EQUALS;
case Token.CARET:
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType);
left = this.compileExpression(expression.left, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
right = this.compileExpression(expression.right, this.currentType);
op = this.currentType.isLongInteger
? BinaryOp.XorI64
@ -1316,11 +1336,17 @@ export class Compiler extends DiagnosticEmitter {
this.currentType = (<Local>element).type;
return this.module.createTeeLocal((<Local>element).index, valueWithCorrectType);
}
this.currentType = Type.void;
return this.module.createSetLocal((<Local>element).index, valueWithCorrectType);
}
if (element.kind == ElementKind.GLOBAL && (<Global>element).type) {
if (element.kind == ElementKind.GLOBAL) {
this.compileGlobal(<Global>element);
if (!(<Global>element).isMutable)
this.error(DiagnosticCode.Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property, expression.range, element.internalName);
if (tee) {
if (!(<Global>element).type)
return this.module.createUnreachable();
const globalNativeType: NativeType = typeToNativeType(<Type>(<Global>element).type);
this.currentType = <Type>(<Global>element).type;
return this.module.createBlock(null, [ // teeGlobal
@ -1328,6 +1354,7 @@ export class Compiler extends DiagnosticEmitter {
this.module.createGetGlobal((<Global>element).internalName, globalNativeType)
], globalNativeType);
}
this.currentType = Type.void;
return this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType);
}
@ -1384,7 +1411,7 @@ export class Compiler extends DiagnosticEmitter {
const operands: ExpressionRef[] = new Array(parameterCount);
for (let i: i32 = 0; i < parameterCount; ++i) {
if (argumentExpressions.length > i) {
operands[i] = this.compileExpression(argumentExpressions[i], parameters[i].type, true);
operands[i] = this.compileExpression(argumentExpressions[i], parameters[i].type);
} else {
const initializer: Expression | null = parameters[i].initializer;
if (initializer) { // omitted, uses initializer
@ -1621,47 +1648,52 @@ export class Compiler extends DiagnosticEmitter {
} else if (expression.kind == NodeKind.THIS) {
if (this.currentFunction.instanceMethodOf) {
this.currentType = this.currentFunction.instanceMethodOf.type;
return this.module.createGetLocal(0, typeToNativeType(this.currentType));
return this.module.createGetLocal(0, this.options.target == Target.WASM64 ? NativeType.I64 : NativeType.I32);
}
this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range);
this.currentType = this.options.target == Target.WASM64 ? Type.u64 : Type.u32;
return this.module.createUnreachable();
}
const element: Element | null = this.program.resolveElement(expression, this.currentFunction); // reports
if (!element) {
if (expression.kind == NodeKind.IDENTIFIER) {
if (expression.kind == NodeKind.IDENTIFIER) {
// NaN
if ((<IdentifierExpression>expression).name == "NaN")
if (this.currentType.kind == TypeKind.F32)
return this.module.createF32(NaN);
else {
this.currentType = Type.f64;
return this.module.createF64(NaN);
}
// NaN
if ((<IdentifierExpression>expression).name == "NaN")
if (this.currentType.kind == TypeKind.F32)
return this.module.createF32(NaN);
else {
this.currentType = Type.f64;
return this.module.createF64(NaN);
}
// Infinity
if ((<IdentifierExpression>expression).name == "Infinity")
if (this.currentType.kind == TypeKind.F32)
return this.module.createF32(Infinity);
else {
this.currentType = Type.f64;
return this.module.createF64(Infinity);
}
}
return this.module.createUnreachable();
// Infinity
if ((<IdentifierExpression>expression).name == "Infinity")
if (this.currentType.kind == TypeKind.F32)
return this.module.createF32(Infinity);
else {
this.currentType = Type.f64;
return this.module.createF64(Infinity);
}
}
const element: Element | null = this.program.resolveElement(expression, this.currentFunction); // reports
if (!element)
return this.module.createUnreachable();
// local
if (element.kind == ElementKind.LOCAL)
if (element.kind == ElementKind.LOCAL) {
this.currentType = (<Local>element).type;
return this.module.createGetLocal((<Local>element).index, typeToNativeType(this.currentType = (<Local>element).type));
}
// global
if (element.kind == ElementKind.GLOBAL)
if (element.kind == ElementKind.GLOBAL) {
if ((<Global>element).type)
this.currentType = <Type>(<Global>element).type;
return this.compileGlobal(<Global>element) // reports
? this.module.createGetGlobal((<Global>element).internalName, typeToNativeType(this.currentType = <Type>(<Global>element).type))
: this.module.createUnreachable();
}
// field
// if (element.kind == ElementKind.FIELD)
@ -1691,6 +1723,10 @@ export class Compiler extends DiagnosticEmitter {
const intValue: I64 = (<IntegerLiteralExpression>expression).value;
if (contextualType == Type.bool && (intValue.isZero || intValue.isOne))
return this.module.createI32(intValue.isZero ? 0 : 1);
if (contextualType == Type.f64)
return this.module.createF64((<f64>intValue.lo) + (<f64>intValue.hi) * 0xffffffff);
if (contextualType == Type.f32)
return this.module.createF32((<f32>intValue.lo) + (<f32>intValue.hi) * 0xffffffff);
if (contextualType.isLongInteger)
return this.module.createI64(intValue.lo, intValue.hi);
if (!intValue.fitsInI32) {
@ -1769,10 +1805,10 @@ export class Compiler extends DiagnosticEmitter {
switch (expression.operator) {
case Token.PLUS:
return this.compileExpression(operandExpression, contextualType);
return this.compileExpression(operandExpression, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
case Token.MINUS:
operand = this.compileExpression(operandExpression, contextualType);
operand = this.compileExpression(operandExpression, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
if (this.currentType == Type.f32)
op = UnaryOp.NegF32;
else if (this.currentType == Type.f64)
@ -1784,7 +1820,7 @@ export class Compiler extends DiagnosticEmitter {
break;
case Token.PLUS_PLUS:
operand = this.compileExpression(operandExpression, contextualType);
operand = this.compileExpression(operandExpression, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
return this.currentType == Type.f32
? this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.AddF32, operand, this.module.createF32(1)), contextualType != Type.void)
: this.currentType == Type.f64
@ -1794,7 +1830,7 @@ export class Compiler extends DiagnosticEmitter {
: this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.AddI32, operand, this.module.createI32(1)), contextualType != Type.void);
case Token.MINUS_MINUS:
operand = this.compileExpression(operandExpression, contextualType);
operand = this.compileExpression(operandExpression, contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
return this.currentType == Type.f32
? this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.SubF32, operand, this.module.createF32(1)), contextualType != Type.void)
: this.currentType == Type.f64
@ -1804,7 +1840,7 @@ export class Compiler extends DiagnosticEmitter {
: this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.SubI32, operand, this.module.createI32(1)), contextualType != Type.void);
case Token.EXCLAMATION:
operand = this.compileExpression(operandExpression, Type.bool, false);
operand = this.compileExpression(operandExpression, Type.bool, ConversionKind.NONE);
if (this.currentType == Type.f32) {
this.currentType = Type.bool;
return this.module.createBinary(BinaryOp.EqF32, operand, this.module.createF32(0));
@ -1820,7 +1856,7 @@ export class Compiler extends DiagnosticEmitter {
break;
case Token.TILDE:
operand = this.compileExpression(operandExpression, contextualType.isAnyFloat ? Type.i64 : contextualType);
operand = this.compileExpression(operandExpression, contextualType.isAnyFloat ? Type.i64 : contextualType, contextualType == Type.void ? ConversionKind.NONE : ConversionKind.IMPLICIT);
return this.currentType.isLongInteger
? this.module.createBinary(BinaryOp.XorI64, operand, this.module.createI64(-1, -1))
: this.module.createBinary(BinaryOp.XorI32, operand, this.module.createI32(-1));

View File

@ -60,6 +60,7 @@ export enum DiagnosticCode {
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
Duplicate_function_implementation = 2393,
Export_declaration_conflicts_with_exported_declaration_of_0 = 2484,
Cannot_assign_to_0_because_it_is_a_constant_or_a_read_only_property = 2540,
The_target_of_an_assignment_must_be_a_variable_or_a_property_access = 2541,
Expected_0_arguments_but_got_1 = 2554,
Expected_at_least_0_arguments_but_got_1 = 2555,
@ -128,6 +129,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 2391: return "Function implementation is missing or not immediately following the declaration.";
case 2393: return "Duplicate function implementation.";
case 2484: return "Export declaration conflicts with exported declaration of '{0}'.";
case 2540: return "Cannot assign to '{0}' because it is a constant or a read-only property.";
case 2541: return "The target of an assignment must be a variable or a property access.";
case 2554: return "Expected {0} arguments, but got {1}.";
case 2555: return "Expected at least {0} arguments, but got {1}.";

View File

@ -60,6 +60,7 @@
"Function implementation is missing or not immediately following the declaration.": 2391,
"Duplicate function implementation.": 2393,
"Export declaration conflicts with exported declaration of '{0}'.": 2484,
"Cannot assign to '{0}' because it is a constant or a read-only property.": 2540,
"The target of an assignment must be a variable or a property access.": 2541,
"Expected {0} arguments, but got {1}.": 2554,
"Expected at least {0} arguments, but got {1}.": 2555,

View File

@ -350,7 +350,7 @@ export class Parser extends DiagnosticEmitter {
const members: VariableDeclaration[] = new Array();
const isDeclare = hasModifier(ModifierKind.DECLARE, modifiers);
do {
const member: VariableDeclaration | null = this.parseVariableDeclaration(tn, isDeclare);
const member: VariableDeclaration | null = this.parseVariableDeclaration(tn, isDeclare, modifiers);
if (!member)
return null;
members.push(<VariableDeclaration>member);
@ -361,7 +361,7 @@ export class Parser extends DiagnosticEmitter {
return ret;
}
parseVariableDeclaration(tn: Tokenizer, isDeclare: bool = false): VariableDeclaration | null {
parseVariableDeclaration(tn: Tokenizer, isDeclare: bool = false, parentModifiers: Modifier[]): VariableDeclaration | null {
// Identifier (':' Type)? ('=' Expression)?
if (!tn.skip(Token.IDENTIFIER)) {
this.error(DiagnosticCode.Identifier_expected, tn.range());
@ -383,7 +383,7 @@ export class Parser extends DiagnosticEmitter {
if (!initializer)
return null;
}
return Statement.createVariableDeclaration(identifier, type, initializer, Range.join(identifier.range, tn.range()));
return Statement.createVariableDeclaration(identifier, type, initializer, parentModifiers, Range.join(identifier.range, tn.range()));
}
parseEnum(tn: Tokenizer, modifiers: Modifier[]): EnumDeclaration | null {

View File

@ -764,7 +764,7 @@ export class Global extends Element {
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't exports */ false; }
get isGlobalExport(): bool { return this.globalExportName != null; }
get isMutable(): bool { return this.declaration ? hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are immutable */ false; }
get isMutable(): bool { return this.declaration ? !hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are immutable */ false; }
}
/** A function parameter. */

View File

@ -49,9 +49,12 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
const actual = module.toText() + "(;\n[program.elements]\n " + iterate(program.elements.keys()).join("\n ") + "\n[program.exports]\n " + iterate(program.exports.keys()).join("\n ") + "\n;)\n";
const fixture = path.basename(filename, ".ts") + ".wast";
if (module.validate())
console.log("Validates");
if (isCreate) {
fs.writeFileSync(__dirname + "/compiler/" + fixture, actual, { encoding: "utf8" });
console.log("Created\n");
console.log("Created");
} else {
const expected = fs.readFileSync(__dirname + "/compiler/" + fixture, { encoding: "utf8" });
const diffs = diff("compiler/" + fixture, expected, actual);
@ -59,9 +62,11 @@ glob.sync(filter, { cwd: __dirname + "/compiler" }).forEach(filename => {
process.exitCode = 1;
console.log(diffs);
} else {
console.log("No changes\n");
console.log("No changes");
}
}
console.log();
});
function iterate<T>(it: IterableIterator<T>): T[] {

161
tests/compiler/binary.ts Normal file
View File

@ -0,0 +1,161 @@
let b: bool = false;
let i: i32 = 0;
i < 1;
i > 1;
i <= 1;
i >= 1;
i == 1;
i === 1;
i + 1;
i - 1;
i * 1;
i / 1;
i % 1;
i << 1;
i >> 1;
i >>> 1;
i & 1;
i | 1;
i ^ 1;
b = i < 1;
b = i > 1;
b = i <= 1;
b = i >= 1;
b = i == 1;
b = i === 1;
i = i + 1;
i = i - 1;
i = i * 1;
i = i / 1;
i = i % 1;
i = i << 1;
i = i >> 1;
i = i >>> 1;
i = i & 1;
i = i | 1;
i = i ^ 1;
i += 1;
i -= 1;
i *= 1;
i %= 1;
i <<= 1;
i >>= 1;
i >>>= 1;
i &= 1;
i |= 1;
i ^= 1;
let I: i64 = 0;
I < 1;
I > 1;
I <= 1;
I >= 1;
I == 1;
I === 1;
I + 1;
I - 1;
I * 1;
I / 1;
I % 1;
I << 1;
I >> 1;
I >>> 1;
I & 1;
I | 1;
I ^ 1;
b = I < 1;
b = I > 1;
b = I <= 1;
b = I >= 1;
b = I == 1;
b = I === 1;
I = I + 1;
I = I - 1;
I = I * 1;
I = I / 1;
I = I % 1;
I = I << 1;
I = I >> 1;
I = I >>> 1;
I = I & 1;
I = I | 1;
I = I ^ 1;
I += 1;
I -= 1;
I *= 1;
I %= 1;
I <<= 1;
I >>= 1;
I >>>= 1;
I &= 1;
I |= 1;
I ^= 1;
let f: f32 = 0;
f < 1;
f > 1;
f <= 1;
f >= 1;
f == 1;
f === 1;
f + 1;
f - 1;
f * 1;
f / 1;
// f % 1;
b = f < 1;
b = f > 1;
b = f <= 1;
b = f >= 1;
b = f == 1;
b = f === 1;
f = f + 1;
f = f - 1;
f = f * 1;
f = f / 1;
// f = f % 1;
f += 1;
f -= 1;
f *= 1;
// f %= 1;
let F: f64 = 0;
F < 1;
F > 1;
F <= 1;
F >= 1;
F == 1;
F === 1;
F + 1;
F - 1;
F * 1;
F / 1;
// f % 1;
b = F < 1;
b = F > 1;
b = F <= 1;
b = F >= 1;
b = F == 1;
b = F === 1;
F = F + 1;
F = F - 1;
F = F * 1;
F = F / 1;
// F = F % 1;
F += 1;
F -= 1;
F *= 1;
// F %= 1;

847
tests/compiler/binary.wast Normal file
View File

@ -0,0 +1,847 @@
(module
(type $v (func))
(global $binary/i (mut i32) (i32.const 0))
(global $binary/b (mut i32) (i32.const -1))
(global $binary/I (mut i64) (i64.const 0))
(global $binary/f (mut f32) (f32.const 0))
(global $binary/F (mut f64) (f64.const 0))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(drop
(i32.lt_s
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.gt_s
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.le_s
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.ge_s
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.eq
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.eq
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.add
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.sub
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.mul
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.div_s
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.rem_s
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.shl
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.shr_s
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.shr_u
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.and
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.or
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i32.xor
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/b
(i32.const 0)
)
(set_global $binary/b
(i32.lt_s
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/b
(i32.gt_s
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/b
(i32.le_s
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/b
(i32.ge_s
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/b
(i32.eq
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/b
(i32.eq
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.add
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.sub
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.mul
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.div_s
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.rem_s
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.shl
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.shr_s
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.shr_u
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.and
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.or
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.xor
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.add
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.sub
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.mul
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.rem_s
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.shl
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.shr_s
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.shr_u
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.and
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.or
(get_global $binary/i)
(i32.const 1)
)
)
(set_global $binary/i
(i32.xor
(get_global $binary/i)
(i32.const 1)
)
)
(drop
(i64.lt_s
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.gt_s
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.le_s
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.ge_s
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.eq
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.eq
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.add
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.sub
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.mul
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.div_s
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.rem_s
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.shl
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.shr_s
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.shr_u
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.and
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.or
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(i64.xor
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/b
(i64.lt_s
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/b
(i64.gt_s
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/b
(i64.le_s
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/b
(i64.ge_s
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/b
(i64.eq
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/b
(i64.eq
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.add
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.sub
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.mul
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.div_s
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.rem_s
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.shl
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.shr_s
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.shr_u
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.and
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.or
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.xor
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.add
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.sub
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.mul
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.rem_s
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.shl
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.shr_s
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.shr_u
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.and
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.or
(get_global $binary/I)
(i64.const 1)
)
)
(set_global $binary/I
(i64.xor
(get_global $binary/I)
(i64.const 1)
)
)
(drop
(f32.lt
(get_global $binary/f)
(f32.const 1)
)
)
(drop
(f32.gt
(get_global $binary/f)
(f32.const 1)
)
)
(drop
(f32.le
(get_global $binary/f)
(f32.const 1)
)
)
(drop
(f32.ge
(get_global $binary/f)
(f32.const 1)
)
)
(drop
(f32.eq
(get_global $binary/f)
(f32.const 1)
)
)
(drop
(f32.eq
(get_global $binary/f)
(f32.const 1)
)
)
(drop
(f32.add
(get_global $binary/f)
(f32.const 1)
)
)
(drop
(f32.sub
(get_global $binary/f)
(f32.const 1)
)
)
(drop
(f32.mul
(get_global $binary/f)
(f32.const 1)
)
)
(drop
(f32.div
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/b
(f32.lt
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/b
(f32.gt
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/b
(f32.le
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/b
(f32.ge
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/b
(f32.eq
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/b
(f32.eq
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/f
(f32.add
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/f
(f32.sub
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/f
(f32.mul
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/f
(f32.div
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/f
(f32.add
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/f
(f32.sub
(get_global $binary/f)
(f32.const 1)
)
)
(set_global $binary/f
(f32.mul
(get_global $binary/f)
(f32.const 1)
)
)
(drop
(f64.lt
(get_global $binary/F)
(f64.const 1)
)
)
(drop
(f64.gt
(get_global $binary/F)
(f64.const 1)
)
)
(drop
(f64.le
(get_global $binary/F)
(f64.const 1)
)
)
(drop
(f64.ge
(get_global $binary/F)
(f64.const 1)
)
)
(drop
(f64.eq
(get_global $binary/F)
(f64.const 1)
)
)
(drop
(f64.eq
(get_global $binary/F)
(f64.const 1)
)
)
(drop
(f64.add
(get_global $binary/F)
(f64.const 1)
)
)
(drop
(f64.sub
(get_global $binary/F)
(f64.const 1)
)
)
(drop
(f64.mul
(get_global $binary/F)
(f64.const 1)
)
)
(drop
(f64.div
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/b
(f64.lt
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/b
(f64.gt
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/b
(f64.le
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/b
(f64.ge
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/b
(f64.eq
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/b
(f64.eq
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/F
(f64.add
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/F
(f64.sub
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/F
(f64.mul
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/F
(f64.div
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/F
(f64.add
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/F
(f64.sub
(get_global $binary/F)
(f64.const 1)
)
)
(set_global $binary/F
(f64.mul
(get_global $binary/F)
(f64.const 1)
)
)
)
)
(;
[program.elements]
clz
ctz
popcnt
rotl
rotr
abs
ceil
copysign
floor
max
min
nearest
sqrt
trunc
isNaN
isFinite
binary/b
binary/i
binary/I
binary/f
binary/F
[program.exports]
;)

14
tests/compiler/do.ts Normal file
View File

@ -0,0 +1,14 @@
export function loopDo(n: i32): void {
do {
n = n - 1;
} while (n);
}
export function loopDoInDo(n: i32): void {
do {
n = n - 1;
do {
n = n - 1;
} while (n);
} while (n);
}

79
tests/compiler/do.wast Normal file
View File

@ -0,0 +1,79 @@
(module
(type $iv (func (param i32)))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(func $do/loopDo (; 0 ;) (type $iv) (param $0 i32)
(block $break$1.1
(loop $continue$1.1
(block
(set_local $0
(i32.sub
(get_local $0)
(i32.const 1)
)
)
)
(br_if $continue$1.1
(get_local $0)
)
)
)
)
(func $do/loopDoInDo (; 1 ;) (type $iv) (param $0 i32)
(block $break$1.1
(loop $continue$1.1
(block
(set_local $0
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(block $break$1.2
(loop $continue$1.2
(block
(set_local $0
(i32.sub
(get_local $0)
(i32.const 1)
)
)
)
(br_if $continue$1.2
(get_local $0)
)
)
)
)
(br_if $continue$1.1
(get_local $0)
)
)
)
)
)
(;
[program.elements]
clz
ctz
popcnt
rotl
rotr
abs
ceil
copysign
floor
max
min
nearest
sqrt
trunc
isNaN
isFinite
do/loopDo
do/loopDoInDo
[program.exports]
do/loopDo
do/loopDoInDo
;)

View File

@ -1,7 +1,7 @@
(module
(type $iii (func (param i32 i32) (result i32)))
(global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2))
(global $export/a (mut i32) (i32.const 1))
(global $export/b (mut i32) (i32.const 2))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))

22
tests/compiler/if.ts Normal file
View File

@ -0,0 +1,22 @@
export function ifThenElse(n: i32): bool {
if (n)
return true;
else
return false;
}
export function ifThen(n: i32): bool {
if (n)
return true;
return false;
}
export function ifThenElseBlock(n: i32): bool {
if (n) {
; // nop
return true;
} else {
; // nop
return false;
}
}

71
tests/compiler/if.wast Normal file
View File

@ -0,0 +1,71 @@
(module
(type $ii (func (param i32) (result i32)))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(func $if/ifThenElse (; 0 ;) (type $ii) (param $0 i32) (result i32)
(if
(get_local $0)
(return
(i32.const 1)
)
(return
(i32.const 0)
)
)
)
(func $if/ifThen (; 1 ;) (type $ii) (param $0 i32) (result i32)
(if
(get_local $0)
(return
(i32.const 1)
)
)
(return
(i32.const 0)
)
)
(func $if/ifThenElseBlock (; 2 ;) (type $ii) (param $0 i32) (result i32)
(if
(get_local $0)
(block
(nop)
(return
(i32.const 1)
)
)
(block
(nop)
(return
(i32.const 0)
)
)
)
)
)
(;
[program.elements]
clz
ctz
popcnt
rotl
rotr
abs
ceil
copysign
floor
max
min
nearest
sqrt
trunc
isNaN
isFinite
if/ifThenElse
if/ifThen
if/ifThenElseBlock
[program.exports]
if/ifThenElse
if/ifThen
if/ifThenElseBlock
;)

View File

@ -1,8 +1,8 @@
(module
(type $iii (func (param i32 i32) (result i32)))
(type $v (func))
(global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2))
(global $export/a (mut i32) (i32.const 1))
(global $export/b (mut i32) (i32.const 2))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))

View File

@ -0,0 +1,46 @@
0;
1;
2;
3;
4;
5;
6;
7;
8;
9;
0x0;
0x1;
0x2;
0x3;
0x4;
0x5;
0x6;
0x7;
0x8;
0x9;
0xA;
0xB;
0xC;
0xD;
0xE;
0xF;
0xa;
0xb;
0xc;
0xd;
0xe;
0xf;
0o0;
0o1;
0o2;
0o3;
0o4;
0o5;
0o6;
0o7;
0b0;
0b1;
true;
false;
NaN;
Infinity;

View File

@ -0,0 +1,168 @@
(module
(type $v (func))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(drop
(i32.const 0)
)
(drop
(i32.const 1)
)
(drop
(i32.const 2)
)
(drop
(i32.const 3)
)
(drop
(i32.const 4)
)
(drop
(i32.const 5)
)
(drop
(i32.const 6)
)
(drop
(i32.const 7)
)
(drop
(i32.const 8)
)
(drop
(i32.const 9)
)
(drop
(i32.const 0)
)
(drop
(i32.const 1)
)
(drop
(i32.const 2)
)
(drop
(i32.const 3)
)
(drop
(i32.const 4)
)
(drop
(i32.const 5)
)
(drop
(i32.const 6)
)
(drop
(i32.const 7)
)
(drop
(i32.const 8)
)
(drop
(i32.const 9)
)
(drop
(i32.const 10)
)
(drop
(i32.const 11)
)
(drop
(i32.const 12)
)
(drop
(i32.const 13)
)
(drop
(i32.const 14)
)
(drop
(i32.const 15)
)
(drop
(i32.const 10)
)
(drop
(i32.const 11)
)
(drop
(i32.const 12)
)
(drop
(i32.const 13)
)
(drop
(i32.const 14)
)
(drop
(i32.const 15)
)
(drop
(i32.const 0)
)
(drop
(i32.const 1)
)
(drop
(i32.const 2)
)
(drop
(i32.const 3)
)
(drop
(i32.const 4)
)
(drop
(i32.const 5)
)
(drop
(i32.const 6)
)
(drop
(i32.const 7)
)
(drop
(i32.const 0)
)
(drop
(i32.const 1)
)
(drop
(i32.const 1)
)
(drop
(i32.const 0)
)
(drop
(f64.const nan:0x8000000000000)
)
(drop
(f64.const inf)
)
)
)
(;
[program.elements]
clz
ctz
popcnt
rotl
rotr
abs
ceil
copysign
floor
max
min
nearest
sqrt
trunc
isNaN
isFinite
[program.exports]
;)

88
tests/compiler/unary.ts Normal file
View File

@ -0,0 +1,88 @@
+1;
-1;
!1;
~1;
+1.25;
-1.25;
!1.25;
// ~1.25;
let i: i32 = 0;
+i;
-i;
!i;
~i;
++i;
--i;
i = +1;
i = -1;
i = !1;
i = ~1;
i = +i;
i = -i;
i = !i;
i = ~i;
i = ++i;
i = --i;
let I: i64 = 0;
+I;
-I;
!I;
~I;
++I;
--I;
I = +1;
I = -1;
I = !1;
I = ~1;
I = +I;
I = -I;
I = !I;
I = ~I;
I = ++I;
I = --I;
let f: f32 = 0;
+f;
-f;
!f;
// ~f;
++f;
--f;
f = +1.25;
f = -1.25;
i = !1.25;
// i = ~1.25;
f = +f;
f = -f;
i = !f;
// i = ~f;
f = ++f;
f = --f;
let F: f64 = 0;
+F;
-F;
!F;
// ~F;
++F;
--F;
F = +1.25;
F = -1.25;
I = !1.25;
// I = ~1.25;
F = +F;
F = -F;
I = !F;
// I = ~F;
F = ++F;
F = --F;

420
tests/compiler/unary.wast Normal file
View File

@ -0,0 +1,420 @@
(module
(type $v (func))
(global $unary/i (mut i32) (i32.const 0))
(global $unary/I (mut i64) (i64.const 0))
(global $unary/f (mut f32) (f32.const 0))
(global $unary/F (mut f64) (f64.const 0))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
(drop
(i32.const 1)
)
(drop
(i32.sub
(i32.const 0)
(i32.const 1)
)
)
(drop
(i32.eqz
(i32.const 1)
)
)
(drop
(i32.xor
(i32.const 1)
(i32.const -1)
)
)
(drop
(f64.const 1.25)
)
(drop
(f64.neg
(f64.const 1.25)
)
)
(drop
(f64.eq
(f64.const 1.25)
(f64.const 0)
)
)
(drop
(get_global $unary/i)
)
(drop
(i32.sub
(i32.const 0)
(get_global $unary/i)
)
)
(drop
(i32.eqz
(get_global $unary/i)
)
)
(drop
(i32.xor
(get_global $unary/i)
(i32.const -1)
)
)
(set_global $unary/i
(i32.add
(get_global $unary/i)
(i32.const 1)
)
)
(set_global $unary/i
(i32.sub
(get_global $unary/i)
(i32.const 1)
)
)
(set_global $unary/i
(i32.const 1)
)
(set_global $unary/i
(i32.sub
(i32.const 0)
(i32.const 1)
)
)
(set_global $unary/i
(i32.eqz
(i32.const 1)
)
)
(set_global $unary/i
(i32.xor
(i32.const 1)
(i32.const -1)
)
)
(set_global $unary/i
(get_global $unary/i)
)
(set_global $unary/i
(i32.sub
(i32.const 0)
(get_global $unary/i)
)
)
(set_global $unary/i
(i32.eqz
(get_global $unary/i)
)
)
(set_global $unary/i
(i32.xor
(get_global $unary/i)
(i32.const -1)
)
)
(set_global $unary/i
(block (result i32)
(set_global $unary/i
(i32.add
(get_global $unary/i)
(i32.const 1)
)
)
(get_global $unary/i)
)
)
(set_global $unary/i
(block (result i32)
(set_global $unary/i
(i32.sub
(get_global $unary/i)
(i32.const 1)
)
)
(get_global $unary/i)
)
)
(drop
(get_global $unary/I)
)
(drop
(i64.sub
(i64.const 0)
(get_global $unary/I)
)
)
(drop
(i64.eqz
(get_global $unary/I)
)
)
(drop
(i64.xor
(get_global $unary/I)
(i64.const -1)
)
)
(set_global $unary/I
(i64.add
(get_global $unary/I)
(i64.const 1)
)
)
(set_global $unary/I
(i64.sub
(get_global $unary/I)
(i64.const 1)
)
)
(set_global $unary/I
(i64.const 1)
)
(set_global $unary/I
(i64.sub
(i64.const 0)
(i64.const 1)
)
)
(set_global $unary/I
(i64.extend_s/i32
(i32.eqz
(i32.const 1)
)
)
)
(set_global $unary/I
(i64.xor
(i64.const 1)
(i64.const -1)
)
)
(set_global $unary/I
(get_global $unary/I)
)
(set_global $unary/I
(i64.sub
(i64.const 0)
(get_global $unary/I)
)
)
(set_global $unary/I
(i64.extend_s/i32
(i64.eqz
(get_global $unary/I)
)
)
)
(set_global $unary/I
(i64.xor
(get_global $unary/I)
(i64.const -1)
)
)
(set_global $unary/I
(block (result i64)
(set_global $unary/I
(i64.add
(get_global $unary/I)
(i64.const 1)
)
)
(get_global $unary/I)
)
)
(set_global $unary/I
(block (result i64)
(set_global $unary/I
(i64.sub
(get_global $unary/I)
(i64.const 1)
)
)
(get_global $unary/I)
)
)
(drop
(get_global $unary/f)
)
(drop
(f32.neg
(get_global $unary/f)
)
)
(drop
(f32.eq
(get_global $unary/f)
(f32.const 0)
)
)
(set_global $unary/f
(f32.add
(get_global $unary/f)
(f32.const 1)
)
)
(set_global $unary/f
(f32.sub
(get_global $unary/f)
(f32.const 1)
)
)
(set_global $unary/f
(f32.const 1.25)
)
(set_global $unary/f
(f32.neg
(f32.const 1.25)
)
)
(set_global $unary/i
(f64.eq
(f64.const 1.25)
(f64.const 0)
)
)
(set_global $unary/f
(get_global $unary/f)
)
(set_global $unary/f
(f32.neg
(get_global $unary/f)
)
)
(set_global $unary/i
(f32.eq
(get_global $unary/f)
(f32.const 0)
)
)
(set_global $unary/f
(block (result f32)
(set_global $unary/f
(f32.add
(get_global $unary/f)
(f32.const 1)
)
)
(get_global $unary/f)
)
)
(set_global $unary/f
(block (result f32)
(set_global $unary/f
(f32.sub
(get_global $unary/f)
(f32.const 1)
)
)
(get_global $unary/f)
)
)
(drop
(get_global $unary/F)
)
(drop
(f64.neg
(get_global $unary/F)
)
)
(drop
(f64.eq
(get_global $unary/F)
(f64.const 0)
)
)
(set_global $unary/F
(f64.add
(get_global $unary/F)
(f64.const 1)
)
)
(set_global $unary/F
(f64.sub
(get_global $unary/F)
(f64.const 1)
)
)
(set_global $unary/F
(f64.const 1.25)
)
(set_global $unary/F
(f64.neg
(f64.const 1.25)
)
)
(set_global $unary/I
(i64.extend_s/i32
(f64.eq
(f64.const 1.25)
(f64.const 0)
)
)
)
(set_global $unary/F
(get_global $unary/F)
)
(set_global $unary/F
(f64.neg
(get_global $unary/F)
)
)
(set_global $unary/I
(i64.extend_s/i32
(f64.eq
(get_global $unary/F)
(f64.const 0)
)
)
)
(set_global $unary/F
(block (result f64)
(set_global $unary/F
(f64.add
(get_global $unary/F)
(f64.const 1)
)
)
(get_global $unary/F)
)
)
(set_global $unary/F
(block (result f64)
(set_global $unary/F
(f64.sub
(get_global $unary/F)
(f64.const 1)
)
)
(get_global $unary/F)
)
)
)
)
(;
[program.elements]
clz
ctz
popcnt
rotl
rotr
abs
ceil
copysign
floor
max
min
nearest
sqrt
trunc
isNaN
isFinite
unary/i
unary/I
unary/f
unary/F
[program.exports]
;)

14
tests/compiler/while.ts Normal file
View File

@ -0,0 +1,14 @@
export function loopWhile(n: i32): void {
while (n) {
n = n - 1;
}
}
export function loopWhileInWhile(n: i32): void {
while (n) {
n = n - 1;
while (n) {
n = n - 1;
}
}
}

88
tests/compiler/while.wast Normal file
View File

@ -0,0 +1,88 @@
(module
(type $iv (func (param i32)))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(func $while/loopWhile (; 0 ;) (type $iv) (param $0 i32)
(block $break$1.1
(loop $continue$1.1
(if
(get_local $0)
(block
(block
(set_local $0
(i32.sub
(get_local $0)
(i32.const 1)
)
)
)
(br $continue$1.1)
)
)
)
)
)
(func $while/loopWhileInWhile (; 1 ;) (type $iv) (param $0 i32)
(block $break$1.1
(loop $continue$1.1
(if
(get_local $0)
(block
(block
(set_local $0
(i32.sub
(get_local $0)
(i32.const 1)
)
)
(block $break$1.2
(loop $continue$1.2
(if
(get_local $0)
(block
(block
(set_local $0
(i32.sub
(get_local $0)
(i32.const 1)
)
)
)
(br $continue$1.2)
)
)
)
)
)
(br $continue$1.1)
)
)
)
)
)
)
(;
[program.elements]
clz
ctz
popcnt
rotl
rotr
abs
ceil
copysign
floor
max
min
nearest
sqrt
trunc
isNaN
isFinite
while/loopWhile
while/loopWhileInWhile
[program.exports]
while/loopWhile
while/loopWhileInWhile
;)

View File

@ -0,0 +1,16 @@
var binaryen = require("binaryen");
// "It is a validation error for a set_global to index an immutable global variable."
var mod = new binaryen.Module();
mod.addGlobal("a", binaryen.i32, false, mod.i32.const(0));
var funcType = mod.addFunctionType("v", binaryen.none, []);
var func = mod.addFunction("start", funcType, [], mod.block("", [
mod.setGlobal("a", mod.i32.const(1))
]));
mod.setStart(func);
console.log(mod.emitText());
if (mod.validate())
console.log("-> validates");