Warn on constant locals not being actual constants; Simplify changetype

This commit is contained in:
dcodeIO 2017-12-28 17:16:37 +01:00
parent 2f12c7fa50
commit 4207f6460d
14 changed files with 90 additions and 74 deletions

View File

@ -7,7 +7,7 @@ var assemblyscript;
var isDev = true; var isDev = true;
try { try {
assemblyscript = require("../dist/assemblyscript.js"); assemblyscript = require("../dist/assemblyscript.js");
require("source-map-support").install(); try { require("source-map-support").install(); } catch (e) {} // optional
isDev = false; isDev = false;
} catch (e) { } catch (e) {
require("ts-node").register({ project: require("path").join(__dirname, "..", "src") }); require("ts-node").register({ project: require("path").join(__dirname, "..", "src") });

View File

@ -13,8 +13,7 @@
"dependencies": { "dependencies": {
"binaryen": "40.0.0-nightly.20171209", "binaryen": "40.0.0-nightly.20171209",
"glob": "^7.1.2", "glob": "^7.1.2",
"minimist": "^1.2.0", "minimist": "^1.2.0"
"source-map-support": "^0.5.0"
}, },
"devDependencies": { "devDependencies": {
"@types/chalk": "^2.2.0", "@types/chalk": "^2.2.0",
@ -26,6 +25,7 @@
"chalk": "^2.3.0", "chalk": "^2.3.0",
"diff": "^3.4.0", "diff": "^3.4.0",
"long": "^3.2.0", "long": "^3.2.0",
"source-map-support": "^0.5.0",
"ts-loader": "^3.2.0", "ts-loader": "^3.2.0",
"ts-node": "^4.0.2", "ts-node": "^4.0.2",
"tslint": "^5.8.0", "tslint": "^5.8.0",
@ -42,15 +42,15 @@
}, },
"scripts": { "scripts": {
"build": "webpack", "build": "webpack",
"clean": "rm dist/assemblyscript.*", "clean": "node scripts/clean",
"lint": "tslint --project src",
"test:config": "npm run test:config:assembly --scripts-prepend-node-path && npm run test:config:portable --scripts-prepend-node-path && npm run test:config:src --scripts-prepend-node-path", "test:config": "npm run test:config:assembly --scripts-prepend-node-path && npm run test:config:portable --scripts-prepend-node-path && npm run test:config:src --scripts-prepend-node-path",
"test:config:assembly": "tsc --noEmit -p std/assembly --diagnostics --listFiles", "test:config:assembly": "tsc --noEmit -p std/assembly --diagnostics --listFiles",
"test:config:portable": "tsc --noEmit -p std/portable --diagnostics --listFiles", "test:config:portable": "tsc --noEmit -p std/portable --diagnostics --listFiles",
"test:config:src": "tsc --noEmit -p src --diagnostics --listFiles", "test:config:src": "tsc --noEmit -p src --diagnostics --listFiles",
"test:parser": "node tests/parser", "test:parser": "node tests/parser",
"test:compiler": "node tests/compiler", "test:compiler": "node tests/compiler",
"test": "npm run test:config --scripts-prepend-node-path && npm run test:parser --scripts-prepend-node-path && npm run test:compiler --scripts-prepend-node-path", "test": "npm run test:config --scripts-prepend-node-path && npm run test:parser --scripts-prepend-node-path && npm run test:compiler --scripts-prepend-node-path"
"lint": "tslint --project src"
}, },
"files": [ "files": [
"bin/", "bin/",

16
scripts/clean.js Normal file
View File

@ -0,0 +1,16 @@
var fs = require("fs");
var glob = require("glob");
glob("*", { cwd: __dirname + "/../dist" }, (err, matches) => {
if (err)
console.log("Failed to list files in 'dist/': " + err.message);
else
matches.forEach(match => {
fs.unlink(__dirname + "/../dist/" + match, err => {
if (err)
console.log("Failed to delete 'dist/" + match + "': " + err.message);
else
console.log("Deleted 'dist/" + match + "'");
});
});
});

View File

@ -2185,15 +2185,14 @@ function builderEndsWith(sb: string[], code: CharCode): bool {
export function escapeString(str: string): string { export function escapeString(str: string): string {
var k = str.length; var k = str.length;
var ret = new Array<string>(k); var ret = new Array<string>(k);
ret.length = 0;
for (var i = 0, c: string; i < k; ++i) { for (var i = 0, c: string; i < k; ++i) {
switch (c = str.charAt(i)) { switch (c = str.charAt(i)) {
case "\\": ret.push("\\\\"); break; case "\\": ret[i] = "\\\\"; break;
case "\"": ret.push("\\\""); break; case "\"": ret[i] = "\\\""; break;
case "\r": ret.push("\\r"); break; case "\r": ret[i] = "\\r"; break;
case "\n": ret.push("\\n"); break; case "\n": ret[i] = "\\n"; break;
case "\0": ret.push("\\0"); break; case "\0": ret[i] = "\\0"; break;
default: ret.push(c); default: ret[i] = c;
} }
} }
return "\"" + ret.join("") + "\""; return "\"" + ret.join("") + "\"";

View File

@ -689,11 +689,11 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
// other // other
case "changetype": // changetype<T1,T2>(value: T1) -> T2 case "changetype": // changetype<T>(value: *) -> T
if (!validateCall(compiler, typeArguments, 2, operands, 1, reportNode)) if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return module.createUnreachable(); return module.createUnreachable();
if ((typeArguments[0] == usizeType && typeArguments[1].classType) || (typeArguments[0].classType && typeArguments[1] == usizeType)) { arg0 = compiler.compileExpression(operands[0], Type.void, ConversionKind.NONE);
arg0 = compiler.compileExpression(operands[0], typeArguments[0]); if ((compiler.currentType == usizeType && typeArguments[1].classType) || (compiler.currentType.classType && typeArguments[1] == usizeType)) {
compiler.currentType = typeArguments[1]; compiler.currentType = typeArguments[1];
return arg0; return arg0;
} }

View File

@ -386,7 +386,7 @@ export class Compiler extends DiagnosticEmitter {
if (!global.isMutable) { if (!global.isMutable) {
initExpr = this.precomputeExpressionRef(initExpr); initExpr = this.precomputeExpressionRef(initExpr);
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range); this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, declaration.range);
initializeInStart = true; initializeInStart = true;
} }
} else } else
@ -461,7 +461,7 @@ export class Compiler extends DiagnosticEmitter {
initExpr = this.precomputeExpressionRef(initExpr); initExpr = this.precomputeExpressionRef(initExpr);
if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) { if (_BinaryenExpressionGetId(initExpr) != ExpressionId.Const) {
if (element.isConstant) if (element.isConstant)
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range); this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, declaration.range);
initInStart = true; initInStart = true;
} }
} }
@ -476,7 +476,7 @@ export class Compiler extends DiagnosticEmitter {
this.module.createI32(1) this.module.createI32(1)
); );
if (element.isConstant) if (element.isConstant)
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range); this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, declaration.range);
initInStart = true; initInStart = true;
} }
if (initInStart) { if (initInStart) {
@ -1029,7 +1029,8 @@ export class Compiler extends DiagnosticEmitter {
} }
this.currentFunction.locals.set(name, local); this.currentFunction.locals.set(name, local);
continue; continue;
} } else
this.warning(DiagnosticCode.Compiling_constant_with_non_constant_initializer_as_mutable, declaration.range);
} else { } else {
this.error(DiagnosticCode._const_declarations_must_be_initialized, declaration.range); this.error(DiagnosticCode._const_declarations_must_be_initialized, declaration.range);
} }

