mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 23:12:19 +00:00
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:
parent
9cc0fcd611
commit
4adb69f73a
2
dist/asc.js
vendored
2
dist/asc.js
vendored
File diff suppressed because one or more lines are too long
2
dist/asc.js.map
vendored
2
dist/asc.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js
vendored
2
dist/assemblyscript.js
vendored
File diff suppressed because one or more lines are too long
2
dist/assemblyscript.js.map
vendored
2
dist/assemblyscript.js.map
vendored
File diff suppressed because one or more lines are too long
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.";
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
3
std/assembly.d.ts
vendored
@ -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;
|
||||
|
@ -240,6 +240,7 @@ export class Array<T> {
|
||||
}
|
||||
|
||||
@unmanaged
|
||||
@sealed
|
||||
export class CArray<T> {
|
||||
|
||||
private constructor() {}
|
||||
|
@ -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);
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,10 +2029,7 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(i32.store
|
||||
(tee_local $3
|
||||
(call "$(lib)/allocator/arena/allocate_memory"
|
||||
(i32.add
|
||||
(if (result i32)
|
||||
(tee_local $2
|
||||
(select
|
||||
(tee_local $3
|
||||
@ -2083,6 +2081,12 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(block (result i32)
|
||||
(i32.store
|
||||
(tee_local $3
|
||||
(call "$(lib)/allocator/arena/allocate_memory"
|
||||
(i32.add
|
||||
(get_local $2)
|
||||
(i32.const 4)
|
||||
)
|
||||
)
|
||||
@ -2105,6 +2109,26 @@
|
||||
)
|
||||
(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)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(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=1
|
||||
|
@ -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,7 +2377,10 @@
|
||||
)
|
||||
)
|
||||
)
|
||||
(set_local $7
|
||||
(if
|
||||
(get_local $6)
|
||||
(block
|
||||
(set_local $4
|
||||
(call "$(lib)/allocator/arena/allocate_memory"
|
||||
(i32.add
|
||||
(i32.const 4)
|
||||
@ -2386,12 +2389,12 @@
|
||||
)
|
||||
)
|
||||
(i32.store
|
||||
(get_local $7)
|
||||
(get_local $4)
|
||||
(get_local $6)
|
||||
)
|
||||
(call "$(lib)/memory/move_memory"
|
||||
(i32.add
|
||||
(get_local $7)
|
||||
(get_local $4)
|
||||
(i32.const 4)
|
||||
)
|
||||
(i32.add
|
||||
@ -2404,7 +2407,32 @@
|
||||
(get_local $6)
|
||||
)
|
||||
(return
|
||||
(get_local $7)
|
||||
(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)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(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
@ -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
Loading…
x
Reference in New Issue
Block a user