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); expr = module.createBinary(BinaryOp.EqI32, leftExpr, rightExpr);
break; 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: { case TypeKind.ISIZE: {
expr = module.createBinary( expr = module.createBinary(
this.options.isWasm64 this.options.isWasm64
@ -2822,7 +2833,17 @@ export class Compiler extends DiagnosticEmitter {
expr = module.createBinary(BinaryOp.AddI32, leftExpr, rightExpr); expr = module.createBinary(BinaryOp.AddI32, leftExpr, rightExpr);
break; 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: { case TypeKind.ISIZE: {
expr = module.createBinary( expr = module.createBinary(
this.options.isWasm64 this.options.isWasm64
@ -3726,6 +3747,20 @@ export class Compiler extends DiagnosticEmitter {
: expr; : 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 { compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): ExpressionRef {
var currentFunction = this.currentFunction; var currentFunction = this.currentFunction;
var resolved = this.program.resolveExpression(expression, currentFunction); // reports var resolved = this.program.resolveExpression(expression, currentFunction); // reports
@ -4526,7 +4561,6 @@ export class Compiler extends DiagnosticEmitter {
assert(parent.kind == ElementKind.CLASS); assert(parent.kind == ElementKind.CLASS);
let thisType = (<Class>parent).type; let thisType = (<Class>parent).type;
if (currentFunction.is(CommonFlags.CONSTRUCTOR)) { if (currentFunction.is(CommonFlags.CONSTRUCTOR)) {
let nativeSizeType = this.options.nativeSizeType;
let flow = currentFunction.flow; let flow = currentFunction.flow;
if (!flow.is(FlowFlags.ALLOCATES)) { if (!flow.is(FlowFlags.ALLOCATES)) {
flow.set(FlowFlags.ALLOCATES); flow.set(FlowFlags.ALLOCATES);
@ -5152,8 +5186,36 @@ export class Compiler extends DiagnosticEmitter {
: this.compileExpression(ifElse, contextualType); : this.compileExpression(ifElse, contextualType);
} }
var ifThenExpr = this.compileExpression(ifThen, contextualType); var currentFunction = this.currentFunction;
var ifElseExpr = this.compileExpression(ifElse, contextualType); 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); return this.module.createIf(condExpr, ifThenExpr, ifElseExpr);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,6 +10,7 @@
(global "$(lib)/allocator/arena/startOffset" (mut i32) (i32.const 0)) (global "$(lib)/allocator/arena/startOffset" (mut i32) (i32.const 0))
(global "$(lib)/allocator/arena/offset" (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 $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 $std/arraybuffer/sliced (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 44)) (global $HEAP_BASE i32 (i32.const 44))
(memory $0 1) (memory $0 1)
@ -2028,82 +2029,105 @@
) )
) )
) )
(i32.store (if (result i32)
(tee_local $3 (tee_local $2
(call "$(lib)/allocator/arena/allocate_memory" (select
(i32.add (tee_local $3
(tee_local $2 (i32.sub
(select (tee_local $2
(tee_local $3 (if (result i32)
(i32.sub (i32.lt_s
(tee_local $2 (get_local $2)
(if (result i32) (i32.const 0)
(i32.lt_s )
(get_local $2) (select
(i32.const 0) (tee_local $3
) (i32.add
(select (get_local $5)
(tee_local $3 (get_local $2)
(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)
)
)
) )
) )
(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) (block (result i32)
) (i32.store
(call "$(lib)/memory/move_memory" (tee_local $3
(i32.add (call "$(lib)/allocator/arena/allocate_memory"
(get_local $3) (i32.add
(i32.const 4) (get_local $2)
) (i32.const 4)
(i32.add )
(i32.add )
(get_local $0) )
(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) (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 (block $N=2

View File

@ -15,6 +15,7 @@
(global "$(lib)/allocator/arena/offset" (mut i32) (i32.const 0)) (global "$(lib)/allocator/arena/offset" (mut i32) (i32.const 0))
(global "$(lib)/arraybuffer/HEADER_SIZE" i32 (i32.const 4)) (global "$(lib)/arraybuffer/HEADER_SIZE" i32 (i32.const 4))
(global $std/arraybuffer/buffer (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 $std/arraybuffer/sliced (mut i32) (i32.const 0))
(global $HEAP_BASE i32 (i32.const 44)) (global $HEAP_BASE i32 (i32.const 44))
(memory $0 1) (memory $0 1)
@ -2280,7 +2281,6 @@
(local $4 i32) (local $4 i32)
(local $5 i32) (local $5 i32)
(local $6 i32) (local $6 i32)
(local $7 i32)
(set_local $3 (set_local $3
(i32.load (i32.load
(get_local $0) (get_local $0)
@ -2377,34 +2377,62 @@
) )
) )
) )
(set_local $7 (if
(call "$(lib)/allocator/arena/allocate_memory" (get_local $6)
(i32.add (block
(i32.const 4) (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) (get_local $6)
) )
) (call "$(lib)/memory/move_memory"
) (i32.add
(i32.store (get_local $4)
(get_local $7) (i32.const 4)
(get_local $6) )
) (i32.add
(call "$(lib)/memory/move_memory" (i32.add
(i32.add (get_local $0)
(get_local $7) (i32.const 4)
(i32.const 4) )
) (get_local $1)
(i32.add )
(i32.add (get_local $6)
(get_local $0) )
(i32.const 4) (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) (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 // preliminary
var str: string = "hi, I'm a string"; var str: string = "hi, I'm a string";
@ -31,3 +33,6 @@ assert(parseFloat("1") == 1);
assert(parseFloat("0.1") == 0.1); assert(parseFloat("0.1") == 0.1);
assert(parseFloat(".25") == 0.25); assert(parseFloat(".25") == 0.25);
assert(parseFloat(".1foobar") == 0.1); assert(parseFloat(".1foobar") == 0.1);
var c = "a" + "b";
assert(c == "ab");

File diff suppressed because it is too large Load Diff