Binary expression operator overloads for +/==; Check allocation flow in ternary expressions; Cache empty array buffers; Sealed decorator for non-derivable internals

This commit is contained in:
dcodeIO 2018-03-23 12:45:29 +01:00
parent 9cc0fcd611
commit 4adb69f73a
18 changed files with 5074 additions and 267 deletions

2
dist/asc.js vendored

File diff suppressed because one or more lines are too long

2
dist/asc.js.map 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

@ -2672,7 +2672,18 @@ export class Compiler extends DiagnosticEmitter {
expr = module.createBinary(BinaryOp.EqI32, leftExpr, rightExpr);
break;
}
case TypeKind.USIZE: // TODO: check operator overload
case TypeKind.USIZE: { // check operator overload
if (this.currentType.is(TypeFlags.REFERENCE)) {
let classInstance = assert(this.currentType.classReference);
let operatorName = classInstance.prototype.fnEquals;
if (operatorName != null) {
expr = this.compileOperatorOverload(classInstance, operatorName, leftExpr, rightExpr);
assert(this.currentType == Type.bool);
break;
}
}
// fall-through
}
case TypeKind.ISIZE: {
expr = module.createBinary(
this.options.isWasm64
@ -2822,7 +2833,17 @@ export class Compiler extends DiagnosticEmitter {
expr = module.createBinary(BinaryOp.AddI32, leftExpr, rightExpr);
break;
}
case TypeKind.USIZE: // TODO: check operator overload
case TypeKind.USIZE: { // check operator overload
if (this.currentType.is(TypeFlags.REFERENCE)) {
let classInstance = assert(this.currentType.classReference);
let operatorName = classInstance.prototype.fnConcat;
if (operatorName != null) {
expr = this.compileOperatorOverload(classInstance, operatorName, leftExpr, rightExpr);
break;
}
}
// fall-through
}
case TypeKind.ISIZE: {
expr = module.createBinary(
this.options.isWasm64
@ -3726,6 +3747,20 @@ export class Compiler extends DiagnosticEmitter {
: expr;
}
compileOperatorOverload(
classInstance: Class,
operatorName: string,
leftExpr: ExpressionRef,
rightExpr: ExpressionRef
): ExpressionRef {
var classPrototype = classInstance.prototype;
var operatorPrototype = assert(assert(classPrototype.members).get(operatorName));
assert(operatorPrototype.kind == ElementKind.FUNCTION_PROTOTYPE);
var operatorInstance = (<FunctionPrototype>operatorPrototype).resolve();
if (!operatorInstance) return this.module.createUnreachable();
return this.makeCallDirect(operatorInstance, [ leftExpr, rightExpr ]);
}
compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): ExpressionRef {
var currentFunction = this.currentFunction;
var resolved = this.program.resolveExpression(expression, currentFunction); // reports
@ -4526,7 +4561,6 @@ export class Compiler extends DiagnosticEmitter {
assert(parent.kind == ElementKind.CLASS);
let thisType = (<Class>parent).type;
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
let nativeSizeType = this.options.nativeSizeType;
let flow = currentFunction.flow;
if (!flow.is(FlowFlags.ALLOCATES)) {
flow.set(FlowFlags.ALLOCATES);
@ -5152,8 +5186,36 @@ export class Compiler extends DiagnosticEmitter {
: this.compileExpression(ifElse, contextualType);
}
var ifThenExpr = this.compileExpression(ifThen, contextualType);
var ifElseExpr = this.compileExpression(ifElse, contextualType);
var currentFunction = this.currentFunction;
var ifThenExpr: ExpressionRef;
var ifElseExpr: ExpressionRef;
// if part of a constructor, keep track of memory allocations
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
let flow = currentFunction.flow;
flow = flow.enterBranchOrScope();
currentFunction.flow = flow;
ifThenExpr = this.compileExpression(ifThen, contextualType);
let ifThenAllocates = flow.is(FlowFlags.ALLOCATES);
flow = flow.leaveBranchOrScope();
currentFunction.flow = flow;
flow = flow.enterBranchOrScope();
currentFunction.flow = flow;
ifElseExpr = this.compileExpression(ifElse, contextualType);
let ifElseAllocates = flow.is(FlowFlags.ALLOCATES);
flow = flow.leaveBranchOrScope();
currentFunction.flow = flow;
if (ifThenAllocates && ifElseAllocates) flow.set(FlowFlags.ALLOCATES);
// otherwise simplify
} else {
ifThenExpr = this.compileExpression(ifThen, contextualType);
ifElseExpr = this.compileExpression(ifElse, contextualType);
}
return this.module.createIf(condExpr, ifThenExpr, ifElseExpr);
}

View File

@ -20,6 +20,7 @@ export enum DiagnosticCode {
Structs_cannot_implement_interfaces = 208,
Invalid_regular_expression_flags = 209,
Implementation_0_must_match_the_signature_1 = 210,
Class_0_is_sealed_and_cannot_be_extended = 211,
Unterminated_string_literal = 1002,
Identifier_expected = 1003,
_0_expected = 1005,
@ -122,6 +123,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 208: return "Structs cannot implement interfaces.";
case 209: return "Invalid regular expression flags.";
case 210: return "Implementation '{0}' must match the signature '{1}'.";
case 211: return "Class '{0}' is sealed and cannot be extended.";
case 1002: return "Unterminated string literal.";
case 1003: return "Identifier expected.";
case 1005: return "'{0}' expected.";

View File

@ -12,6 +12,7 @@
"Structs cannot implement interfaces.": 208,
"Invalid regular expression flags.": 209,
"Implementation '{0}' must match the signature '{1}'.": 210,
"Class '{0}' is sealed and cannot be extended.": 211,
"Unterminated string literal.": 1002,
"Identifier expected.": 1003,

View File

@ -171,6 +171,10 @@ export class Parser extends DiagnosticEmitter {
flags |= CommonFlags.UNMANAGED;
continue;
}
if (text == "sealed") {
flags |= CommonFlags.SEALED;
continue;
}
}
if (!decorators) decorators = [];
decorators.push(decorator);

View File

@ -2041,34 +2041,36 @@ export enum CommonFlags {
BUILTIN = 1 << 14,
/** Is unmanaged. */
UNMANAGED = 1 << 15,
/** Is sealed. */
SEALED = 1 << 16,
// Extended modifiers usually derived from basic modifiers or internal decorators
/** Is ambient, that is either declared or nested in a declared element. */
AMBIENT = 1 << 16,
AMBIENT = 1 << 17,
/** Is generic. */
GENERIC = 1 << 17,
GENERIC = 1 << 18,
/** Is part of a generic context. */
GENERIC_CONTEXT = 1 << 18,
GENERIC_CONTEXT = 1 << 19,
/** Is an instance member. */
INSTANCE = 1 << 19,
INSTANCE = 1 << 20,
/** Is a constructor. */
CONSTRUCTOR = 1 << 20,
CONSTRUCTOR = 1 << 21,
/** Is an arrow function. */
ARROW = 1 << 21,
ARROW = 1 << 22,
/** Is a module export. */
MODULE_EXPORT = 1 << 22,
MODULE_EXPORT = 1 << 23,
/** Is a module import. */
MODULE_IMPORT = 1 << 23,
MODULE_IMPORT = 1 << 24,
// Compilation states
/** Is compiled. */
COMPILED = 1 << 24,
COMPILED = 1 << 25,
/** Has a constant value and is therefore inlined. */
INLINED = 1 << 25,
INLINED = 1 << 26,
/** Is scoped. */
SCOPED = 1 << 26
SCOPED = 1 << 27
}
/** Base class of all program elements. */
@ -2873,6 +2875,13 @@ export class ClassPrototype extends Element {
);
return null;
}
if (baseClass.is(CommonFlags.SEALED)) {
this.program.error(
DiagnosticCode.Class_0_is_sealed_and_cannot_be_extended,
declaration.extendsType.range, baseClass.internalName
);
return null;
}
if (baseClass.prototype.is(CommonFlags.UNMANAGED) != this.is(CommonFlags.UNMANAGED)) {
this.program.error(
DiagnosticCode.Structs_cannot_extend_classes_and_vice_versa,

3
std/assembly.d.ts vendored
View File

@ -354,5 +354,8 @@ declare function operator(token: string): (target: any, propertyKey: string, des
/** Annotates a class as being unmanaged with limited capabilities. */
declare function unmanaged(target: Function): any;
/** Annotates a class as being sealed / non-derivable. */
declare function sealed(target: Function): any;
/** Annotates a class field with an explicit offset. */
declare function offset(offset: usize): any;

View File

@ -240,6 +240,7 @@ export class Array<T> {
}
@unmanaged
@sealed
export class CArray<T> {
private constructor() {}

View File

@ -1,14 +1,12 @@
const HEADER_SIZE: usize = sizeof<i32>();
@unmanaged
@sealed
export class ArrayBuffer {
readonly byteLength: i32;
constructor(length: i32) {
if (<u32>length > 0x7fffffff) {
throw new RangeError("Invalid array buffer length");
}
if (<u32>length > 0x7fffffff) throw new RangeError("Invalid array buffer length");
var buffer = allocate_memory(HEADER_SIZE + <usize>length);
store<i32>(buffer, length);
return changetype<ArrayBuffer>(buffer);
@ -21,9 +19,21 @@ export class ArrayBuffer {
if (end < 0) end = max(len + end, 0);
else end = min(end, len);
var newLen = max(end - begin, 0);
var buffer = allocate_memory(HEADER_SIZE + <usize>newLen);
store<i32>(buffer, newLen);
move_memory(buffer + HEADER_SIZE, changetype<usize>(this) + HEADER_SIZE + begin, newLen);
return changetype<ArrayBuffer>(buffer);
if (newLen) {
let buffer = allocate_memory(HEADER_SIZE + <usize>newLen);
store<i32>(buffer, newLen);
move_memory(buffer + HEADER_SIZE, changetype<usize>(this) + HEADER_SIZE + begin, newLen);
return changetype<ArrayBuffer>(buffer);
} else if (ArrayBuffer.EMPTY) {
return ArrayBuffer.EMPTY;
} else {
let buffer = allocate_memory(HEADER_SIZE);
store<i32>(buffer, 0);
ArrayBuffer.EMPTY = changetype<ArrayBuffer>(buffer);
return changetype<ArrayBuffer>(buffer);
}
}
/** @internal */
static EMPTY: ArrayBuffer | null = null;
}

View File

@ -2,15 +2,16 @@
const EMPTY: String = changetype<String>("");
// number of bytes preceeding string data
const HEAD: usize = 4;
const HEADER_SIZE: usize = 4;
function allocate(length: i32): String {
assert(length > 0); // 0 -> EMPTY
var ptr = allocate_memory(HEAD + (<usize>length << 1));
var ptr = allocate_memory(HEADER_SIZE + (<usize>length << 1));
store<i32>(ptr, length);
return changetype<String>(ptr);
}
@sealed
export class String {
readonly length: i32; // capped to [0, 0x7fffffff]
@ -28,9 +29,9 @@ export class String {
changetype<usize>(out),
load<u16>(
changetype<usize>(this) + (<usize>pos << 1),
HEAD
HEADER_SIZE
),
HEAD
HEADER_SIZE
);
return out;
}
@ -42,7 +43,7 @@ export class String {
}
return load<u16>(
changetype<usize>(this) + (<usize>pos << 1),
HEAD
HEADER_SIZE
);
}
@ -53,14 +54,14 @@ export class String {
}
var first = <i32>load<u16>(
changetype<usize>(this) + (<usize>pos << 1),
HEAD
HEADER_SIZE
);
if (first < 0xD800 || first > 0xDBFF || pos + 1 == this.length) {
return first;
}
var second = <i32>load<u16>(
changetype<usize>(this) + ((<usize>pos + 1) << 1),
HEAD
HEADER_SIZE
);
if (second < 0xDC00 || second > 0xDFFF) {
return first;
@ -70,32 +71,26 @@ export class String {
@operator("+")
private static __concat(left: String, right: String): String {
if (left == null) {
left = changetype<String>("null");
}
if (!changetype<usize>(left)) left = changetype<String>("null");
return left.concat(right);
}
concat(other: String): String {
assert(this != null);
if (other == null) {
other = changetype<String>("null");
}
if (other == null) other = changetype<String>("null");
var thisLen: isize = this.length;
var otherLen: isize = other.length;
var outLen: usize = thisLen + otherLen;
if (outLen == 0) {
return EMPTY;
}
if (outLen == 0) return EMPTY;
var out = allocate(outLen);
move_memory(
changetype<usize>(out) + HEAD,
changetype<usize>(this) + HEAD,
changetype<usize>(out) + HEADER_SIZE,
changetype<usize>(this) + HEADER_SIZE,
thisLen << 1
);
move_memory(
changetype<usize>(out) + HEAD + (thisLen << 1),
changetype<usize>(other) + HEAD,
changetype<usize>(out) + HEADER_SIZE + (thisLen << 1),
changetype<usize>(other) + HEADER_SIZE,
otherLen << 1
);
return out;
@ -113,26 +108,21 @@ export class String {
return false;
}
return !compare_memory(
changetype<usize>(this) + HEAD + (start << 1),
changetype<usize>(searchString) + HEAD,
changetype<usize>(this) + HEADER_SIZE + (start << 1),
changetype<usize>(searchString) + HEADER_SIZE,
searchLength << 1
);
}
@operator("==")
private static __eq(left: String, right: String): bool {
if (left == null) {
return right == null;
} else if (right == null) {
return false;
}
if (!changetype<usize>(left)) return !changetype<usize>(right);
else if (!changetype<usize>(right)) return false;
var leftLength = left.length;
if (leftLength != right.length) {
return false;
}
if (leftLength != right.length) return false;
return !compare_memory(
changetype<usize>(left) + HEAD,
changetype<usize>(right) + HEAD,
changetype<usize>(left) + HEADER_SIZE,
changetype<usize>(right) + HEADER_SIZE,
(<usize>leftLength << 1)
);
}
@ -154,8 +144,8 @@ export class String {
// TODO: two-way, multiple char codes
for (let k: usize = start; <isize>k + searchLen <= len; ++k) {
if (!compare_memory(
changetype<usize>(this) + HEAD + (k << 1),
changetype<usize>(searchString) + HEAD,
changetype<usize>(this) + HEADER_SIZE + (k << 1),
changetype<usize>(searchString) + HEADER_SIZE,
searchLen << 1)
) {
return <i32>k;
@ -177,8 +167,8 @@ export class String {
return false;
}
return !compare_memory(
changetype<usize>(this) + HEAD + (start << 1),
changetype<usize>(searchString) + HEAD,
changetype<usize>(this) + HEADER_SIZE + (start << 1),
changetype<usize>(searchString) + HEADER_SIZE,
searchLength << 1
);
}
@ -197,8 +187,8 @@ export class String {
}
var out = allocate(resultLength);
move_memory(
changetype<usize>(out) + HEAD,
changetype<usize>(this) + HEAD + (intStart << 1),
changetype<usize>(out) + HEADER_SIZE,
changetype<usize>(this) + HEADER_SIZE + (intStart << 1),
<usize>resultLength << 1
);
return out;
@ -220,8 +210,8 @@ export class String {
}
var out = allocate(len);
move_memory(
changetype<usize>(out) + HEAD,
changetype<usize>(this) + HEAD + (from << 1),
changetype<usize>(out) + HEADER_SIZE,
changetype<usize>(this) + HEADER_SIZE + (from << 1),
len << 1
);
return out;
@ -233,7 +223,7 @@ export class String {
while (
length &&
isWhiteSpaceOrLineTerminator(
load<u16>(changetype<usize>(this) + (length << 1), HEAD)
load<u16>(changetype<usize>(this) + (length << 1), HEADER_SIZE)
)
) {
--length;
@ -242,7 +232,7 @@ export class String {
while (
start < length &&
isWhiteSpaceOrLineTerminator(
load<u16>(changetype<usize>(this) + (start << 1), HEAD)
load<u16>(changetype<usize>(this) + (start << 1), HEADER_SIZE)
)
) {
++start, --length;
@ -255,8 +245,8 @@ export class String {
}
var out = allocate(length);
move_memory(
changetype<usize>(out) + HEAD,
changetype<usize>(this) + HEAD + (start << 1),
changetype<usize>(out) + HEADER_SIZE,
changetype<usize>(this) + HEADER_SIZE + (start << 1),
length << 1
);
return out;
@ -269,7 +259,7 @@ export class String {
while (
start < len &&
isWhiteSpaceOrLineTerminator(
load<u16>(changetype<usize>(this) + (start << 1), HEAD)
load<u16>(changetype<usize>(this) + (start << 1), HEADER_SIZE)
)
) {
++start;
@ -283,8 +273,8 @@ export class String {
}
var out = allocate(outLen);
move_memory(
changetype<usize>(out) + HEAD,
changetype<usize>(this) + HEAD + (start << 1),
changetype<usize>(out) + HEADER_SIZE,
changetype<usize>(this) + HEADER_SIZE + (start << 1),
outLen << 1
);
return out;
@ -296,7 +286,7 @@ export class String {
while (
len > 0 &&
isWhiteSpaceOrLineTerminator(
load<u16>(changetype<usize>(this) + (len << 1), HEAD)
load<u16>(changetype<usize>(this) + (len << 1), HEADER_SIZE)
)
) {
--len;
@ -309,8 +299,8 @@ export class String {
}
var out = allocate(len);
move_memory(
changetype<usize>(out) + HEAD,
changetype<usize>(this) + HEAD,
changetype<usize>(out) + HEADER_SIZE,
changetype<usize>(this) + HEADER_SIZE,
len << 1
);
return out;
@ -381,7 +371,7 @@ function parse<T>(str: String, radix: i32 = 0): T {
return <T>NaN;
}
var ptr = changetype<usize>(str) /* + HEAD -> offset */;
var code = <i32>load<u16>(ptr, HEAD);
var code = <i32>load<u16>(ptr, HEADER_SIZE);
// determine sign
var sign: T;
@ -389,13 +379,13 @@ function parse<T>(str: String, radix: i32 = 0): T {
if (!--len) {
return <T>NaN;
}
code = <i32>load<u16>(ptr += 2, HEAD);
code = <i32>load<u16>(ptr += 2, HEADER_SIZE);
sign = -1;
} else if (code == CharCode.PLUS) {
if (!--len) {
return <T>NaN;
}
code = <i32>load<u16>(ptr += 2, HEAD);
code = <i32>load<u16>(ptr += 2, HEADER_SIZE);
sign = 1;
} else {
sign = 1;
@ -404,7 +394,7 @@ function parse<T>(str: String, radix: i32 = 0): T {
// determine radix
if (!radix) {
if (code == CharCode._0 && len > 2) {
switch (<i32>load<u16>(ptr + 2, HEAD)) {
switch (<i32>load<u16>(ptr + 2, HEADER_SIZE)) {
case CharCode.B:
case CharCode.b: {
ptr += 4; len -= 2;
@ -435,7 +425,7 @@ function parse<T>(str: String, radix: i32 = 0): T {
// calculate value
var num: T = 0;
while (len--) {
code = <i32>load<u16>(ptr, HEAD);
code = <i32>load<u16>(ptr, HEADER_SIZE);
if (code >= CharCode._0 && code <= CharCode._9) {
code -= CharCode._0;
} else if (code >= CharCode.A && code <= CharCode.Z) {
@ -460,7 +450,7 @@ export function parseFloat(str: String): f64 {
return NaN;
}
var ptr = changetype<usize>(str) /* + HEAD -> offset */;
var code = <i32>load<u16>(ptr, HEAD);
var code = <i32>load<u16>(ptr, HEADER_SIZE);
// determine sign
var sign: f64;
@ -468,13 +458,13 @@ export function parseFloat(str: String): f64 {
if (!--len) {
return NaN;
}
code = <i32>load<u16>(ptr += 2, HEAD);
code = <i32>load<u16>(ptr += 2, HEADER_SIZE);
sign = -1;
} else if (code == CharCode.PLUS) {
if (!--len) {
return NaN;
}
code = <i32>load<u16>(ptr += 2, HEAD);
code = <i32>load<u16>(ptr += 2, HEADER_SIZE);
sign = 1;
} else {
sign = 1;
@ -483,12 +473,12 @@ export function parseFloat(str: String): f64 {
// calculate value
var num: f64 = 0;
while (len--) {
code = <i32>load<u16>(ptr, HEAD);
code = <i32>load<u16>(ptr, HEADER_SIZE);
if (code == CharCode.DOT) {
ptr += 2;
let fac: f64 = 0.1; // precision :(
while (len--) {
code = <i32>load<u16>(ptr, HEAD);
code = <i32>load<u16>(ptr, HEADER_SIZE);
if (code == CharCode.E || code == CharCode.e) {
assert(false); // TODO
}

View File

@ -10,6 +10,7 @@
(global "$(lib)/allocator/arena/startOffset" (mut i32) (i32.const 0))
(global "$(lib)/allocator/arena/offset" (mut i32) (i32.const 0))
(global $std/arraybuffer/buffer (mut i32) (i32.const 0))
(global "$(lib)/arraybuffer/ArrayBuffer.EMPTY" (mut i32) (i32.const 0))
(global $std/arraybuffer/sliced (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 44))
(memory $0 1)
@ -2028,82 +2029,105 @@
)
)
)
(i32.store
(tee_local $3
(call "$(lib)/allocator/arena/allocate_memory"
(i32.add
(tee_local $2
(select
(tee_local $3
(i32.sub
(tee_local $2
(if (result i32)
(i32.lt_s
(get_local $2)
(i32.const 0)
)
(select
(tee_local $3
(i32.add
(get_local $5)
(get_local $2)
)
)
(tee_local $4
(i32.const 0)
)
(i32.gt_s
(get_local $3)
(get_local $4)
)
)
(select
(tee_local $3
(get_local $2)
)
(tee_local $4
(get_local $5)
)
(i32.lt_s
(get_local $3)
(get_local $4)
)
)
(if (result i32)
(tee_local $2
(select
(tee_local $3
(i32.sub
(tee_local $2
(if (result i32)
(i32.lt_s
(get_local $2)
(i32.const 0)
)
(select
(tee_local $3
(i32.add
(get_local $5)
(get_local $2)
)
)
(get_local $1)
(tee_local $4
(i32.const 0)
)
(i32.gt_s
(get_local $3)
(get_local $4)
)
)
(select
(tee_local $3
(get_local $2)
)
(tee_local $4
(get_local $5)
)
(i32.lt_s
(get_local $3)
(get_local $4)
)
)
)
(tee_local $4
(i32.const 0)
)
(i32.gt_s
(get_local $3)
(get_local $4)
)
)
(get_local $1)
)
(i32.const 4)
)
(tee_local $4
(i32.const 0)
)
(i32.gt_s
(get_local $3)
(get_local $4)
)
)
)
(get_local $2)
)
(call "$(lib)/memory/move_memory"
(i32.add
(get_local $3)
(i32.const 4)
)
(i32.add
(i32.add
(get_local $0)
(i32.const 4)
(block (result i32)
(i32.store
(tee_local $3
(call "$(lib)/allocator/arena/allocate_memory"
(i32.add
(get_local $2)
(i32.const 4)
)
)
)
(get_local $2)
)
(call "$(lib)/memory/move_memory"
(i32.add
(get_local $3)
(i32.const 4)
)
(i32.add
(i32.add
(get_local $0)
(i32.const 4)
)
(get_local $1)
)
(get_local $2)
)
(get_local $3)
)
(if (result i32)
(get_global "$(lib)/arraybuffer/ArrayBuffer.EMPTY")
(get_global "$(lib)/arraybuffer/ArrayBuffer.EMPTY")
(block (result i32)
(i32.store
(tee_local $3
(call "$(lib)/allocator/arena/allocate_memory"
(i32.const 4)
)
)
(i32.const 0)
)
(set_global "$(lib)/arraybuffer/ArrayBuffer.EMPTY"
(get_local $3)
)
(get_local $3)
)
(get_local $1)
)
(get_local $2)
)
(get_local $3)
)
(func "$(lib)/arraybuffer/ArrayBuffer#slice|trampoline" (; 6 ;) (type $iiiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)
(block $N=2

View File

@ -15,6 +15,7 @@
(global "$(lib)/allocator/arena/offset" (mut i32) (i32.const 0))
(global "$(lib)/arraybuffer/HEADER_SIZE" i32 (i32.const 4))
(global $std/arraybuffer/buffer (mut i32) (i32.const 0))
(global "$(lib)/arraybuffer/ArrayBuffer.EMPTY" (mut i32) (i32.const 0))
(global $std/arraybuffer/sliced (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 44))
(memory $0 1)
@ -2280,7 +2281,6 @@
(local $4 i32)
(local $5 i32)
(local $6 i32)
(local $7 i32)
(set_local $3
(i32.load
(get_local $0)
@ -2377,34 +2377,62 @@
)
)
)
(set_local $7
(call "$(lib)/allocator/arena/allocate_memory"
(i32.add
(i32.const 4)
(if
(get_local $6)
(block
(set_local $4
(call "$(lib)/allocator/arena/allocate_memory"
(i32.add
(i32.const 4)
(get_local $6)
)
)
)
(i32.store
(get_local $4)
(get_local $6)
)
)
)
(i32.store
(get_local $7)
(get_local $6)
)
(call "$(lib)/memory/move_memory"
(i32.add
(get_local $7)
(i32.const 4)
)
(i32.add
(i32.add
(get_local $0)
(i32.const 4)
(call "$(lib)/memory/move_memory"
(i32.add
(get_local $4)
(i32.const 4)
)
(i32.add
(i32.add
(get_local $0)
(i32.const 4)
)
(get_local $1)
)
(get_local $6)
)
(return
(get_local $4)
)
)
(if
(get_global "$(lib)/arraybuffer/ArrayBuffer.EMPTY")
(return
(get_global "$(lib)/arraybuffer/ArrayBuffer.EMPTY")
)
(block
(set_local $4
(call "$(lib)/allocator/arena/allocate_memory"
(i32.const 4)
)
)
(i32.store
(get_local $4)
(i32.const 0)
)
(set_global "$(lib)/arraybuffer/ArrayBuffer.EMPTY"
(get_local $4)
)
(return
(get_local $4)
)
)
(get_local $1)
)
(get_local $6)
)
(return
(get_local $7)
)
)
(func "$(lib)/arraybuffer/ArrayBuffer#slice|trampoline" (; 6 ;) (type $iiiii) (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32) (result i32)

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,5 @@
import "allocator/arena";
// preliminary
var str: string = "hi, I'm a string";
@ -31,3 +33,6 @@ assert(parseFloat("1") == 1);
assert(parseFloat("0.1") == 0.1);
assert(parseFloat(".25") == 0.25);
assert(parseFloat(".1foobar") == 0.1);
var c = "a" + "b";
assert(c == "ab");

File diff suppressed because it is too large Load Diff