View File

@ -6,7 +6,7 @@ export enum DiagnosticCode {
Operation_not_supported = 102, Operation_not_supported = 102,
Operation_is_unsafe = 103, Operation_is_unsafe = 103,
Cannot_export_a_mutable_global = 104, Cannot_export_a_mutable_global = 104,
Compiling_constant_global_with_non_constant_initializer_as_mutable = 105, Compiling_constant_with_non_constant_initializer_as_mutable = 105,
Type_0_cannot_be_changed_to_type_1 = 106, Type_0_cannot_be_changed_to_type_1 = 106,
Unterminated_string_literal = 1002, Unterminated_string_literal = 1002,
Identifier_expected = 1003, Identifier_expected = 1003,
@ -87,7 +87,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 102: return "Operation not supported."; case 102: return "Operation not supported.";
case 103: return "Operation is unsafe."; case 103: return "Operation is unsafe.";
case 104: return "Cannot export a mutable global."; case 104: return "Cannot export a mutable global.";
case 105: return "Compiling constant global with non-constant initializer as mutable."; case 105: return "Compiling constant with non-constant initializer as mutable.";
case 106: return "Type '{0}' cannot be changed to type '{1}'."; case 106: return "Type '{0}' cannot be changed to type '{1}'.";
case 1002: return "Unterminated string literal."; case 1002: return "Unterminated string literal.";
case 1003: return "Identifier expected."; case 1003: return "Identifier expected.";

View File

@ -4,7 +4,7 @@
"Operation not supported.": 102, "Operation not supported.": 102,
"Operation is unsafe.": 103, "Operation is unsafe.": 103,
"Cannot export a mutable global.": 104, "Cannot export a mutable global.": 104,
"Compiling constant global with non-constant initializer as mutable.": 105, "Compiling constant with non-constant initializer as mutable.": 105,
"Type '{0}' cannot be changed to type '{1}'.": 106, "Type '{0}' cannot be changed to type '{1}'.": 106,
"Unterminated string literal.": 1002, "Unterminated string literal.": 1002,

View File

@ -264,7 +264,7 @@ export class Module {
static create(): Module { static create(): Module {
var module = new Module(); var module = new Module();
module.ref = _BinaryenModuleCreate(); module.ref = _BinaryenModuleCreate();
module.lit = changetype<usize,BinaryenLiteral>(Heap.allocate(16)); module.lit = changetype<BinaryenLiteral>(Heap.allocate(16));
module.noEmit = false; module.noEmit = false;
return module; return module;
} }
@ -274,18 +274,18 @@ export class Module {
try { try {
var module = new Module(); var module = new Module();
module.ref = _BinaryenModuleRead(cArr, buffer.length); module.ref = _BinaryenModuleRead(cArr, buffer.length);
module.lit = changetype<usize,BinaryenLiteral>(Heap.allocate(16)); module.lit = changetype<BinaryenLiteral>(Heap.allocate(16));
module.noEmit = false; module.noEmit = false;
return module; return module;
} finally { } finally {
Heap.dispose(changetype<usize,usize>(cArr)); Heap.dispose(changetype<usize>(cArr));
} }
} }
static createStub(): Module { static createStub(): Module {
var module = new Module(); var module = new Module();
module.ref = 0; module.ref = 0;
module.lit = changetype<usize,BinaryenLiteral>(0); module.lit = changetype<BinaryenLiteral>(0);
module.noEmit = true; module.noEmit = true;
return module; return module;
} }
@ -806,7 +806,7 @@ export class Module {
dispose(): void { dispose(): void {
if (!this.ref) return; // sic if (!this.ref) return; // sic
_BinaryenModuleDispose(this.ref); _BinaryenModuleDispose(this.ref);
Heap.dispose(changetype<BinaryenLiteral, usize>(this.lit)); Heap.dispose(changetype<usize>(this.lit));
} }
createRelooper(): Relooper { createRelooper(): Relooper {

2
std/assembly.d.ts vendored
View File

@ -162,7 +162,7 @@ declare const HEAP_BASE: usize;
/** Determines the byte size of the specified core or class type. Compiles to a constant. */ /** Determines the byte size of the specified core or class type. Compiles to a constant. */
declare function sizeof<T>(): usize; declare function sizeof<T>(): usize;
/** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */ /** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */
declare function changetype<T1,T2>(value: T1): T2; declare function changetype<T>(value: any): T;
/** Tests if a 32-bit or 64-bit float is `NaN`. */ /** Tests if a 32-bit or 64-bit float is `NaN`. */
declare function isNaN<T = f32 | f64>(value: T): bool; declare function isNaN<T = f32 | f64>(value: T): bool;
/** Tests if a 32-bit or 64-bit float is finite, that is not `NaN` or +/-`Infinity`. */ /** Tests if a 32-bit or 64-bit float is finite, that is not `NaN` or +/-`Infinity`. */

View File

@ -18,10 +18,10 @@ export class Array<T> {
} }
dispose(): void { dispose(): void {
store<i64>(changetype<this,usize>(this), 0); store<i64>(changetype<usize>(this), 0);
Heap.dispose(this.ptr); Heap.dispose(this.ptr);
this.ptr = 0; this.ptr = 0;
Heap.dispose(changetype<this,usize>(this)); Heap.dispose(changetype<usize>(this));
} }
// TODO // TODO

View File

@ -2,7 +2,7 @@ const ALIGN_LOG2: usize = 3;
const ALIGN_SIZE: usize = 1 << ALIGN_LOG2; const ALIGN_SIZE: usize = 1 << ALIGN_LOG2;
const ALIGN_MASK: usize = ALIGN_SIZE - 1; const ALIGN_MASK: usize = ALIGN_SIZE - 1;
let HEAP_OFFSET: usize = HEAP_BASE; // HEAP_BASE is a constant generated by the compiler var HEAP_OFFSET: usize = HEAP_BASE; // HEAP_BASE is a constant generated by the compiler
// TODO: maybe tlsf // TODO: maybe tlsf
@ -15,11 +15,11 @@ export class Heap {
static allocate(size: usize): usize { static allocate(size: usize): usize {
if (!size) return 0; if (!size) return 0;
const len: i32 = current_memory(); var len: i32 = current_memory();
if (HEAP_OFFSET + size > <usize>len << 16) if (HEAP_OFFSET + size > <usize>len << 16)
if(grow_memory(max<i32>(<i32>ceil<f64>(<f64>size / 65536), len * 2 - len)) < 0) if(grow_memory(max<i32>(<i32>ceil<f64>(<f64>size / 65536), len * 2 - len)) < 0)
unreachable(); unreachable();
const ptr: usize = HEAP_OFFSET; var ptr: usize = HEAP_OFFSET;
if ((HEAP_OFFSET += size) & ALIGN_MASK) // align next offset if ((HEAP_OFFSET += size) & ALIGN_MASK) // align next offset
HEAP_OFFSET = (HEAP_OFFSET | ALIGN_MASK) + 1; HEAP_OFFSET = (HEAP_OFFSET | ALIGN_MASK) + 1;
return ptr; return ptr;
@ -33,8 +33,8 @@ export class Heap {
assert(dest >= HEAP_BASE); assert(dest >= HEAP_BASE);
// the following is based on musl's implementation of memcpy // the following is based on musl's implementation of memcpy
let dst: usize = dest; var dst: usize = dest;
let w: u32, x: u32; var w: u32, x: u32;
// copy 1 byte each until src is aligned to 4 bytes // copy 1 byte each until src is aligned to 4 bytes
while (n && src % 4) { while (n && src % 4) {
@ -180,7 +180,7 @@ export class Heap {
// the following is based on musl's implementation of memset // the following is based on musl's implementation of memset
if (!n) return dest; if (!n) return dest;
let s: usize = dest; var s: usize = dest;
// Fill head and tail with minimal branching // Fill head and tail with minimal branching
store<u8>(s, c); store<u8>(s + n - 1, c); store<u8>(s, c); store<u8>(s + n - 1, c);
@ -192,12 +192,12 @@ export class Heap {
if (n <= 8) return dest; if (n <= 8) return dest;
// Align to 4 bytes // Align to 4 bytes
let k: usize = -s & 3; var k: usize = -s & 3;
s += k; s += k;
n -= k; n -= k;
n &= -4; n &= -4;
let c32: u32 = -1 / 255 * c; var c32: u32 = -1 / 255 * c;
// Fill head and tail in preparation of setting 32 bytes at a time // Fill head and tail in preparation of setting 32 bytes at a time
store<u32>(s, c32); store<u32>(s, c32);
@ -223,7 +223,7 @@ export class Heap {
n -= k; n -= k;
// Set 32 bytes at a time // Set 32 bytes at a time
let c64: u64 = <u64>c32 | (<u64>c32 << 32); var c64: u64 = <u64>c32 | (<u64>c32 << 32);
while (n >= 32) { while (n >= 32) {
store<u64>(s, c64); store<u64>(s, c64);
store<u64>(s + 8, c64); store<u64>(s + 8, c64);

View File

@ -1,4 +1,4 @@
const EMPTY: String = changetype<string,String>(""); const EMPTY: String = changetype<String>("");
@global() @global()
export class String { export class String {
@ -29,10 +29,10 @@ export class String {
assert(this != null); assert(this != null);
if (pos < 0 || pos >= this.length) if (pos < 0 || pos >= this.length)
return -1; // undefined return -1; // undefined
let first: i32 = <i32>load<u16>(this.ptr + (<usize>pos << 1)); var first = <i32>load<u16>(this.ptr + (<usize>pos << 1));
if (first < 0xD800 || first > 0xDBFF || pos + 1 == this.length) if (first < 0xD800 || first > 0xDBFF || pos + 1 == this.length)
return first; return first;
let second: i32 = <i32>load<u16>(this.ptr + ((<usize>pos + 1) << 1)); var second = <i32>load<u16>(this.ptr + ((<usize>pos + 1) << 1));
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;
@ -42,9 +42,9 @@ export class String {
concat(other: String): String { concat(other: String): String {
assert(this != null); assert(this != null);
assert(other != null); assert(other != null);
const thisLen: isize = this.length; var thisLen: isize = this.length;
const otherLen: isize = other.length; var otherLen: isize = other.length;
const len: usize = thisLen + otherLen; var len: usize = thisLen + otherLen;
return new String( return new String(
Heap.copy( Heap.copy(
Heap.copy( Heap.copy(
@ -62,9 +62,9 @@ export class String {
endsWith(searchString: String, endPosition: i32 = 0x7fffffff): bool { endsWith(searchString: String, endPosition: i32 = 0x7fffffff): bool {
assert(this != null); assert(this != null);
assert(searchString != null); assert(searchString != null);
let end: isize = <isize>min<i32>(max<i32>(endPosition, 0), this.length); var end: isize = <isize>min<i32>(max<i32>(endPosition, 0), this.length);
let searchLength: isize = searchString.length; var searchLength: isize = searchString.length;
let start: isize = end - searchLength; var start: isize = end - searchLength;
if (start < 0) if (start < 0)
return false; return false;
return !Heap.compare(this.ptr + (start << 1), searchString.ptr, searchLength << 1); return !Heap.compare(this.ptr + (start << 1), searchString.ptr, searchLength << 1);
@ -85,11 +85,11 @@ export class String {
indexOf(searchString: String, position: i32 = 0): i32 { indexOf(searchString: String, position: i32 = 0): i32 {
assert(this != null); assert(this != null);
assert(searchString != null); assert(searchString != null);
let pos: isize = position; var pos: isize = position;
let len: isize = this.length; var len: isize = this.length;
let start: isize = min<isize>(max<isize>(pos, 0), len); var start: isize = min<isize>(max<isize>(pos, 0), len);
let searchLen: isize = searchString.length; var searchLen: isize = searchString.length;
for (let k: usize = start; <isize>k + searchLen <= len; ++k) for (var k: usize = start; <isize>k + searchLen <= len; ++k)
if (!Heap.compare(this.ptr + (k << 1), searchString.ptr, searchLen << 1)) if (!Heap.compare(this.ptr + (k << 1), searchString.ptr, searchLen << 1))
return <i32>k; return <i32>k;
return -1; return -1;
@ -98,10 +98,10 @@ 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); assert(searchString != null);
let pos: isize = position; var pos: isize = position;
let len: isize = this.length; var len: isize = this.length;
let start: isize = min<isize>(max<isize>(position, 0), len); var start: isize = min<isize>(max<isize>(position, 0), len);
let searchLength: isize = searchString.length; var searchLength: isize = searchString.length;
if (searchLength + start > len) if (searchLength + start > len)
return false; return false;
return !Heap.compare(this.ptr + (start << 1), searchString.ptr, searchLength << 1); return !Heap.compare(this.ptr + (start << 1), searchString.ptr, searchLength << 1);
@ -109,12 +109,12 @@ 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);
let intStart: isize = start; var intStart: isize = start;
let end: isize = length; var end: isize = length;
let 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);
let 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;
return new String(this.ptr + (intStart << 1), <i32>resultLength); return new String(this.ptr + (intStart << 1), <i32>resultLength);
@ -122,11 +122,11 @@ 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);
let len: i32 = this.length; var len = this.length;
let finalStart: i32 = min<i32>(max<i32>(start, 0), len); var finalStart = min<i32>(max<i32>(start, 0), len);
let finalEnd: i32 = min<i32>(max<i32>(end, 0), len); var finalEnd = min<i32>(max<i32>(end, 0), len);
let from: i32 = min<i32>(finalStart, finalEnd); var from = min<i32>(finalStart, finalEnd);
let to: i32 = max<i32>(finalStart, finalEnd); var to = max<i32>(finalStart, finalEnd);
len = to - from; len = to - from;
if (!len) if (!len)
return EMPTY; return EMPTY;
@ -137,10 +137,10 @@ export class String {
trim(): String { trim(): String {
assert(this != null); assert(this != null);
let length: usize = this.length; var length: usize = this.length;
while (length && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (length << 1)))) while (length && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (length << 1))))
--length; --length;
let start: usize = 0; var start: usize = 0;
while (start < length && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (start << 1)))) { while (start < length && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (start << 1)))) {
++start; --length; ++start; --length;
} }
@ -153,8 +153,8 @@ export class String {
trimLeft(): String { trimLeft(): String {
assert(this != null); assert(this != null);
let start: isize = 0; var start: isize = 0;
let len: isize = this.length; var len: isize = this.length;
while (start < len && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (start << 1)))) while (start < len && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (start << 1))))
++start; ++start;
if (!start) if (!start)
@ -164,7 +164,7 @@ export class String {
trimRight(): String { trimRight(): String {
assert(this != null); assert(this != null);
let len: isize = this.length; var len: isize = this.length;
while (len > 0 && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (len << 1)))) while (len > 0 && isWhiteSpaceOrLineTerminator(load<u16>(this.ptr + (len << 1))))
--len; --len;
if (len <= 0) if (len <= 0)

2
std/portable.d.ts vendored
View File

@ -116,7 +116,7 @@ declare function store<T = u8>(offset: usize, value: T): void;
declare function unreachable(): any; // sic declare function unreachable(): any; // sic
/** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */ /** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */
declare function changetype<T1,T2>(value: T1): T2; declare function changetype<T>(value: any): T;
/** Traps if the specified value evaluates to `false`. */ /** Traps if the specified value evaluates to `false`. */
declare function assert(isTrue: bool, message?: string): void; declare function assert(isTrue: bool, message?: string): void;
/** Parses an integer string to a 64-bit float. */ /** Parses an integer string to a 64-bit float. */