mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 23:12:19 +00:00
A first take on imported built-ins
This commit is contained in:
parent
09cbad6ede
commit
ad1fbcf5b2
@ -3,7 +3,7 @@ AssemblyScript NEXT
|
||||
|
||||
[](https://travis-ci.org/AssemblyScript/next)
|
||||
|
||||
**AssemblyScript** is a new compiler targeting WebAssembly while utilizing [TypeScript](http://www.typescriptlang.org)'s syntax and [node](https://nodejs.org)'s vibrant ecosystem. Instead of requiring complex toolchains to set up, you can simply `npm install` it - or run it in a browser.
|
||||
**AssemblyScript** is a new compiler targeting [WebAssembly](http://webassembly.org) while utilizing [TypeScript](http://www.typescriptlang.org)'s syntax and [node](https://nodejs.org)'s vibrant ecosystem. Instead of requiring complex toolchains to set up, you can simply `npm install` it - or run it in a browser.
|
||||
|
||||
By compiling a variant of TypeScript to [Binaryen](https://github.com/WebAssembly/binaryen) IR, the resulting module can be validated, optimized, emitted in WebAssembly text or binary format and converted to [asm.js](http://asmjs.org) as a polyfill.
|
||||
|
||||
|
4
assembly.d.ts
vendored
4
assembly.d.ts
vendored
@ -90,6 +90,10 @@ declare function isNaN<T = f32 | f64>(value: T): bool;
|
||||
declare function isFinite<T = f32 | f64>(value: T): bool;
|
||||
/** Traps if the specified value evaluates to `false`. */
|
||||
declare function assert(isTrue: bool): 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. */
|
||||
declare function parseFloat(str: string): f64;
|
||||
|
||||
// Internal decorators (not yet implemented)
|
||||
|
||||
|
7
portable.d.ts
vendored
7
portable.d.ts
vendored
@ -52,6 +52,10 @@ declare function unreachable(): any; // sic
|
||||
declare function changetype<T1,T2>(value: T1): T2;
|
||||
/** Traps if the specified value evaluates to `false`. */
|
||||
declare function assert(isTrue: bool): 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. */
|
||||
declare function parseFloat(str: string): f64;
|
||||
|
||||
// Portable standard library
|
||||
// Everything marked @deprecated is a temporary filler. Do not use.
|
||||
@ -143,6 +147,3 @@ declare namespace console {
|
||||
/** @deprecated */
|
||||
function log(message: string): void;
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
declare function parseFloat(str: string): f64;
|
||||
|
@ -2,7 +2,7 @@ import { Compiler, Target, typeToNativeType, typeToNativeOne } from "./compiler"
|
||||
import { DiagnosticCode } from "./diagnostics";
|
||||
import { Node, Expression } from "./ast";
|
||||
import { Type } from "./types";
|
||||
import { Module, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType } from "./module";
|
||||
import { Module, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType, FunctionTypeRef } from "./module";
|
||||
import { Program, FunctionPrototype, Local } from "./program";
|
||||
|
||||
/** Initializes the specified program with built-in functions. */
|
||||
@ -33,23 +33,23 @@ export function initialize(program: Program): void {
|
||||
addFunction(program, "isNaN", true);
|
||||
addFunction(program, "isFinite", true);
|
||||
addFunction(program, "assert");
|
||||
// addFunction(program, "fmod", false, true);
|
||||
// addFunction(program, "pow", true, true);
|
||||
addFunction(program, "parseInt");
|
||||
addFunction(program, "parseFloat");
|
||||
}
|
||||
|
||||
/** Adds a built-in function to the specified program. */
|
||||
function addFunction(program: Program, name: string, isGeneric: bool = false, isImport: bool = false): void {
|
||||
function addFunction(program: Program, name: string, isGeneric: bool = false): void {
|
||||
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
|
||||
prototype.isBuiltIn = true;
|
||||
prototype.isGeneric = isGeneric;
|
||||
prototype.isImport = isImport;
|
||||
program.elements.set(name, prototype);
|
||||
}
|
||||
|
||||
/** Compiles a call to a built-in function. */
|
||||
export function compileCall(compiler: Compiler, internalName: string, typeArguments: Type[], operands: Expression[], reportNode: Node): ExpressionRef {
|
||||
export function compileCall(compiler: Compiler, prototype: FunctionPrototype, typeArguments: Type[], operands: Expression[], reportNode: Node): ExpressionRef {
|
||||
const module: Module = compiler.module;
|
||||
const usizeType: Type = select<Type>(Type.usize64, Type.usize32, compiler.options.target == Target.WASM64);
|
||||
const nativeUsizeType: NativeType = select<NativeType>(NativeType.I64, NativeType.I32, compiler.options.target == Target.WASM64);
|
||||
|
||||
let arg0: ExpressionRef,
|
||||
arg1: ExpressionRef,
|
||||
@ -59,8 +59,9 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume
|
||||
let tempLocal1: Local;
|
||||
|
||||
let type: Type;
|
||||
var ftype: FunctionTypeRef;
|
||||
|
||||
switch (internalName) {
|
||||
switch (prototype.internalName) {
|
||||
|
||||
case "clz": // clz<T>(value: T) -> T
|
||||
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
|
||||
@ -498,8 +499,42 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume
|
||||
module.createUnreachable()
|
||||
);
|
||||
|
||||
// case "fmod":
|
||||
// case "pow":
|
||||
case "parseInt": // takes a pointer to the string
|
||||
compiler.currentType = Type.f64;
|
||||
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();
|
||||
}
|
||||
if (!prototype.isCompiled) {
|
||||
if (!(ftype = module.getFunctionTypeBySignature(NativeType.F64, [ nativeUsizeType, NativeType.I32 ])))
|
||||
ftype = module.addFunctionType(nativeUsizeType == NativeType.I64 ? "FIi" : "Fii", NativeType.F64, [ nativeUsizeType, NativeType.I32 ]);
|
||||
module.addFunctionImport("parseInt", "env", "parseInt", ftype); // FIXME: can't call with i64 pointers (WASM64)
|
||||
prototype.isCompiled = true;
|
||||
}
|
||||
arg0 = compiler.compileExpression(operands[0], usizeType); // reports
|
||||
arg1 = operands.length == 2 ? compiler.compileExpression(operands[1], Type.i32) : module.createI32(-1); // -1 marks omitted
|
||||
return module.createCallImport("parseInt", [ arg0, arg1 ], NativeType.F64);
|
||||
|
||||
case "parseFloat": // takes a pointer to the string
|
||||
compiler.currentType = Type.f64;
|
||||
if (!validateCall(compiler, typeArguments, 0, operands, 1, reportNode))
|
||||
return module.createUnreachable();
|
||||
if (!prototype.isCompiled) {
|
||||
if (!(ftype = module.getFunctionTypeBySignature(NativeType.F64, [ nativeUsizeType ])))
|
||||
ftype = module.addFunctionType(nativeUsizeType == NativeType.I64 ? "FI" : "Fi", NativeType.F64, [ nativeUsizeType ]);
|
||||
module.addFunctionImport("parseFloat", "env", "parseFloat", ftype); // FIXME: can't call with i64 pointers (WASM64)
|
||||
prototype.isCompiled = true;
|
||||
}
|
||||
arg0 = compiler.compileExpression(operands[0], usizeType); // reports
|
||||
return module.createCallImport("parseFloat", [ arg0 ], NativeType.F64);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1673,7 +1673,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
functionInstance = <Function | null>functionPrototype.instances.get(sb.join(","));
|
||||
if (!functionInstance) {
|
||||
this.currentType = contextualType;
|
||||
let expr: ExpressionRef = compileBuiltinCall(this, functionPrototype.internalName, resolvedTypeArguments, expression.arguments, expression);
|
||||
let expr: ExpressionRef = compileBuiltinCall(this, functionPrototype, resolvedTypeArguments, expression.arguments, expression);
|
||||
if (!expr) {
|
||||
this.error(DiagnosticCode.Operation_not_supported, expression.range);
|
||||
return this.module.createUnreachable();
|
||||
|
@ -41,6 +41,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
[program.exports]
|
||||
|
||||
;)
|
||||
|
@ -844,6 +844,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
binary/b
|
||||
binary/i
|
||||
binary/I
|
||||
|
@ -1,6 +1,6 @@
|
||||
let b: bool;
|
||||
|
||||
// integer builtins
|
||||
// integers
|
||||
|
||||
let i: i32;
|
||||
|
||||
@ -40,7 +40,7 @@ I = abs<i64>(-42); assert(I == 42);
|
||||
I = max<i64>(1, 2); assert(I == 2);
|
||||
I = min<i64>(1, 2); assert(i == 1);
|
||||
|
||||
// floating point builtins
|
||||
// floats
|
||||
|
||||
let f: f32;
|
||||
|
||||
@ -104,7 +104,7 @@ F = trunc<f64>(1.25);
|
||||
b = isNaN<f64>(1.25);
|
||||
b = isFinite<f64>(1.25);
|
||||
|
||||
// load and store builtins
|
||||
// load and store
|
||||
|
||||
i = load<i32>(8); store<i32>(8, i);
|
||||
store<i32>(8, load<i32>(8));
|
||||
@ -115,7 +115,7 @@ store<f32>(8, load<f32>(8));
|
||||
F = load<f64>(8); store<f64>(8, F);
|
||||
store<f64>(8, load<f64>(8));
|
||||
|
||||
// reinterpretation builtins
|
||||
// reinterpretation
|
||||
|
||||
reinterpret<f32,i32>(1.25);
|
||||
reinterpret<i32,f32>(25);
|
||||
@ -127,7 +127,7 @@ f = reinterpret<i32,f32>(25);
|
||||
I = reinterpret<f64,i64>(1.25);
|
||||
F = reinterpret<i64,f64>(25);
|
||||
|
||||
// host builtins
|
||||
// host
|
||||
|
||||
let s: usize;
|
||||
|
||||
@ -137,7 +137,7 @@ grow_memory(1);
|
||||
s = current_memory();
|
||||
s = grow_memory(1);
|
||||
|
||||
// other builtins
|
||||
// other
|
||||
|
||||
select<i32>(10, 20, true);
|
||||
select<i64>(100, 200, false);
|
||||
@ -151,7 +151,7 @@ F = select<f64>(12.5, 25.0, false);
|
||||
|
||||
if (0) unreachable();
|
||||
|
||||
// AS specific builtins
|
||||
// AS specific
|
||||
|
||||
sizeof<u8>();
|
||||
sizeof<u16>();
|
||||
@ -176,3 +176,11 @@ assert(!isFinite<f64>(NaN));
|
||||
assert(!isFinite<f64>(Infinity));
|
||||
assert(isFinite<f32>(0));
|
||||
assert(isFinite<f64>(0));
|
||||
|
||||
// imported
|
||||
|
||||
// TODO: Can't be interpreted due to 'Fatal: callImport: unknown import: env.parseInt'
|
||||
|
||||
// parseInt(0);
|
||||
// parseInt(0, 10);
|
||||
// parseFloat(0);
|
||||
|
@ -1087,6 +1087,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
builtins/b
|
||||
builtins/i
|
||||
builtins/I
|
||||
|
@ -34,6 +34,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
declare/external
|
||||
[program.exports]
|
||||
declare/external
|
||||
|
@ -79,6 +79,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
do/loopDo
|
||||
do/loopDoInDo
|
||||
[program.exports]
|
||||
|
@ -64,6 +64,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
enum/Implicit
|
||||
enum/Explicit
|
||||
enum/Mixed
|
||||
|
@ -54,6 +54,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
export/add
|
||||
export/sub
|
||||
export/a
|
||||
|
@ -175,6 +175,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
for/i
|
||||
[program.exports]
|
||||
|
||||
|
@ -336,6 +336,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
game-of-life/w
|
||||
game-of-life/h
|
||||
game-of-life/s
|
||||
|
@ -22,8 +22,8 @@
|
||||
(export "or" (func $i64/or))
|
||||
(export "xor" (func $i64/xor))
|
||||
(export "shl" (func $i64/shl))
|
||||
(export "shr_u" (func $i64/shr_u))
|
||||
(export "shr_s" (func $i64/shr_s))
|
||||
(export "shr_u" (func $i64/shr_u))
|
||||
(export "rotl" (func $i64/rotl_))
|
||||
(export "rotr" (func $i64/rotr_))
|
||||
(export "eq" (func $i64/eq))
|
||||
@ -580,12 +580,12 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $i64/shr_u (; 17 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
|
||||
(func $i64/shr_s (; 17 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
|
||||
(local $4 i64)
|
||||
(set_global $i64/lo
|
||||
(i32.wrap/i64
|
||||
(tee_local $4
|
||||
(i64.shr_u
|
||||
(i64.shr_s
|
||||
(i64.or
|
||||
(i64.extend_u/i32
|
||||
(get_local $0)
|
||||
@ -621,12 +621,12 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $i64/shr_s (; 18 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
|
||||
(func $i64/shr_u (; 18 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
|
||||
(local $4 i64)
|
||||
(set_global $i64/lo
|
||||
(i32.wrap/i64
|
||||
(tee_local $4
|
||||
(i64.shr_s
|
||||
(i64.shr_u
|
||||
(i64.or
|
||||
(i64.extend_u/i32
|
||||
(get_local $0)
|
||||
|
@ -102,14 +102,14 @@ export function shl(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void
|
||||
hi = <u32>(ret >>> 32);
|
||||
}
|
||||
|
||||
export function shr_u(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
|
||||
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) >> (<u64>loRight | <u64>hiRight << 32);
|
||||
export function shr_s(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
|
||||
const ret: u64 = <u64>(<i64>(<u64>loLeft | <u64>hiLeft << 32) >> <i64>(<u64>loRight | <u64>hiRight << 32));
|
||||
lo = <u32>ret;
|
||||
hi = <u32>(ret >>> 32);
|
||||
}
|
||||
|
||||
export function shr_s(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
|
||||
const ret: u64 = <u64>(<i64>(<u64>loLeft | <u64>hiLeft << 32) >> <i64>(<u64>loRight | <u64>hiRight << 32));
|
||||
export function shr_u(loLeft: u32, hiLeft: u32, loRight: u32, hiRight: u32): void {
|
||||
const ret: u64 = (<u64>loLeft | <u64>hiLeft << 32) >> (<u64>loRight | <u64>hiRight << 32);
|
||||
lo = <u32>ret;
|
||||
hi = <u32>(ret >>> 32);
|
||||
}
|
||||
|
@ -23,8 +23,8 @@
|
||||
(export "or" (func $i64/or))
|
||||
(export "xor" (func $i64/xor))
|
||||
(export "shl" (func $i64/shl))
|
||||
(export "shr_u" (func $i64/shr_u))
|
||||
(export "shr_s" (func $i64/shr_s))
|
||||
(export "shr_u" (func $i64/shr_u))
|
||||
(export "rotl" (func $i64/rotl_))
|
||||
(export "rotr" (func $i64/rotr_))
|
||||
(export "eq" (func $i64/eq))
|
||||
@ -642,11 +642,11 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $i64/shr_u (; 17 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
|
||||
(func $i64/shr_s (; 17 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
|
||||
(local $4 i64)
|
||||
(block
|
||||
(set_local $4
|
||||
(i64.shr_u
|
||||
(i64.shr_s
|
||||
(i64.or
|
||||
(i64.extend_u/i32
|
||||
(get_local $0)
|
||||
@ -686,11 +686,11 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(func $i64/shr_s (; 18 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
|
||||
(func $i64/shr_u (; 18 ;) (type $iiiiv) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
|
||||
(local $4 i64)
|
||||
(block
|
||||
(set_local $4
|
||||
(i64.shr_s
|
||||
(i64.shr_u
|
||||
(i64.or
|
||||
(i64.extend_u/i32
|
||||
(get_local $0)
|
||||
@ -1217,6 +1217,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
i64/lo
|
||||
i64/hi
|
||||
i64/getLo
|
||||
@ -1236,8 +1238,8 @@
|
||||
i64/or
|
||||
i64/xor
|
||||
i64/shl
|
||||
i64/shr_u
|
||||
i64/shr_s
|
||||
i64/shr_u
|
||||
i64/rotl_
|
||||
i64/rotr_
|
||||
i64/eq
|
||||
@ -1268,8 +1270,8 @@
|
||||
i64/or
|
||||
i64/xor
|
||||
i64/shl
|
||||
i64/shr_u
|
||||
i64/shr_s
|
||||
i64/shr_u
|
||||
i64/rotl
|
||||
i64/rotr
|
||||
i64/eq
|
||||
|
@ -74,6 +74,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
if/ifThenElse
|
||||
if/ifThen
|
||||
if/ifThenElseBlock
|
||||
|
@ -66,6 +66,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
export/add
|
||||
export/sub
|
||||
export/a
|
||||
|
@ -167,6 +167,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
[program.exports]
|
||||
|
||||
;)
|
||||
|
@ -295,6 +295,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
logical/i
|
||||
logical/I
|
||||
logical/f
|
||||
|
@ -2161,6 +2161,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
memcpy/memcpy
|
||||
memcpy/base
|
||||
memcpy/dest
|
||||
|
@ -72,6 +72,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
export/add
|
||||
export/sub
|
||||
export/a
|
||||
|
@ -173,6 +173,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
switch/doSwitch
|
||||
switch/doSwitchDefaultFirst
|
||||
switch/doSwitchDefaultOmitted
|
||||
|
@ -61,6 +61,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
ternary/a
|
||||
[program.exports]
|
||||
|
||||
|
@ -356,6 +356,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
tlsf/fls
|
||||
tlsf/ffs
|
||||
tlsf/ALIGN_SIZE_LOG2
|
||||
|
@ -661,6 +661,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
unary/i
|
||||
unary/I
|
||||
unary/f
|
||||
|
@ -88,6 +88,8 @@
|
||||
isNaN
|
||||
isFinite
|
||||
assert
|
||||
parseInt
|
||||
parseFloat
|
||||
while/loopWhile
|
||||
while/loopWhileInWhile
|
||||
[program.exports]
|
||||
|
Loading…
x
Reference in New Issue
Block a user