Static operator overloads

This commit is contained in:
dcodeIO 2018-01-28 06:18:27 +01:00
parent 3165f4337f
commit b1e7b75ad7
16 changed files with 379 additions and 149 deletions

19
NOTICE
View File

@ -1,4 +1,13 @@
Includes parts of TypeScript: Copyright (c) 2017-2018 AssemblyScript authors.
The following authors have all licensed their contributions to AssemblyScript
under the licensing terms detailed in LICENSE.
* Daniel Wirtz <dcode@dcode.io>
================================================================================
This program includes parts of TypeScript:
https://github.com/Microsoft/TypeScript https://github.com/Microsoft/TypeScript
@ -6,7 +15,9 @@ Includes parts of TypeScript:
Apache License, Version 2.0 Apache License, Version 2.0
https://www.apache.org/licenses/LICENSE-2.0 https://www.apache.org/licenses/LICENSE-2.0
Includes parts of Binaryen: ================================================================================
This program includes parts of Binaryen:
https://github.com/WebAssembly/binaryen https://github.com/WebAssembly/binaryen
@ -14,7 +25,9 @@ Includes parts of Binaryen:
Apache License, Version 2.0 Apache License, Version 2.0
https://www.apache.org/licenses/LICENSE-2.0 https://www.apache.org/licenses/LICENSE-2.0
Includes parts of musl: ================================================================================
This program includes parts of musl:
http://www.musl-libc.org http://www.musl-libc.org

View File

