Add importMemory option to asc, see #36

This commit is contained in:
dcodeIO 2018-02-28 18:38:42 +01:00
parent 56bc1be8ba
commit 02dce5a518
12 changed files with 158 additions and 70 deletions

View File

@ -277,6 +277,7 @@ exports.main = function main(argv, options, callback) {
assemblyscript.setNoTreeShaking(compilerOptions, !!args.noTreeShaking);
assemblyscript.setNoAssert(compilerOptions, !!args.noAssert);
assemblyscript.setNoMemory(compilerOptions, !!args.noMemory);
assemblyscript.setImportMemory(compilerOptions, !!args.importMemory);
assemblyscript.setMemoryBase(compilerOptions, args.memoryBase >>> 0);
assemblyscript.setSourceMap(compilerOptions, args.sourceMap != null);

View File

@ -89,6 +89,10 @@
"desc": "Does not set up a memory. Useful for low-level WebAssembly.",
"type": "boolean"
},
"importMemory": {
"desc": "Imports the memory instance provided by the embedder.",
"type": "boolean"
},
"memoryBase": {
"desc": "Sets the start offset of compiler-generated static memory.",
"type": "number"

4
dist/asc.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -132,6 +132,8 @@ export class Options {
noAssert: bool = false;
/** If true, does not set up a memory. */
noMemory: bool = false;
/** If true, imports the memory provided by the embedder. */
importMemory: bool = false;
/** Static memory start offset. */
memoryBase: u32 = 0;
/** Memory allocation implementation to use. */
@ -299,6 +301,11 @@ export class Compiler extends DiagnosticEmitter {
);
}
// import memory if requested
if (this.options.importMemory) {
this.module.addMemoryImport("memory", "env", "memory");
}
// set up function table
if (k = this.functionTable.length) {
var entries = new Array<FunctionRef>(k);
@ -2030,6 +2037,16 @@ export class Compiler extends DiagnosticEmitter {
return expr;
}
/** Computes the common compatible type of two types. Returns `null` if incompatible. */
computeCommonType(leftType: Type, rightType: Type): Type | null {
if (leftType.isAssignableTo(rightType)) {
return rightType;
} else if (rightType.isAssignableTo(leftType)) {
return leftType;
}
return null;
}
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef {
var toType = this.program.resolveType( // reports
expression.toType,
@ -2046,6 +2063,38 @@ export class Compiler extends DiagnosticEmitter {
): ExpressionRef {
var left: ExpressionRef;
var right: ExpressionRef;
// TODO: Currently, the common type of any binary expression is the first operand's type. This
// differs from C and other languages where comparing an int to a long, in this order, upcasts
// left to a long before comparison, instead of failing when trying to downcast right to an int.
// NOTE that if we change the current behaviour, some examples, tests and wiki pages will have
// to be updated, while compound binary operations must retain the previous behavior.
// var left = this.compileExpression(
// expression.left,
// contextualType == Type.void
// ? Type.i32
// : contextualType,
// ConversionKind.NONE
// );
// var leftType = this.currentType;
// var right = this.compileExpression(
// expression.right,
// leftType,
// ConversionKind.NONE
// );
// var rightType = this.currentType;
// var commonType = this.computeCommonType(leftType, rightType);
// if (!commonType) {
// this.error(
// DiagnosticCode.Operator_0_cannot_be_applied_to_types_1_and_2,
// expression.range,
// Token.operatorToString(expression.operator), leftType.toString(), rightType.toString()
// );
// this.currentType = contextualType;
// return this.module.createUnreachable();
// }
var condition: ExpressionRef;
var expr: ExpressionRef;
@ -3828,6 +3877,8 @@ export class Compiler extends DiagnosticEmitter {
var instance = this.compileFunctionUsingTypeArguments(prototype, [], null, declaration);
if (!instance) return this.module.createUnreachable();
this.currentType = Type.u32.asFunction(instance);
// NOTE that, in order to make this work in every case, the function must be represented by a
// value, so we add it and rely on the optimizer to figure out where it can be called directly.
var index = this.addFunctionTableEntry(instance);
if (index < 0) return this.module.createUnreachable();
return this.module.createI32(index);

View File

@ -80,11 +80,13 @@ export enum DiagnosticCode {
A_function_whose_declared_type_is_not_void_must_return_a_value = 2355,
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access = 2364,
Operator_0_cannot_be_applied_to_types_1_and_2 = 2365,
_get_and_set_accessor_must_have_the_same_type = 2380,
Constructor_implementation_is_missing = 2390,
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
Multiple_constructor_implementations_are_not_allowed = 2392,
Duplicate_function_implementation = 2393,
The_0_operator_cannot_be_applied_to_type_1 = 2469,
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,
@ -177,11 +179,13 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 2355: return "A function whose declared type is not 'void' must return a value.";
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
case 2364: return "The left-hand side of an assignment expression must be a variable or a property access.";
case 2365: return "Operator '{0}' cannot be applied to types '{1}' and '{2}'.";
case 2380: return "'get' and 'set' accessor must have the same type.";
case 2390: return "Constructor implementation is missing.";
case 2391: return "Function implementation is missing or not immediately following the declaration.";
case 2392: return "Multiple constructor implementations are not allowed.";
case 2393: return "Duplicate function implementation.";
case 2469: return "The '{0}' operator cannot be applied to type '{1}'.";
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.";

View File

@ -79,11 +79,13 @@
"A function whose declared type is not 'void' must return a value.": 2355,
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
"The left-hand side of an assignment expression must be a variable or a property access.": 2364,
"Operator '{0}' cannot be applied to types '{1}' and '{2}'.": 2365,
"'get' and 'set' accessor must have the same type.": 2380,
"Constructor implementation is missing.": 2390,
"Function implementation is missing or not immediately following the declaration.": 2391,
"Multiple constructor implementations are not allowed.": 2392,
"Duplicate function implementation.": 2393,
"The '{0}' operator cannot be applied to type '{1}'.": 2469,
"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,

View File

@ -62,11 +62,13 @@ export class DiagnosticMessage {
code: DiagnosticCode,
category: DiagnosticCategory,
arg0: string | null = null,
arg1: string | null = null
arg1: string | null = null,
arg2: string | null = null
): DiagnosticMessage {
var message = diagnosticCodeToString(code);
if (arg0 != null) message = message.replace("{0}", arg0);
if (arg1 != null) message = message.replace("{1}", arg1);
if (arg2 != null) message = message.replace("{2}", arg2);
return new DiagnosticMessage(code, category, message);
}
@ -211,23 +213,42 @@ export abstract class DiagnosticEmitter {
category: DiagnosticCategory,
range: Range,
arg0: string | null = null,
arg1: string | null = null
arg1: string | null = null,
arg2: string | null = null
) {
var message = DiagnosticMessage.create(code, category, arg0, arg1).withRange(range);
var message = DiagnosticMessage.create(code, category, arg0, arg1, arg2).withRange(range);
this.diagnostics.push(message);
// 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 {
this.emitDiagnostic(code, DiagnosticCategory.ERROR, range, arg0, arg1);
error(
code: DiagnosticCode,
range: Range,
arg0: string | null = null,
arg1: string | null = null,
arg2: string | null = null
): void {
this.emitDiagnostic(code, DiagnosticCategory.ERROR, range, arg0, arg1, arg2);
}
info(code: DiagnosticCode, range: Range, arg0: string | null = null, arg1: string | null = null): void {
this.emitDiagnostic(code, DiagnosticCategory.INFO, range, arg0, arg1);
info(
code: DiagnosticCode,
range: Range,
arg0: string | null = null,
arg1: string | null = null,
arg2: string | null = null
): void {
this.emitDiagnostic(code, DiagnosticCategory.INFO, range, arg0, arg1, arg2);
}
warning(code: DiagnosticCode, range: Range, arg0: string | null = null, arg1: string | null = null): void {
this.emitDiagnostic(code, DiagnosticCategory.WARNING, range, arg0, arg1);
warning(
code: DiagnosticCode,
range: Range,
arg0: string | null = null,
arg1: string | null = null,
arg2: string | null = null
): void {
this.emitDiagnostic(code, DiagnosticCategory.WARNING, range, arg0, arg1, arg2);
}
}

View File

@ -373,7 +373,7 @@ export function serializeAssertionExpression(node: AssertionExpression, sb: stri
export function serializeBinaryExpression(node: BinaryExpression, sb: string[]): void {
serializeExpression(node.left, sb);
sb.push(" ");
sb.push(operatorToString(node.operator));
sb.push(Token.operatorToString(node.operator));
sb.push(" ");
serializeExpression(node.right, sb);
}
@ -613,11 +613,11 @@ export function serializeUnaryExpression(node: UnaryExpression, sb: string[]): v
export function serializeUnaryPostfixExpression(node: UnaryPostfixExpression, sb: string[]): void {
serializeExpression(node.operand, sb);
sb.push(operatorToString(node.operator));
sb.push(Token.operatorToString(node.operator));
}
export function serializeUnaryPrefixExpression(node: UnaryPrefixExpression, sb: string[]): void {
sb.push(operatorToString(node.operator));
sb.push(Token.operatorToString(node.operator));
serializeExpression(node.operand, sb);
}
@ -1245,60 +1245,6 @@ export function serializeParameter(node: Parameter, sb: string[]): void {
// helpers
export function operatorToString(token: Token): string {
switch (token) {
case Token.DELETE: return "delete";
case Token.IN: return "in";
case Token.INSTANCEOF: return "instanceof";
case Token.NEW: return "new";
case Token.TYPEOF: return "typeof";
case Token.VOID: return "void";
case Token.YIELD: return "yield";
case Token.DOT_DOT_DOT: return "...";
case Token.COMMA: return ",";
case Token.LESSTHAN: return "<";
case Token.GREATERTHAN: return ">";
case Token.LESSTHAN_EQUALS: return "<=";
case Token.GREATERTHAN_EQUALS: return ">=";
case Token.EQUALS_EQUALS: return "==";
case Token.EXCLAMATION_EQUALS: return "!=";
case Token.EQUALS_EQUALS_EQUALS: return "===";
case Token.EXCLAMATION_EQUALS_EQUALS: return "!==";
case Token.PLUS: return "+";
case Token.MINUS: return "-";
case Token.ASTERISK_ASTERISK: return "**";
case Token.ASTERISK: return "*";
case Token.SLASH: return "/";
case Token.PERCENT: return "%";
case Token.PLUS_PLUS: return "++";
case Token.MINUS_MINUS: return "--";
case Token.LESSTHAN_LESSTHAN: return "<<";
case Token.GREATERTHAN_GREATERTHAN: return ">>";
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN: return ">>>";
case Token.AMPERSAND: return "&";
case Token.BAR: return "|";
case Token.CARET: return "^";
case Token.EXCLAMATION: return "!";
case Token.TILDE: return "~";
case Token.AMPERSAND_AMPERSAND: return "&&";
case Token.BAR_BAR: return "||";
case Token.EQUALS: return "=";
case Token.PLUS_EQUALS: return "+=";
case Token.MINUS_EQUALS: return "-=";
case Token.ASTERISK_EQUALS: return "*=";
case Token.ASTERISK_ASTERISK_EQUALS: return "**=";
case Token.SLASH_EQUALS: return "/=";
case Token.PERCENT_EQUALS: return "%=";
case Token.LESSTHAN_LESSTHAN_EQUALS: return "<<=";
case Token.GREATERTHAN_GREATERTHAN_EQUALS: return ">>=";
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS: return ">>>=";
case Token.AMPERSAND_EQUALS: return "&=";
case Token.BAR_EQUALS: return "|=";
case Token.CARET_EQUALS: return "^=";
default: assert(false); return "";
}
}
export function modifierToString(node: Modifier): string {
switch (node.modifierKind) {
case ModifierKind.ASYNC: return "async";

View File

@ -92,6 +92,11 @@ export function setNoMemory(options: Options, noMemory: bool): void {
options.noMemory = noMemory;
}
/** Sets the `importMemory` option. */
export function setImportMemory(options: Options, importMemory: bool): void {
options.importMemory = importMemory;
}
/** Sets the `sourceMap` option. */
export function setSourceMap(options: Options, sourceMap: bool): void {
options.sourceMap = sourceMap;

View File

@ -266,6 +266,60 @@ export namespace Token {
return false;
}
}
export function operatorToString(token: Token): string {
switch (token) {
case Token.DELETE: return "delete";
case Token.IN: return "in";
case Token.INSTANCEOF: return "instanceof";
case Token.NEW: return "new";
case Token.TYPEOF: return "typeof";
case Token.VOID: return "void";
case Token.YIELD: return "yield";
case Token.DOT_DOT_DOT: return "...";
case Token.COMMA: return ",";
case Token.LESSTHAN: return "<";
case Token.GREATERTHAN: return ">";
case Token.LESSTHAN_EQUALS: return "<=";
case Token.GREATERTHAN_EQUALS: return ">=";
case Token.EQUALS_EQUALS: return "==";
case Token.EXCLAMATION_EQUALS: return "!=";
case Token.EQUALS_EQUALS_EQUALS: return "===";
case Token.EXCLAMATION_EQUALS_EQUALS: return "!==";
case Token.PLUS: return "+";
case Token.MINUS: return "-";
case Token.ASTERISK_ASTERISK: return "**";
case Token.ASTERISK: return "*";
case Token.SLASH: return "/";
case Token.PERCENT: return "%";
case Token.PLUS_PLUS: return "++";
case Token.MINUS_MINUS: return "--";
case Token.LESSTHAN_LESSTHAN: return "<<";
case Token.GREATERTHAN_GREATERTHAN: return ">>";
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN: return ">>>";
case Token.AMPERSAND: return "&";
case Token.BAR: return "|";
case Token.CARET: return "^";
case Token.EXCLAMATION: return "!";
case Token.TILDE: return "~";
case Token.AMPERSAND_AMPERSAND: return "&&";
case Token.BAR_BAR: return "||";
case Token.EQUALS: return "=";
case Token.PLUS_EQUALS: return "+=";
case Token.MINUS_EQUALS: return "-=";
case Token.ASTERISK_EQUALS: return "*=";
case Token.ASTERISK_ASTERISK_EQUALS: return "**=";
case Token.SLASH_EQUALS: return "/=";
case Token.PERCENT_EQUALS: return "%=";
case Token.LESSTHAN_LESSTHAN_EQUALS: return "<<=";
case Token.GREATERTHAN_GREATERTHAN_EQUALS: return ">>=";
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS: return ">>>=";
case Token.AMPERSAND_EQUALS: return "&=";
case Token.BAR_EQUALS: return "|=";
case Token.CARET_EQUALS: return "^=";
default: assert(false); return "";
}
}
}
export class Range {