@ -1,18 +1,19 @@
// code below is generated from diagnosticsMessages.json by scripts/build-diagnostics // code below is generated from diagnosticsMessages.json by scripts/build-diagnostics
export enum DiagnosticCode { export enum DiagnosticCode {
Conversion_from_type_0_to_1_possibly_loses_information_and_thus_requires_an_explicit_cast = 100, Operation_not_supported = 100,
Basic_type_0_cannot_be_nullable = 101, Operation_is_unsafe = 101,
Operation_not_supported = 102, Conversion_from_type_0_to_1_possibly_loses_information_and_thus_requires_an_explicit_cast = 200,
Operation_is_unsafe = 103, Conversion_from_type_0_to_1_will_require_an_explicit_cast_when_switching_between_32_64_bit = 201,
Cannot_export_a_mutable_global = 104, Type_0_cannot_be_changed_to_type_1 = 202,
Compiling_constant_with_non_constant_initializer_as_mutable = 105, Type_0_cannot_be_reinterpreted_as_type_1 = 203,
Type_0_cannot_be_changed_to_type_1 = 106, Basic_type_0_cannot_be_nullable = 204,
Structs_cannot_extend_classes_and_vice_versa = 107, Cannot_export_a_mutable_global = 205,
Structs_cannot_implement_interfaces = 108, Compiling_constant_with_non_constant_initializer_as_mutable = 206,
Invalid_regular_expression_flags = 109, Structs_cannot_extend_classes_and_vice_versa = 207,
Type_0_cannot_be_reinterpreted_as_type_1 = 110, Structs_cannot_implement_interfaces = 208,
Implementation_0_must_match_the_signature_1 = 111, Invalid_regular_expression_flags = 209,
Implementation_0_must_match_the_signature_1 = 210,
Unterminated_string_literal = 1002, Unterminated_string_literal = 1002,
Identifier_expected = 1003, Identifier_expected = 1003,
_0_expected = 1005, _0_expected = 1005,
@ -94,18 +95,19 @@ export enum DiagnosticCode {
export function diagnosticCodeToString(code: DiagnosticCode): string { export function diagnosticCodeToString(code: DiagnosticCode): string {
switch (code) { switch (code) {
case 100: return "Conversion from type '{0}' to '{1}' possibly loses information and thus requires an explicit cast."; case 100: return "Operation not supported.";
case 101: return "Basic type '{0}' cannot be nullable."; case 101: return "Operation is unsafe.";
case 102: return "Operation not supported."; case 200: return "Conversion from type '{0}' to '{1}' possibly loses information and thus requires an explicit cast.";
case 103: return "Operation is unsafe."; case 201: return "Conversion from type '{0}' to '{1}' will require an explicit cast when switching between 32/64-bit.";
case 104: return "Cannot export a mutable global."; case 202: return "Type '{0}' cannot be changed to type '{1}'.";
case 105: return "Compiling constant with non-constant initializer as mutable."; case 203: return "Type '{0}' cannot be reinterpreted as type '{1}'.";
case 106: return "Type '{0}' cannot be changed to type '{1}'."; case 204: return "Basic type '{0}' cannot be nullable.";
case 107: return "Structs cannot extend classes and vice-versa."; case 205: return "Cannot export a mutable global.";
case 108: return "Structs cannot implement interfaces."; case 206: return "Compiling constant with non-constant initializer as mutable.";
case 109: return "Invalid regular expression flags."; case 207: return "Structs cannot extend classes and vice-versa.";
case 110: return "Type '{0}' cannot be reinterpreted as type '{1}'."; case 208: return "Structs cannot implement interfaces.";
case 111: return "Implementation '{0}' must match the signature '{1}'."; case 209: return "Invalid regular expression flags.";
case 210: return "Implementation '{0}' must match the signature '{1}'.";
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

@ -1,16 +1,17 @@
{ {
"Conversion from type '{0}' to '{1}' possibly loses information and thus requires an explicit cast.": 100, "Operation not supported.": 100,
"Basic type '{0}' cannot be nullable.": 101, "Operation is unsafe.": 101,
"Operation not supported.": 102, "Conversion from type '{0}' to '{1}' possibly loses information and thus requires an explicit cast.": 200,
"Operation is unsafe.": 103, "Conversion from type '{0}' to '{1}' will require an explicit cast when switching between 32/64-bit.": 201,
"Cannot export a mutable global.": 104, "Type '{0}' cannot be changed to type '{1}'.": 202,
"Compiling constant with non-constant initializer as mutable.": 105, "Type '{0}' cannot be reinterpreted as type '{1}'.": 203,
"Type '{0}' cannot be changed to type '{1}'.": 106, "Basic type '{0}' cannot be nullable.": 204,
"Structs cannot extend classes and vice-versa.": 107, "Cannot export a mutable global.": 205,
"Structs cannot implement interfaces.": 108, "Compiling constant with non-constant initializer as mutable.": 206,
"Invalid regular expression flags.": 109, "Structs cannot extend classes and vice-versa.": 207,
"Type '{0}' cannot be reinterpreted as type '{1}'.": 110, "Structs cannot implement interfaces.": 208,
"Implementation '{0}' must match the signature '{1}'.": 111, "Invalid regular expression flags.": 209,
"Implementation '{0}' must match the signature '{1}'.": 210,
"Unterminated string literal.": 1002, "Unterminated string literal.": 1002,
"Identifier expected.": 1003, "Identifier expected.": 1003,

View File

@ -107,7 +107,7 @@ export function formatDiagnosticMessage(message: DiagnosticMessage, useColors: b
if (useColors) sb.push(diagnosticCategoryToColor(message.category)); if (useColors) sb.push(diagnosticCategoryToColor(message.category));
sb.push(diagnosticCategoryToString(message.category)); sb.push(diagnosticCategoryToString(message.category));
if (useColors) sb.push(colorReset); if (useColors) sb.push(colorReset);
sb.push(" AS"); sb.push(message.code < 1000 ? " AS" : " TS");
sb.push(message.code.toString(10)); sb.push(message.code.toString(10));
sb.push(": "); sb.push(": ");
sb.push(message.message); sb.push(message.message);

View File

@ -402,7 +402,7 @@ export class Program extends DiagnosticEmitter {
private initializeMethod(declaration: MethodDeclaration, classPrototype: ClassPrototype): void { private initializeMethod(declaration: MethodDeclaration, classPrototype: ClassPrototype): void {
var name = declaration.name.name; var name = declaration.name.name;
var internalName = declaration.fileLevelInternalName; var internalName = declaration.fileLevelInternalName;
var instancePrototype: FunctionPrototype | null = null; var prototype: FunctionPrototype | null = null;
// static methods become global functions // static methods become global functions
if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) { if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) {
@ -419,9 +419,9 @@ export class Program extends DiagnosticEmitter {
} }
} else } else
classPrototype.members = new Map(); classPrototype.members = new Map();
var staticPrototype = new FunctionPrototype(this, name, internalName, declaration, null); prototype = new FunctionPrototype(this, name, internalName, declaration, null);
classPrototype.members.set(name, staticPrototype); classPrototype.members.set(name, prototype);
this.elements.set(internalName, staticPrototype); this.elements.set(internalName, prototype);
// instance methods are remembered until resolved // instance methods are remembered until resolved
} else { } else {
@ -432,26 +432,31 @@ export class Program extends DiagnosticEmitter {
} }
} else } else
classPrototype.instanceMembers = new Map(); classPrototype.instanceMembers = new Map();
instancePrototype = new FunctionPrototype(this, name, internalName, declaration, classPrototype); prototype = new FunctionPrototype(this, name, internalName, declaration, classPrototype);
// if (classPrototype.isUnmanaged && instancePrototype.isAbstract) { // if (classPrototype.isUnmanaged && instancePrototype.isAbstract) {
// this.error( Unmanaged classes cannot declare abstract methods. ); // this.error( Unmanaged classes cannot declare abstract methods. );
// } // }
classPrototype.instanceMembers.set(name, instancePrototype); classPrototype.instanceMembers.set(name, prototype);
if (declaration.name.kind == NodeKind.CONSTRUCTOR) { if (declaration.name.kind == NodeKind.CONSTRUCTOR) {
if (classPrototype.constructorPrototype) if (classPrototype.constructorPrototype)
this.error(DiagnosticCode.Multiple_constructor_implementations_are_not_allowed, declaration.name.range); this.error(DiagnosticCode.Multiple_constructor_implementations_are_not_allowed, declaration.name.range);
else else
classPrototype.constructorPrototype = instancePrototype; classPrototype.constructorPrototype = prototype;
} }
} }
// handle operator annotations. operators are instance methods taking a second argument of the this.checkOperators(declaration.decorators, prototype, classPrototype);
// instance's type. return values vary depending on the operation. }
if (declaration.decorators) {
for (var i = 0, k = declaration.decorators.length; i < k; ++i) { private checkOperators(decorators: Decorator[] | null, prototype: FunctionPrototype, classPrototype: ClassPrototype) {
var decorator = declaration.decorators[i]; // handle operator annotations. operators are either instance methods taking a second argument of the
// instance's type or static methods taking two arguments of the instance's type. return values vary
// depending on the operation.
if (decorators) {
for (var i = 0, k = decorators.length; i < k; ++i) {
var decorator = decorators[i];
if (decorator.decoratorKind == DecoratorKind.OPERATOR) { if (decorator.decoratorKind == DecoratorKind.OPERATOR) {
if (!instancePrototype) { if (!prototype) {
this.error(DiagnosticCode.Operation_not_supported, decorator.range); this.error(DiagnosticCode.Operation_not_supported, decorator.range);
continue; continue;
} }
@ -462,22 +467,22 @@ export class Program extends DiagnosticEmitter {
switch ((<StringLiteralExpression>firstArg).value) { switch ((<StringLiteralExpression>firstArg).value) {
case "[]": case "[]":
classPrototype.fnIndexedGet = instancePrototype.simpleName; classPrototype.fnIndexedGet = prototype.simpleName;
break; break;
case "[]=": case "[]=":
classPrototype.fnIndexedSet = instancePrototype.simpleName; classPrototype.fnIndexedSet = prototype.simpleName;
break; break;
case "+": case "+":
classPrototype.fnConcat = instancePrototype.simpleName; classPrototype.fnConcat = prototype.simpleName;
break; break;
case "==": case "==":
classPrototype.fnEquals = instancePrototype.simpleName; classPrototype.fnEquals = prototype.simpleName;
break; break;
default: // TBD: does it make sense to provide more, even though not JS/TS-compatible? default:
this.error(DiagnosticCode.Operation_not_supported, firstArg.range); this.error(DiagnosticCode.Operation_not_supported, firstArg.range);
} }
} else } else

View File

@ -278,6 +278,10 @@ export class Range {
start: i32; start: i32;
end: i32; end: i32;
// TODO: set these while tokenizing
// line: i32;
// column: i32;
constructor(source: Source, start: i32, end: i32) { constructor(source: Source, start: i32, end: i32) {
this.source = source; this.source = source;
this.start = start; this.start = start;

View File

@ -19,6 +19,8 @@ export class Set<T> {
// FIXME: not a proper set implementation, just a filler // FIXME: not a proper set implementation, just a filler
has(value: T): bool { has(value: T): bool {
assert(this != null);
for (var index: usize = 0, limit: usize = this.__size; index < limit; ++index) for (var index: usize = 0, limit: usize = this.__size; index < limit; ++index)
if (load<T>(this.__memory + index * sizeof<T>()) == value) if (load<T>(this.__memory + index * sizeof<T>()) == value)
return true; return true;
@ -26,6 +28,8 @@ export class Set<T> {
} }
add(value: T): Set<T> { add(value: T): Set<T> {
assert(this != null);
if (this.__size >= this.__capacity) { if (this.__size >= this.__capacity) {
var newCapacity = max(this.__capacity << 1, 8); var newCapacity = max(this.__capacity << 1, 8);
var newMemory = allocate_memory(<usize>newCapacity * sizeof<T>()); var newMemory = allocate_memory(<usize>newCapacity * sizeof<T>());
@ -42,6 +46,8 @@ export class Set<T> {
} }
delete(value: T): bool { delete(value: T): bool {
assert(this != null);
for (var index: usize = 0, limit: usize = this.__size; index < limit; ++index) for (var index: usize = 0, limit: usize = this.__size; index < limit; ++index)
if (load<T>(this.__memory + index * sizeof<T>()) == value) { if (load<T>(this.__memory + index * sizeof<T>()) == value) {
if (index + 1 < this.__size) if (index + 1 < this.__size)
@ -53,6 +59,8 @@ export class Set<T> {
} }
clear(): void { clear(): void {
assert(this != null);
this.__size = 0; this.__size = 0;
} }

View File

@ -1,10 +1,12 @@
// singleton empty string
const EMPTY: String = changetype<String>(""); const EMPTY: String = changetype<String>("");
// number of bytes preceeding string data
const HEAD: usize = 4; const HEAD: usize = 4;
function allocate(length: i32): String { function allocate(length: i32): String {
assert(<u32>length >= 1); assert(length > 0); // 0 -> EMPTY
var ptr = allocate_memory(HEAD + length * 2); var ptr = allocate_memory(HEAD + (<usize>length << 1));
store<i32>(ptr, length); store<i32>(ptr, length);
return changetype<String>(ptr); return changetype<String>(ptr);
} }
@ -15,45 +17,75 @@ export class String {
@operator("[]") @operator("[]")
charAt(pos: i32): String { charAt(pos: i32): String {
assert(this != null);
if (<u32>pos >= this.length) if (<u32>pos >= this.length)
return EMPTY; return EMPTY;
var out = allocate(1); var out = allocate(1);
store<u16>( store<u16>(
changetype<usize>(out), changetype<usize>(out),
load<u16>(changetype<usize>(this) + (<usize>pos << 1), HEAD), load<u16>(
changetype<usize>(this) + (<usize>pos << 1),
HEAD
),
HEAD HEAD
); );
return out; return out;
} }
charCodeAt(pos: i32): i32 { charCodeAt(pos: i32): i32 {
assert(this != null);
if (<u32>pos >= this.length) if (<u32>pos >= this.length)
return -1; // NaN return -1; // (NaN)
return load<u16>(changetype<usize>(this) + (<usize>pos << 1), HEAD);
return load<u16>(
changetype<usize>(this) + (<usize>pos << 1),
HEAD
);
} }
codePointAt(pos: i32): i32 { codePointAt(pos: i32): i32 {
assert(this != null);
if (<u32>pos >= this.length) if (<u32>pos >= this.length)
return -1; // undefined return -1; // (undefined)
var first = <i32>load<u16>(changetype<usize>(this) + (<usize>pos << 1), HEAD); var first = <i32>load<u16>(
changetype<usize>(this) + (<usize>pos << 1),
HEAD
);
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>(changetype<usize>(this) + ((<usize>pos + 1) << 1), HEAD); var second = <i32>load<u16>(
changetype<usize>(this) + ((<usize>pos + 1) << 1),
HEAD
);
if (second < 0xDC00 || second > 0xDFFF) if (second < 0xDC00 || second > 0xDFFF)
return first; return first;
return ((first - 0xD800) << 10) + (second - 0xDC00) + 0x10000; return ((first - 0xD800) << 10) + (second - 0xDC00) + 0x10000;
} }
@operator("+") @operator("+")
private static __concat(left: String, right: String): String {
if (left == null)
left = changetype<String>("null");
return left.concat(right);
}
concat(other: String): String { concat(other: String): String {
assert(this != null); assert(this != null);
assert(other != null);
if (other == 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 len: usize = thisLen + otherLen; var outLen: usize = thisLen + otherLen;
if (len == 0) if (outLen == 0)
return EMPTY; return EMPTY;
var out = allocate(len);
var out = allocate(outLen);
move_memory( move_memory(
changetype<usize>(out) + HEAD, changetype<usize>(out) + HEAD,
changetype<usize>(this) + HEAD, changetype<usize>(this) + HEAD,
@ -68,12 +100,17 @@ export class String {
} }
endsWith(searchString: String, endPosition: i32 = 0x7fffffff): bool { endsWith(searchString: String, endPosition: i32 = 0x7fffffff): bool {
assert(searchString != null); assert(this != null);
var end: isize = <isize>min<i32>(max<i32>(endPosition, 0), this.length);
if (searchString == null)
return false;
var end: isize = <isize>min(max(endPosition, 0), this.length);
var searchLength: isize = searchString.length; var searchLength: isize = searchString.length;
var start: isize = end - searchLength; var start: isize = end - searchLength;
if (start < 0) if (start < 0)
return false; return false;
return !compare_memory( return !compare_memory(
changetype<usize>(this) + HEAD + (start << 1), changetype<usize>(this) + HEAD + (start << 1),
changetype<usize>(searchString) + HEAD, changetype<usize>(searchString) + HEAD,
@ -82,17 +119,20 @@ export class String {
} }
@operator("==") @operator("==")
private __eq(other: String): bool { private static __eq(left: String, right: String): bool {
if (this == null) if (left == null)
return other == null; return right == null;
else if (other == null) else if (right == null)
return false; return false;
if (this.length != other.length)
var leftLength = left.length;
if (leftLength != right.length)
return false; return false;
return !compare_memory( return !compare_memory(
changetype<usize>(this) + HEAD, changetype<usize>(left) + HEAD,
changetype<usize>(other) + HEAD, changetype<usize>(right) + HEAD,
<usize>(this.length << 1) (<usize>leftLength << 1)
); );
} }
@ -101,11 +141,17 @@ export class String {
} }
indexOf(searchString: String, position: i32 = 0): i32 { indexOf(searchString: String, position: i32 = 0): i32 {
assert(searchString != null); assert(this != null);
if (searchString == null)
searchString = changetype<String>("null");
var pos: isize = position; var pos: isize = position;
var len: isize = this.length; var len: isize = this.length;
var start: isize = min<isize>(max<isize>(pos, 0), len); var start: isize = min<isize>(max<isize>(pos, 0), len);
var searchLen: isize = searchString.length; var searchLen: isize = <isize>searchString.length;
// TODO: two-way, multiple char codes
for (var k: usize = start; <isize>k + searchLen <= len; ++k) for (var k: usize = start; <isize>k + searchLen <= len; ++k)
if (!compare_memory( if (!compare_memory(
changetype<usize>(this) + HEAD + (k << 1), changetype<usize>(this) + HEAD + (k << 1),
@ -118,13 +164,17 @@ export class String {
startsWith(searchString: String, position: i32 = 0): bool { startsWith(searchString: String, position: i32 = 0): bool {
assert(this != null); assert(this != null);
assert(searchString != null);
if (searchString == null)
searchString = changetype<String>("null");
var pos: isize = position; var pos: isize = position;
var len: isize = this.length; var len: isize = this.length;
var start: isize = min<isize>(max<isize>(position, 0), len); var start: isize = min<isize>(max<isize>(position, 0), len);
var searchLength: isize = searchString.length; var searchLength: isize = <isize>searchString.length;
if (searchLength + start > len) if (searchLength + start > len)
return false; return false;
return !compare_memory( return !compare_memory(
changetype<usize>(this) + HEAD + (start << 1), changetype<usize>(this) + HEAD + (start << 1),
changetype<usize>(searchString) + HEAD, changetype<usize>(searchString) + HEAD,
@ -134,14 +184,17 @@ export class String {
substr(start: i32, length: i32 = i32.MAX_VALUE): String { substr(start: i32, length: i32 = i32.MAX_VALUE): String {
assert(this != null); assert(this != null);
var intStart: isize = start; var intStart: isize = start;
var end: isize = length; var end: isize = length;
var size: isize = this.length; var size: isize = this.length;
if (intStart < 0) if (intStart < 0)
intStart = max<isize>(size + intStart, 0); intStart = max<isize>(size + intStart, 0);
var resultLength: isize = min<isize>(max<isize>(end, 0), size - intStart); var resultLength: isize = min<isize>(max<isize>(end, 0), size - intStart);
if (resultLength <= 0) if (resultLength <= 0)
return EMPTY; return EMPTY;
var out = allocate(resultLength); var out = allocate(resultLength);
move_memory( move_memory(
changetype<usize>(out) + HEAD, changetype<usize>(out) + HEAD,
@ -153,6 +206,7 @@ export class String {
substring(start: i32, end: i32 = i32.MAX_VALUE): String { substring(start: i32, end: i32 = i32.MAX_VALUE): String {
assert(this != null); assert(this != null);
var len = this.length; var len = this.length;
var finalStart = min<i32>(max<i32>(start, 0), len); var finalStart = min<i32>(max<i32>(start, 0), len);
var finalEnd = min<i32>(max<i32>(end, 0), len); var finalEnd = min<i32>(max<i32>(end, 0), len);
@ -161,8 +215,10 @@ export class String {
len = to - from; len = to - from;
if (!len) if (!len)
return EMPTY; return EMPTY;
if (!from && to == this.length) if (!from && to == this.length)
return this; return this;
var out = allocate(len); var out = allocate(len);
move_memory( move_memory(
changetype<usize>(out) + HEAD, changetype<usize>(out) + HEAD,
@ -174,17 +230,21 @@ export class String {
trim(): String { trim(): String {
assert(this != null); assert(this != null);
var length: usize = this.length; var length: usize = this.length;
while (length && isWhiteSpaceOrLineTerminator(load<u16>(changetype<usize>(this) + (length << 1), HEAD))) while (length && isWhiteSpaceOrLineTerminator(load<u16>(changetype<usize>(this) + (length << 1), HEAD)))
--length; --length;
var start: usize = 0; var start: usize = 0;
while (start < length && isWhiteSpaceOrLineTerminator(load<u16>(changetype<usize>(this) + (start << 1), HEAD))) { while (start < length && isWhiteSpaceOrLineTerminator(load<u16>(changetype<usize>(this) + (start << 1), HEAD)))
++start; --length; ++start, --length;
}
if (!length) if (!length)
return EMPTY; return EMPTY;
if (!start && length == this.length) if (!start && length == this.length)
return this; return this;
var out = allocate(length); var out = allocate(length);
move_memory( move_memory(
changetype<usize>(out) + HEAD, changetype<usize>(out) + HEAD,
@ -196,15 +256,19 @@ export class String {
trimLeft(): String { trimLeft(): String {
assert(this != null); assert(this != null);
var start: isize = 0; var start: isize = 0;
var len: isize = this.length; var len: isize = this.length;
while (start < len && isWhiteSpaceOrLineTerminator(load<u16>(changetype<usize>(this) + (start << 1), HEAD))) while (start < len && isWhiteSpaceOrLineTerminator(load<u16>(changetype<usize>(this) + (start << 1), HEAD)))
++start; ++start;
if (!start) if (!start)
return this; return this;
var outLen = len - start; var outLen = len - start;
if (!outLen) if (!outLen)
return EMPTY; return EMPTY;
var out = allocate(outLen); var out = allocate(outLen);
move_memory( move_memory(
changetype<usize>(out) + HEAD, changetype<usize>(out) + HEAD,
@ -216,13 +280,17 @@ export class String {
trimRight(): String { trimRight(): String {
assert(this != null); assert(this != null);
var len: isize = this.length; var len: isize = this.length;
while (len > 0 && isWhiteSpaceOrLineTerminator(load<u16>(changetype<usize>(this) + (len << 1), HEAD))) while (len > 0 && isWhiteSpaceOrLineTerminator(load<u16>(changetype<usize>(this) + (len << 1), HEAD)))
--len; --len;
if (len <= 0) if (len <= 0)
return EMPTY; return EMPTY;
if (<i32>len == this.length) if (<i32>len == this.length)
return this; return this;
var out = allocate(len); var out = allocate(len);
move_memory( move_memory(
changetype<usize>(out) + HEAD, changetype<usize>(out) + HEAD,

View File

@ -4071,6 +4071,8 @@
GLOBAL: std:string/HEAD GLOBAL: std:string/HEAD
FUNCTION_PROTOTYPE: std:string/allocate FUNCTION_PROTOTYPE: std:string/allocate
CLASS_PROTOTYPE: std:string/String CLASS_PROTOTYPE: std:string/String
FUNCTION_PROTOTYPE: std:string/String.__concat
FUNCTION_PROTOTYPE: std:string/String.__eq
CLASS_PROTOTYPE: String CLASS_PROTOTYPE: String
FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator
FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: std:string/parseInt

View File

@ -284,6 +284,8 @@
GLOBAL: std:string/HEAD GLOBAL: std:string/HEAD
FUNCTION_PROTOTYPE: std:string/allocate FUNCTION_PROTOTYPE: std:string/allocate
CLASS_PROTOTYPE: std:string/String CLASS_PROTOTYPE: std:string/String
FUNCTION_PROTOTYPE: std:string/String.__concat
FUNCTION_PROTOTYPE: std:string/String.__eq
CLASS_PROTOTYPE: String CLASS_PROTOTYPE: String
FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator
FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: std:string/parseInt

View File

@ -2867,6 +2867,8 @@
GLOBAL: std:string/HEAD GLOBAL: std:string/HEAD
FUNCTION_PROTOTYPE: std:string/allocate FUNCTION_PROTOTYPE: std:string/allocate
CLASS_PROTOTYPE: std:string/String CLASS_PROTOTYPE: std:string/String
FUNCTION_PROTOTYPE: std:string/String.__concat
FUNCTION_PROTOTYPE: std:string/String.__eq
CLASS_PROTOTYPE: String CLASS_PROTOTYPE: String
FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator
FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: std:string/parseInt

View File

@ -1972,6 +1972,12 @@
(func $std:set/Set#add (; 4 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $std:set/Set#add (; 4 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32) (local $2 i32)
(local $3 i32) (local $3 i32)
(if
(i32.eqz
(get_local $0)
)
(unreachable)
)
(if (if
(i32.ge_u (i32.ge_u
(i32.load offset=8 (i32.load offset=8
@ -2068,6 +2074,12 @@
(func $std:set/Set#has (; 5 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $std:set/Set#has (; 5 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32) (local $2 i32)
(local $3 i32) (local $3 i32)
(if
(i32.eqz
(get_local $0)
)
(unreachable)
)
(set_local $3 (set_local $3
(i32.load offset=8 (i32.load offset=8
(get_local $0) (get_local $0)
@ -2114,6 +2126,12 @@
(func $std:set/Set#delete (; 6 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $std:set/Set#delete (; 6 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32) (local $2 i32)
(local $3 i32) (local $3 i32)
(if
(i32.eqz
(get_local $0)
)
(unreachable)
)
(set_local $3 (set_local $3
(i32.load offset=8 (i32.load offset=8
(get_local $0) (get_local $0)
@ -2212,6 +2230,7 @@
(i32.const 0) (i32.const 0)
) )
(func $start (; 7 ;) (type $v) (func $start (; 7 ;) (type $v)
(local $0 i32)
(set_global $std:heap/HEAP_OFFSET (set_global $std:heap/HEAP_OFFSET
(get_global $HEAP_BASE) (get_global $HEAP_BASE)
) )
@ -2327,8 +2346,16 @@
) )
(unreachable) (unreachable)
) )
(if
(i32.eqz
(tee_local $0
(get_global $std/set/set)
)
)
(unreachable)
)
(i32.store offset=8 (i32.store offset=8
(get_global $std/set/set) (get_local $0)
(i32.const 0) (i32.const 0)
) )
(if (if

View File

@ -2247,6 +2247,15 @@
(local $3 i32) (local $3 i32)
(local $4 i32) (local $4 i32)
(local $5 i32) (local $5 i32)
(if
(i32.eqz
(i32.ne
(get_local $0)
(i32.const 0)
)
)
(unreachable)
)
(if (if
(i32.ge_u (i32.ge_u
(i32.load offset=8 (i32.load offset=8
@ -2348,6 +2357,15 @@
(func $std:set/Set#has (; 6 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $std:set/Set#has (; 6 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32) (local $2 i32)
(local $3 i32) (local $3 i32)
(if
(i32.eqz
(i32.ne
(get_local $0)
(i32.const 0)
)
)
(unreachable)
)
(block $break|0 (block $break|0
(block (block
(set_local $2 (set_local $2
@ -2403,6 +2421,15 @@
(func $std:set/Set#delete (; 7 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $std:set/Set#delete (; 7 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(local $2 i32) (local $2 i32)
(local $3 i32) (local $3 i32)
(if
(i32.eqz
(i32.ne
(get_local $0)
(i32.const 0)
)
)
(unreachable)
)
(block $break|0 (block $break|0
(block (block
(set_local $2 (set_local $2
@ -2510,6 +2537,15 @@
) )
) )
(func $std:set/Set#clear (; 8 ;) (type $iv) (param $0 i32) (func $std:set/Set#clear (; 8 ;) (type $iv) (param $0 i32)
(if
(i32.eqz
(i32.ne
(get_local $0)
(i32.const 0)
)
)
(unreachable)
)
(i32.store offset=8 (i32.store offset=8
(get_local $0) (get_local $0)
(i32.const 0) (i32.const 0)
@ -2760,6 +2796,8 @@
GLOBAL: std:string/HEAD GLOBAL: std:string/HEAD
FUNCTION_PROTOTYPE: std:string/allocate FUNCTION_PROTOTYPE: std:string/allocate
CLASS_PROTOTYPE: std:string/String CLASS_PROTOTYPE: std:string/String
FUNCTION_PROTOTYPE: std:string/String.__concat
FUNCTION_PROTOTYPE: std:string/String.__eq
CLASS_PROTOTYPE: String CLASS_PROTOTYPE: String
FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator
FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: std:string/parseInt

View File

@ -1,19 +1,49 @@
(module (module
(type $i (func (result i32))) (type $i (func (result i32)))
(type $iii (func (param i32 i32) (result i32)))
(type $iiii (func (param i32 i32 i32) (result i32))) (type $iiii (func (param i32 i32 i32) (result i32)))
(type $v (func)) (type $v (func))
(global $std/string/str (mut i32) (i32.const 8)) (global $std/string/str (mut i32) (i32.const 8))
(memory $0 1) (memory $0 1)
(data (i32.const 8) "\10\00\00\00h\00i\00,\00 \00I\00\'\00m\00 \00a\00 \00s\00t\00r\00i\00n\00g") (data (i32.const 8) "\10\00\00\00h\00i\00,\00 \00I\00\'\00m\00 \00a\00 \00s\00t\00r\00i\00n\00g")
(data (i32.const 48) "\02\00\00\00h\00i") (data (i32.const 48) "\02\00\00\00h\00i")
(data (i32.const 56) "\06\00\00\00s\00t\00r\00i\00n\00g") (data (i32.const 56) "\04\00\00\00n\00u\00l\00l")
(data (i32.const 72) "\03\00\00\00I\00\'\00m") (data (i32.const 72) "\06\00\00\00s\00t\00r\00i\00n\00g")
(data (i32.const 88) "\01\00\00\00,") (data (i32.const 88) "\03\00\00\00I\00\'\00m")
(data (i32.const 96) "\01\00\00\00x") (data (i32.const 104) "\01\00\00\00,")
(data (i32.const 112) "\01\00\00\00x")
(export "getString" (func $std/string/getString)) (export "getString" (func $std/string/getString))
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $std:heap/compare_memory (; 0 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (func $std:string/String#charCodeAt (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(if
(i32.eqz
(get_local $0)
)
(unreachable)
)
(if
(i32.ge_u
(get_local $1)
(i32.load
(get_local $0)
)
)
(return
(i32.const -1)
)
)
(i32.load16_u offset=4
(i32.add
(get_local $0)
(i32.shl
(get_local $1)
(i32.const 1)
)
)
)
)
(func $std:heap/compare_memory (; 1 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(if (if
(i32.eq (i32.eq
(get_local $0) (get_local $0)
@ -73,7 +103,7 @@
(i32.const 0) (i32.const 0)
) )
) )
(func $std:string/String#startsWith (; 1 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (func $std:string/String#startsWith (; 2 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32) (local $3 i32)
(local $4 i32) (local $4 i32)
(local $5 i32) (local $5 i32)
@ -87,7 +117,9 @@
(i32.eqz (i32.eqz
(get_local $1) (get_local $1)
) )
(unreachable) (set_local $1
(i32.const 56)
)
) )
(if (if
(i32.gt_s (i32.gt_s
@ -152,13 +184,21 @@
) )
) )
) )
(func $std:string/String#endsWith (; 2 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (func $std:string/String#endsWith (; 3 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32) (local $3 i32)
(if
(i32.eqz
(get_local $0)
)
(unreachable)
)
(if (if
(i32.eqz (i32.eqz
(get_local $1) (get_local $1)
) )
(unreachable) (return
(i32.const 0)
)
) )
(if (if
(i32.lt_s (i32.lt_s
@ -221,16 +261,24 @@
) )
) )
) )
(func $std:string/String#indexOf (; 3 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32) (func $std:string/String#indexOf (; 4 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
(local $3 i32) (local $3 i32)
(local $4 i32) (local $4 i32)
(local $5 i32) (local $5 i32)
(if (if
(i32.eqz (i32.eqz
(get_local $1) (get_local $0)
) )
(unreachable) (unreachable)
) )
(if
(i32.eqz
(get_local $1)
)
(set_local $1
(i32.const 56)
)
)
(set_local $4 (set_local $4
(i32.load (i32.load
(get_local $1) (get_local $1)
@ -310,11 +358,10 @@
) )
(i32.const -1) (i32.const -1)
) )
(func $std/string/getString (; 4 ;) (type $i) (result i32) (func $std/string/getString (; 5 ;) (type $i) (result i32)
(get_global $std/string/str) (get_global $std/string/str)
) )
(func $start (; 5 ;) (type $v) (func $start (; 6 ;) (type $v)
(local $0 i32)
(if (if
(i32.ne (i32.ne
(get_global $std/string/str) (get_global $std/string/str)
@ -333,26 +380,9 @@
) )
(if (if
(i32.ne (i32.ne
(block $__inlined_func$std:string/String#charCodeAt (result i32) (call $std:string/String#charCodeAt
(drop (get_global $std/string/str)
(br_if $__inlined_func$std:string/String#charCodeAt (i32.const 0)
(i32.const -1)
(i32.ge_u
(i32.const 0)
(i32.load
(tee_local $0
(get_global $std/string/str)
)
)
)
)
)
(i32.load16_u offset=4
(i32.add
(get_local $0)
(i32.const 0)
)
)
) )
(i32.const 104) (i32.const 104)
) )
@ -372,7 +402,7 @@
(i32.eqz (i32.eqz
(call $std:string/String#endsWith (call $std:string/String#endsWith
(get_global $std/string/str) (get_global $std/string/str)
(i32.const 56) (i32.const 72)
(i32.const 2147483647) (i32.const 2147483647)
) )
) )
@ -382,10 +412,8 @@
(i32.eqz (i32.eqz
(i32.ne (i32.ne
(call $std:string/String#indexOf (call $std:string/String#indexOf
(tee_local $0 (get_global $std/string/str)
(get_global $std/string/str) (i32.const 88)
)
(i32.const 72)
(i32.const 0) (i32.const 0)
) )
(i32.const -1) (i32.const -1)
@ -397,7 +425,7 @@
(i32.ne (i32.ne
(call $std:string/String#indexOf (call $std:string/String#indexOf
(get_global $std/string/str) (get_global $std/string/str)
(i32.const 88) (i32.const 104)
(i32.const 0) (i32.const 0)
) )
(i32.const 2) (i32.const 2)
@ -408,7 +436,7 @@
(i32.ne (i32.ne
(call $std:string/String#indexOf (call $std:string/String#indexOf
(get_global $std/string/str) (get_global $std/string/str)
(i32.const 96) (i32.const 112)
(i32.const 0) (i32.const 0)
) )
(i32.const -1) (i32.const -1)

View File

@ -5,18 +5,28 @@
(type $v (func)) (type $v (func))
(global $std/string/str (mut i32) (i32.const 8)) (global $std/string/str (mut i32) (i32.const 8))
(global $std:string/HEAD i32 (i32.const 4)) (global $std:string/HEAD i32 (i32.const 4))
(global $HEAP_BASE i32 (i32.const 102)) (global $HEAP_BASE i32 (i32.const 118))
(memory $0 1) (memory $0 1)
(data (i32.const 8) "\10\00\00\00h\00i\00,\00 \00I\00\'\00m\00 \00a\00 \00s\00t\00r\00i\00n\00g\00") (data (i32.const 8) "\10\00\00\00h\00i\00,\00 \00I\00\'\00m\00 \00a\00 \00s\00t\00r\00i\00n\00g\00")
(data (i32.const 48) "\02\00\00\00h\00i\00") (data (i32.const 48) "\02\00\00\00h\00i\00")
(data (i32.const 56) "\06\00\00\00s\00t\00r\00i\00n\00g\00") (data (i32.const 56) "\04\00\00\00n\00u\00l\00l\00")
(data (i32.const 72) "\03\00\00\00I\00\'\00m\00") (data (i32.const 72) "\06\00\00\00s\00t\00r\00i\00n\00g\00")
(data (i32.const 88) "\01\00\00\00,\00") (data (i32.const 88) "\03\00\00\00I\00\'\00m\00")
(data (i32.const 96) "\01\00\00\00x\00") (data (i32.const 104) "\01\00\00\00,\00")
(data (i32.const 112) "\01\00\00\00x\00")
(export "getString" (func $std/string/getString)) (export "getString" (func $std/string/getString))
(export "memory" (memory $0)) (export "memory" (memory $0))
(start $start) (start $start)
(func $std:string/String#charCodeAt (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32) (func $std:string/String#charCodeAt (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
(if
(i32.eqz
(i32.ne
(get_local $0)
(i32.const 0)
)
)
(unreachable)
)
(if (if
(i32.ge_u (i32.ge_u
(get_local $1) (get_local $1)
@ -129,13 +139,13 @@
(unreachable) (unreachable)
) )
(if (if
(i32.eqz (i32.eq
(i32.ne (get_local $1)
(get_local $1) (i32.const 0)
(i32.const 0) )
) (set_local $1
(i32.const 56)
) )
(unreachable)
) )
(set_local $3 (set_local $3
(get_local $2) (get_local $2)
@ -221,12 +231,21 @@
(if (if
(i32.eqz (i32.eqz
(i32.ne (i32.ne
(get_local $1) (get_local $0)
(i32.const 0) (i32.const 0)
) )
) )
(unreachable) (unreachable)
) )
(if
(i32.eq
(get_local $1)
(i32.const 0)
)
(return
(i32.const 0)
)
)
(set_local $5 (set_local $5
(select (select
(tee_local $3 (tee_local $3
@ -310,12 +329,21 @@
(if (if
(i32.eqz (i32.eqz
(i32.ne (i32.ne
(get_local $1) (get_local $0)
(i32.const 0) (i32.const 0)
) )
) )
(unreachable) (unreachable)
) )
(if
(i32.eq
(get_local $1)
(i32.const 0)
)
(set_local $1
(i32.const 56)
)
)
(set_local $3 (set_local $3
(get_local $2) (get_local $2)
) )
@ -480,7 +508,7 @@
(i32.eqz (i32.eqz
(call $std:string/String#endsWith (call $std:string/String#endsWith
(get_global $std/string/str) (get_global $std/string/str)
(i32.const 56) (i32.const 72)
(i32.const 2147483647) (i32.const 2147483647)
) )
) )
@ -490,7 +518,7 @@
(i32.eqz (i32.eqz
(call $std:string/String#includes (call $std:string/String#includes
(get_global $std/string/str) (get_global $std/string/str)
(i32.const 72) (i32.const 88)
(i32.const 0) (i32.const 0)
) )
) )
@ -501,7 +529,7 @@
(i32.eq (i32.eq
(call $std:string/String#indexOf (call $std:string/String#indexOf
(get_global $std/string/str) (get_global $std/string/str)
(i32.const 88) (i32.const 104)
(i32.const 0) (i32.const 0)
) )
(i32.const 2) (i32.const 2)
@ -514,7 +542,7 @@
(i32.eq (i32.eq
(call $std:string/String#indexOf (call $std:string/String#indexOf
(get_global $std/string/str) (get_global $std/string/str)
(i32.const 96) (i32.const 112)
(i32.const 0) (i32.const 0)
) )
(i32.sub (i32.sub
@ -606,6 +634,8 @@
GLOBAL: std:string/HEAD GLOBAL: std:string/HEAD
FUNCTION_PROTOTYPE: std:string/allocate FUNCTION_PROTOTYPE: std:string/allocate
CLASS_PROTOTYPE: std:string/String CLASS_PROTOTYPE: std:string/String
FUNCTION_PROTOTYPE: std:string/String.__concat
FUNCTION_PROTOTYPE: std:string/String.__eq
CLASS_PROTOTYPE: String CLASS_PROTOTYPE: String
FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator FUNCTION_PROTOTYPE: std:string/isWhiteSpaceOrLineTerminator
FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: std:string/parseInt

View File

@ -8,6 +8,6 @@ b / ig;
false && /abc/gX.test(someString) || true; false && /abc/gX.test(someString) || true;
// ERROR 1161: "Unterminated regular expression literal." in regexp.ts @ 75,76 // ERROR 1161: "Unterminated regular expression literal." in regexp.ts @ 75,76
// ERROR 1005: "'/' expected." in regexp.ts @ 74,76 // ERROR 1005: "'/' expected." in regexp.ts @ 74,76
// ERROR 109: "Invalid regular expression flags." in regexp.ts @ 95,98 // ERROR 209: "Invalid regular expression flags." in regexp.ts @ 95,98
// ERROR 109: "Invalid regular expression flags." in regexp.ts @ 111,113 // ERROR 209: "Invalid regular expression flags." in regexp.ts @ 111,113
// ERROR 109: "Invalid regular expression flags." in regexp.ts @ 131,133 // ERROR 209: "Invalid regular expression flags." in regexp.ts @ 131,133