diff --git a/assembly/__benches__/misc.bench.ts b/assembly/__benches__/misc.bench.ts index 8574639..dc8e9ff 100644 --- a/assembly/__benches__/misc.bench.ts +++ b/assembly/__benches__/misc.bench.ts @@ -1,6 +1,6 @@ import { deserializeString_SIMD } from "../deserialize/simd/string"; import { serializeString_SIMD } from "../serialize/simd/string"; -import { bench } from "as-bench/assembly/index" +import { bench } from "as-bench/assembly/index"; const str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()\\\"\t\r\f\n\u0000'; const str2 = '"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()\\\\\\"\\t\\r\\f\\n\\u0000"'; @@ -22,4 +22,4 @@ bench("Serialize String (SIMD)", () => { bench("Deserialize String (SIMD)", () => { // ~4.03GB/s deserializeString_SIMD(str2, changetype(out)); -}); \ No newline at end of file +}); diff --git a/assembly/__tests__/simd/string.spec.ts b/assembly/__tests__/simd/string.spec.ts index d777678..ce09a0b 100644 --- a/assembly/__tests__/simd/string.spec.ts +++ b/assembly/__tests__/simd/string.spec.ts @@ -9,29 +9,24 @@ const deserialize_simd = (data: string): string => String.UTF16.decodeUnsafe(out describe("Should serialize strings", () => { expect(serialize_simd("abcdefg")).toBe('"abcdefg"'); - expect(serialize_simd('st"ring" w""ith quotes"')) - .toBe('"st\\"ring\\" w\\"\\"ith quotes\\""'); + expect(serialize_simd('st"ring" w""ith quotes"')).toBe('"st\\"ring\\" w\\"\\"ith quotes\\""'); - expect(serialize_simd('string "with random spa\nces and \nnewlines\n\n\n')) - .toBe('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"'); + expect(serialize_simd('string "with random spa\nces and \nnewlines\n\n\n')).toBe('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"'); - expect(serialize_simd('string with colon : comma , brace [ ] bracket { } and quote " and other quote "')) - .toBe('"string with colon : comma , brace [ ] bracket { } and quote \\" and other quote \\""'); + expect(serialize_simd('string with colon : comma , brace [ ] bracket { } and quote " and other quote "')).toBe('"string with colon : comma , brace [ ] bracket { } and quote \\" and other quote \\""'); - expect(serialize_simd("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u000f\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f")) - .toBe("\"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u000f\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f\"") + expect(serialize_simd("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u000f\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f")).toBe('"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u000f\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f"'); }); describe("Should deserialize strings", () => { expect(deserialize_simd('"abcdefg"')).toBe("abcdefg"); - expect(deserialize_simd('"st\\"ring\\" w\\"\\"ith quotes\\""')) - .toBe('st"ring" w""ith quotes"'); + expect(deserialize_simd('"st\\"ring\\" w\\"\\"ith quotes\\""')).toBe('st"ring" w""ith quotes"'); - expect(deserialize_simd('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"')) - .toBe('string "with random spa\nces and \nnewlines\n\n\n'); + expect(deserialize_simd('"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"')).toBe('string "with random spa\nces and \nnewlines\n\n\n'); - expect(deserialize_simd('"string with colon : comma , brace [ ] bracket { } and quote \\" and other quote \\""')) - .toBe('string with colon : comma , brace [ ] bracket { } and quote " and other quote "'); + expect(deserialize_simd('"string with colon : comma , brace [ ] bracket { } and quote \\" and other quote \\""')).toBe('string with colon : comma , brace [ ] bracket { } and quote " and other quote "'); + + expect(deserialize_simd('"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f\\u000f\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f"')).toBe("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u000f\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f"); }); run(); diff --git a/assembly/__tests__/types.ts b/assembly/__tests__/types.ts index 8adadc7..7602837 100644 --- a/assembly/__tests__/types.ts +++ b/assembly/__tests__/types.ts @@ -12,6 +12,7 @@ export class ObjWithStrangeKey { data!: T; } + @json export class ObjectWithStringArray { sa!: string[]; @@ -86,10 +87,12 @@ export type Null = Nullable | null; export class OmitIf { x: i32 = 1; + @omitif("this.y == -1") y: i32 = -1; z: i32 = 1; + @omitnull() foo: string | null = null; } diff --git a/assembly/custom/bs.ts b/assembly/custom/bs.ts index 95da7ae..e06a44c 100644 --- a/assembly/custom/bs.ts +++ b/assembly/custom/bs.ts @@ -1,202 +1,63 @@ -import { dtoa_buffered, itoa_buffered } from "util/number"; -import { OBJECT, TOTAL_OVERHEAD } from "rt/common"; -// @ts-ignore -@inline const MAX_LEN: usize = 1024; -const STORE: usize[] = []; -let STORE_LEN: usize = 0; -const CACHE = memory.data(i32(MAX_LEN)); -// Configurable amount of referenceable strings -let POINTER = changetype(CACHE); -// @ts-ignore -@inline const MAX_CACHE = CACHE + MAX_LEN; +import { bytes } from "../util/bytes"; +import { nextPowerOf2 } from "../util/nextPowerOf2"; -export namespace bs { - // @ts-ignore - @inline export function write_int(num: T): void { - POINTER += itoa_buffered(POINTER, num) << 1; - if (MAX_CACHE <= POINTER) bs.shrink(); - } - - // @ts-ignore - @inline export function write_int_u(num: T): void { - POINTER += itoa_buffered(POINTER, num) << 1; - } - - // @ts-ignore - @inline export function write_fl(num: T): void { - POINTER += dtoa_buffered(POINTER, num) << 1; - if (MAX_CACHE <= POINTER) bs.shrink(); - } - - // @ts-ignore - @inline export function write_fl_u(num: T): void { - POINTER += dtoa_buffered(POINTER, num) << 1; - } - - // @ts-ignore - @inline export function write_b(buf: usize, bytes: usize = changetype(buf - TOTAL_OVERHEAD).rtSize): void { - memory.copy(POINTER, buf, bytes); - POINTER += bytes; - if (MAX_CACHE <= POINTER) bs.shrink(); - } - - // @ts-ignore - @inline export function write_b_u(buf: usize, bytes: usize = changetype(buf - TOTAL_OVERHEAD).rtSize): void { - memory.copy(POINTER, buf, bytes); - POINTER += bytes; - } +let maxOffset: usize = 0; - // @ts-ignore - @inline export function write_s(str: string, bytes: usize = changetype(changetype(str) - TOTAL_OVERHEAD).rtSize): void { - memory.copy(POINTER, changetype(str), bytes); - POINTER += bytes; - if (MAX_CACHE <= POINTER) bs.shrink(); - } - - // @ts-ignore - @inline export function write_s_u(str: string, bytes: usize = changetype(changetype(str) - TOTAL_OVERHEAD).rtSize): void { - memory.copy(POINTER, changetype(str), bytes); - POINTER += bytes; - } - - // @ts-ignore - @inline export function write_s_se(str: string, start: usize, end: usize): void { - const bytes = end - start; - memory.copy(POINTER, changetype(str) + start, bytes); - POINTER += bytes; - if (MAX_CACHE <= POINTER) bs.shrink(); - } - - // @ts-ignore - @inline export function write_s_se_u(str: string, start: usize, end: usize): void { - const bytes = end - start; - memory.copy(POINTER, changetype(str) + start, bytes); - POINTER += bytes; - } - - // @ts-ignore - @inline export function write_8(char: i32): void { - store(POINTER, char); - POINTER += 2; - if (MAX_CACHE <= POINTER) bs.shrink(); - } - - // @ts-ignore - @inline export function write_8_u(char: i32): void { - store(POINTER, char); - //POINTER += 2; - } - - // @ts-ignore - @inline export function write_16(char: i32): void { - store(POINTER, char); - POINTER += 2; - if (MAX_CACHE <= POINTER) bs.shrink(); - } - - // @ts-ignore - @inline export function write_16_u(char: i32): void { - store(POINTER, char); - //POINTER += 2; - } - - // @ts-ignore - @inline export function write_32(chars: i32): void { - store(POINTER, chars); - POINTER += 4; - if (MAX_CACHE <= POINTER) bs.shrink(); - } - - // @ts-ignore - @inline export function write_32_u(chars: i32): void { - store(POINTER, chars); - //POINTER += 4; - } - - // @ts-ignore - @inline export function write_64(chars: i64): void { - store(POINTER, chars); - POINTER += 8; - if (MAX_CACHE <= POINTER) bs.shrink(); - } - - // @ts-ignore - @inline export function write_64_u(chars: i64): void { - store(POINTER, chars); - POINTER += 8; - } - - // @ts-ignore - @inline export function write_128(chars: v128): void { - store(POINTER, chars); - POINTER += 16; - if (MAX_CACHE <= POINTER) bs.shrink(); - } - - // @ts-ignore - @inline export function write_128_n(chars: v128, n: usize): void { - store(POINTER, chars); - POINTER += n; - if (MAX_CACHE <= POINTER) bs.shrink(); - } +/** + * This serves as the central buffer + */ +export namespace bs { + export let buffer: usize = 0; + export let offset: usize = 0; + export let byteLength: usize = 0; // @ts-ignore - @inline export function write_128_u(chars: v128): void { - store(POINTER, chars); - //POINTER += 16; - //if (MAX_CACHE <= POINTER) bs.shrink(); + @inline export function setBuffer(data: T): void { + buffer = changetype(data); + offset = changetype(data); + byteLength = bytes(data); + maxOffset = byteLength + buffer; } // @ts-ignore - @inline export function shrink(): void { - const len = POINTER - CACHE; - STORE_LEN += len; - const out = __new(len, idof()); - memory.copy(out, CACHE, len); - bs.reset(); - STORE.push(out); + @inline export function ensureCapacity(size: u32): void { + const newSize = offset + size; + if (newSize > maxOffset) { + const newPtr = __renew(buffer, (byteLength = nextPowerOf2(newSize - buffer))); + offset = offset - buffer + newPtr; + maxOffset = newPtr + byteLength; + buffer = newPtr; + } } // @ts-ignore - @inline export function out(): T { - const len = POINTER - CACHE; - let out = __new(len + STORE_LEN, idof()); - - memory.copy(out, CACHE, len); - if (STORE_LEN) { - out += len; - for (let i = 0; i < STORE.length; i++) { - const ptr = changetype(unchecked(STORE[i])); - const storeLen = changetype(ptr - TOTAL_OVERHEAD).rtSize; - memory.copy(out, ptr, storeLen); - //__unpin(ptr); - out += storeLen; - } - STORE_LEN = 0; + @inline export function ensureSize(size: u32): void { + const newSize = offset + size; + if (newSize > maxOffset) { + const newPtr = __renew(buffer, (byteLength = newSize - buffer)); + offset = offset - buffer + newPtr; + maxOffset = newPtr + byteLength; + buffer = newPtr; } - bs.reset(); - - return changetype(out); } // @ts-ignore - @inline export function out_u(): T { - const len = POINTER - CACHE; - const out = __new(len + STORE_LEN, idof()); - - memory.copy(out, CACHE, len); - bs.reset(); - - return changetype(out); + @inline export function shrink(): void { + byteLength = offset - buffer; + buffer = __renew(buffer, byteLength); + maxOffset = byteLength + buffer; } // @ts-ignore - @inline export function _out(out: usize): void { - memory.copy(out, CACHE, POINTER - CACHE); + @inline export function shrinkTo(): T { + shrink(); + offset = buffer; + return changetype(buffer); } // @ts-ignore - @inline export function reset(): void { - POINTER = CACHE; + @inline export function to(): T { + offset = buffer; + return changetype(buffer); } } diff --git a/assembly/custom/memory.ts b/assembly/custom/memory.ts index 3b95d05..8092a90 100644 --- a/assembly/custom/memory.ts +++ b/assembly/custom/memory.ts @@ -3,23 +3,23 @@ import { E_INVALIDLENGTH } from "util/error"; // @ts-ignore: Decorator valid here @inline export function ensureCapacity(obj: T, newSize: usize): usize { - const ptr = changetype(obj); - const oldCapacity = changetype(ptr - TOTAL_OVERHEAD).rtSize; - if (newSize > oldCapacity) { - if (newSize > BLOCK_MAXSIZE) throw new RangeError(E_INVALIDLENGTH); - const newCapacity = max(min(oldCapacity << 1, BLOCK_MAXSIZE), newSize); - const newObj = __renew(ptr, newCapacity); - return newObj; - } - return ptr; + const ptr = changetype(obj); + const oldCapacity = changetype(ptr - TOTAL_OVERHEAD).rtSize; + if (newSize > oldCapacity) { + if (newSize > BLOCK_MAXSIZE) throw new RangeError(E_INVALIDLENGTH); + const newCapacity = max(min(oldCapacity << 1, BLOCK_MAXSIZE), newSize); + const newObj = __renew(ptr, newCapacity); + return newObj; + } + return ptr; } // @ts-ignore: Decorator valid here @inline export function setCapacity(obj: T, oldCapacity: usize, newCapacity: usize): usize { - const ptr = changetype(obj); - if (newCapacity > oldCapacity) { - if (newCapacity > BLOCK_MAXSIZE) throw new RangeError(E_INVALIDLENGTH); - return __renew(ptr, newCapacity); - } - return ptr; -} \ No newline at end of file + const ptr = changetype(obj); + if (newCapacity > oldCapacity) { + if (newCapacity > BLOCK_MAXSIZE) throw new RangeError(E_INVALIDLENGTH); + return __renew(ptr, newCapacity); + } + return ptr; +} diff --git a/assembly/custom/util.ts b/assembly/custom/util.ts index 53aad14..b38333f 100644 --- a/assembly/custom/util.ts +++ b/assembly/custom/util.ts @@ -1,5 +1,5 @@ import { isSpace } from "util/string"; -import { BACK_SLASH, QUOTE } from "./chars"; +import { BACK_SLASH, QUOTE } from "./chars"; import { Sink } from "./sink"; // @ts-ignore: Decorator @@ -307,7 +307,6 @@ export function getArrayDepth(depth: i32 = 1): i32 { return false; } - // @ts-ignore: Decorator @inline export function _intTo16(int: i32): i32 { if (int < 10) { @@ -341,4 +340,4 @@ export function getArrayDepth(depth: i32 = 1): i32 { // @ts-ignore: Decorator valid here @inline export function nextPowerOf2(n: u32): u32 { return 1 << (32 - clz(n - 1)); -} \ No newline at end of file +} diff --git a/assembly/deserialize/simd/string.ts b/assembly/deserialize/simd/string.ts index 276f243..b9da861 100644 --- a/assembly/deserialize/simd/string.ts +++ b/assembly/deserialize/simd/string.ts @@ -1,38 +1,6 @@ import { OBJECT, TOTAL_OVERHEAD } from "rt/common"; import { BACK_SLASH } from "../../custom/chars"; -import { JSON } from "../.."; - -const ESCAPE_TABLE = memory.data([ - 0, 0, 0, 0, 0, 0, 0, 0, // 0-7 - 0, 0, 0, 0, 0, 0, 0, 0, // 8-15 - 0, 0, 0, 0, 0, 0, 0, 0, // 16-23 - 0, 0, 0, 0, 0, 0, 0, 0, // 24-31 - 0, 0, 34, 0, 0, 0, 0, 0, // 32-39 - 0, 0, 0, 0, 0, 0, 0, 0, // 40-47 - 0, 0, 0, 0, 0, 0, 0, 0, // 48-55 - 0, 0, 0, 0, 0, 0, 0, 0, // 56-63 - 0, 0, 0, 0, 0, 0, 0, 0, // 64-71 - 0, 0, 0, 0, 0, 0, 0, 0, // 72-79 - 0, 0, 0, 0, 0, 0, 0, 0, // 80-87 - 0, 0, 0, 0, 92, 0, 0, 0, // 88-95 - 0, 0, 8, 0, 0, 0, 12, 0, // 96-103 - 0, 0, 0, 0, 0, 0, 10, 0, // 104-111 - 0, 0, 13, 0, 9, 117, 0, 0, // 112-119 - 0, 0, 0, 0, 0, 0, 0, 0, // 120-127 - 0, 0, 0, 0, 0, 0, 0, 0, // 128-135 - 0, 0, 0, 0, 0, 0, 0, 0, // 136-143 - 0, 0, 0, 0, 0, 0, 0, 0, // 144-151 -]); - -const ESCAPE_HEX_TABLE = memory.data([ - 0, 1, 2, 3, 4, 5, 6, 7, // 0-7 - 8, 9, 0, 0, 0, 0, 0, 0, // 8-15 - 0, 0, 0, 0, 0, 0, 0, 0, // 16-23 - 0, 0, 0, 0, 0, 0, 0, 0, // 24-31 - 0, 0, 0, 0, 0, 0, 0, 0, // 32-39 - 0, 0, 0, 0, 0, 0, 0, 0, // 40-47 - 0, 10, 11, 12, 13, 14, 15, // 48-54 -]) - 48; +import { DESERIALIZE_ESCAPE_TABLE, ESCAPE_HEX_TABLE } from "../../globals/tables"; const SPLAT_92 = i16x8.splat(92); /* \ */ @@ -42,6 +10,7 @@ const SPLAT_92 = i16x8.splat(92); /* \ */ * @param dst buffer to write to * @returns number of bytes written */ +// todo: optimize and stuff. it works, its not pretty. ideally, i'd like this to be (nearly) branchless // @ts-ignore: Decorator @inline export function deserializeString_SIMD(src: string, dst: usize): usize { let src_ptr = changetype(src) + 2; @@ -66,8 +35,8 @@ const SPLAT_92 = i16x8.splat(92); /* \ */ mask &= mask - 1; if (code == 117 && load(src_offset, 4) == 3145776) { const block = load(src_offset, 8); - const codeA = block & 0xFFFF; - const codeB = (block >> 16) & 0xFFFF; + const codeA = block & 0xffff; + const codeB = (block >> 16) & 0xffff; const escapedA = load(ESCAPE_HEX_TABLE + codeA); const escapedB = load(ESCAPE_HEX_TABLE + codeB); const escaped = (escapedA << 4) + escapedB; @@ -88,7 +57,7 @@ const SPLAT_92 = i16x8.splat(92); /* \ */ } dst_ptr -= 10; } else { - const escaped = load(ESCAPE_TABLE + code); + const escaped = load(DESERIALIZE_ESCAPE_TABLE + code); store(dst_offset, escaped); v128.store(dst_offset, v128.load(src_offset, 4), 2); // console.log("Escaped:"); @@ -109,11 +78,11 @@ const SPLAT_92 = i16x8.splat(92); /* \ */ while (src_ptr < src_end) { let code = load(src_ptr); if (code == BACK_SLASH) { - code = load(ESCAPE_TABLE + load(src_ptr, 2)); + code = load(DESERIALIZE_ESCAPE_TABLE + load(src_ptr, 2)); if (code == 117 && load(src_ptr, 4) == 3145776) { const block = load(src_ptr, 8); - const codeA = block & 0xFFFF; - const codeB = (block >> 16) & 0xFFFF; + const codeA = block & 0xffff; + const codeB = (block >> 16) & 0xffff; const escapedA = load(ESCAPE_HEX_TABLE + codeA); const escapedB = load(ESCAPE_HEX_TABLE + codeB); const escaped = (escapedA << 4) + escapedB; @@ -133,4 +102,4 @@ const SPLAT_92 = i16x8.splat(92); /* \ */ } return dst_ptr - dst; -} \ No newline at end of file +} diff --git a/assembly/deserialize/simple/array.ts b/assembly/deserialize/simple/array.ts index 1faaa69..c39b085 100644 --- a/assembly/deserialize/simple/array.ts +++ b/assembly/deserialize/simple/array.ts @@ -36,4 +36,4 @@ export function deserializeArray(data: string): T { } else { throw new Error("Could not parse array of type " + nameof() + "!"); } -} \ No newline at end of file +} diff --git a/assembly/deserialize/simple/bool.ts b/assembly/deserialize/simple/bool.ts index 2d97bbf..d2aa146 100644 --- a/assembly/deserialize/simple/bool.ts +++ b/assembly/deserialize/simple/bool.ts @@ -15,4 +15,4 @@ import { unsafeCharCodeAt } from "../../custom/util"; if (len == 4 && firstChar == CHAR_T && load(ptr) == 28429475166421108) return true; else if (len == 5 && firstChar == CHAR_F && load(ptr, 2) == 28429466576093281) return false; return false; //ERROR(`Expected to find boolean, but found "${data.slice(0, 100)}" instead!`); -} \ No newline at end of file +} diff --git a/assembly/deserialize/simple/date.ts b/assembly/deserialize/simple/date.ts index 3f4430c..c2a34b7 100644 --- a/assembly/deserialize/simple/date.ts +++ b/assembly/deserialize/simple/date.ts @@ -9,4 +9,4 @@ import { QUOTE } from "../../custom/chars"; // This may seem redundant, but addreses the issue when Date // is globally aliased to wasi_Date (or some other superclass). return new Date(d.getTime()); -} \ No newline at end of file +} diff --git a/assembly/deserialize/simple/float.ts b/assembly/deserialize/simple/float.ts index e62162d..6d0b60c 100644 --- a/assembly/deserialize/simple/float.ts +++ b/assembly/deserialize/simple/float.ts @@ -6,4 +6,4 @@ if (type instanceof f64) return f64.parse(data); // @ts-ignore return f32.parse(data); -} \ No newline at end of file +} diff --git a/assembly/deserialize/simple/integer.ts b/assembly/deserialize/simple/integer.ts index 3563445..c4ef3fa 100644 --- a/assembly/deserialize/simple/integer.ts +++ b/assembly/deserialize/simple/integer.ts @@ -4,4 +4,4 @@ import { snip_fast } from "../../custom/util"; @inline export function deserializeInteger(data: string): T { // @ts-ignore return snip_fast(data); -} \ No newline at end of file +} diff --git a/assembly/deserialize/simple/map.ts b/assembly/deserialize/simple/map.ts index d84d975..5cdea26 100644 --- a/assembly/deserialize/simple/map.ts +++ b/assembly/deserialize/simple/map.ts @@ -129,4 +129,4 @@ function deserializeMapKey(key: Virtual): T { } throw new Error(`JSON: Cannot parse JSON object to a Map with a key of type ${nameof()}`); -} \ No newline at end of file +} diff --git a/assembly/deserialize/simple/object.ts b/assembly/deserialize/simple/object.ts index 084f3e6..bbfe301 100644 --- a/assembly/deserialize/simple/object.ts +++ b/assembly/deserialize/simple/object.ts @@ -102,4 +102,4 @@ export function deserializeObject(data: string): T { } } return schema; -} \ No newline at end of file +} diff --git a/assembly/deserialize/simple/string.ts b/assembly/deserialize/simple/string.ts index 3d9bc21..460c787 100644 --- a/assembly/deserialize/simple/string.ts +++ b/assembly/deserialize/simple/string.ts @@ -65,4 +65,4 @@ import { unsafeCharCodeAt } from "../../custom/util"; result.write(data, last, end); } return result.toString(); -} \ No newline at end of file +} diff --git a/assembly/globals/tables.ts b/assembly/globals/tables.ts new file mode 100644 index 0000000..c2d8caa --- /dev/null +++ b/assembly/globals/tables.ts @@ -0,0 +1,413 @@ +export const SERIALIZE_ESCAPE_TABLE = memory.data([ + 48, + 48, + 48, + 49, + 48, + 50, + 48, + 51, // Pair 0-3 + 48, + 52, + 48, + 53, + 48, + 54, + 48, + 55, // Pair 4-7 + + 92, + 98, + 92, + 116, + 92, + 110, + 48, + 98, // Pair 8-11 + 92, + 102, + 92, + 114, + 48, + 101, + 48, + 102, // Pair 12-15 + + 49, + 48, + 49, + 49, + 49, + 50, + 49, + 51, // Pair 16-19 + 49, + 52, + 49, + 53, + 49, + 54, + 49, + 55, // Pair 20-23 + + 49, + 56, + 49, + 57, + 49, + 97, + 49, + 98, // Pair 24-27 + 49, + 99, + 49, + 100, + 49, + 101, + 49, + 102, // Pair 28-31 + + 0, + 0, + 0, + 0, + 92, + 34, + 0, + 0, // Pair 32-35 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 36-39 + + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 40-43 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 44-47 + + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 48-51 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 52-55 + + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 56-59 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 60-63 + + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 64-67 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 68-71 + + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 72-75 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 76-79 + + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 80-83 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 84-87 + + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // Pair 88-91 + 92, + 92, // Pair 92-93 +]); + +export const DESERIALIZE_ESCAPE_TABLE = memory.data([ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 0-7 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 8-15 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 16-23 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 24-31 + 0, + 0, + 34, + 0, + 0, + 0, + 0, + 0, // 32-39 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 40-47 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 48-55 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 56-63 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 64-71 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 72-79 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 80-87 + 0, + 0, + 0, + 0, + 92, + 0, + 0, + 0, // 88-95 + 0, + 0, + 8, + 0, + 0, + 0, + 12, + 0, // 96-103 + 0, + 0, + 0, + 0, + 0, + 0, + 10, + 0, // 104-111 + 0, + 0, + 13, + 0, + 9, + 117, + 0, + 0, // 112-119 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 120-127 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 128-135 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 136-143 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 144-151 +]); + +export const ESCAPE_HEX_TABLE = + memory.data([ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, // 0-7 + 8, + 9, + 0, + 0, + 0, + 0, + 0, + 0, // 8-15 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 16-23 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 24-31 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 32-39 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, // 40-47 + 0, + 10, + 11, + 12, + 13, + 14, + 15, // 48-54 + ]) - 48; diff --git a/assembly/index.ts b/assembly/index.ts index dac0bad..bf8b62f 100644 --- a/assembly/index.ts +++ b/assembly/index.ts @@ -19,23 +19,14 @@ import { serializeArbitrary } from "./serialize/simple/arbitrary"; import { Sink } from "./custom/sink"; import { NULL_WORD } from "./custom/chars"; +import { Result } from "as-container"; +import { bs } from "./custom/bs"; import { setCapacity } from "./custom/memory"; +import { dtoa_buffered, itoa_buffered } from "util/number"; -import { BLOCK_MAXSIZE, OBJECT, TOTAL_OVERHEAD } from "rt/common"; -import { E_INVALIDLENGTH } from "util/error"; -import { serializeString_SIMD } from "./serialize/simd/string"; -import { Option } from "as-container"; -import { deserializeString_SIMD } from "./deserialize/simd/string"; +class Nullable {} -// Config -class SerializeOptions { - public pretty: bool = false; -} - -class JSONRAW { } - -export type Raw = JSONRAW; -const DEFAULT_SERIALIZE_OPTIONS = new SerializeOptions(); +export type Raw = string; /** * Offset of the 'storage' property in the JSON.Value class. @@ -48,47 +39,58 @@ const DEFAULT_SERIALIZE_OPTIONS = new SerializeOptions(); */ export namespace JSON { /** - * Serializes valid JSON data and outputs it to string - * ```js - * JSON.stringify(data) - * ``` - * @param data T - * @returns string - */ - export function stringifyTo(data: T, out: string): string { - if (isString()) { - const oldCapacity = changetype(changetype(out) - TOTAL_OVERHEAD).rtSize; - const outPtr = setCapacity(out, oldCapacity, oldCapacity << 3); // this doesn't account for \u0000+ - out = changetype(__renew(outPtr, serializeString_SIMD(data as string, outPtr))); - return changetype(outPtr); - } else { - return unreachable(); - } - } - - /** - * Serializes valid JSON data and outputs it to string - * ```js - * JSON.stringify(data) - * ``` - * @param data T - * @returns string - */ - export function stringifySafe(data: T, out: string): Option { + * Serializes valid JSON data + * ```js + * JSON.stringify(data) + * ``` + * @param data T + * @returns string + */ + export function stringify(data: T, out: string | null = null): string { if (isBoolean()) { - return Option.Some(serializeBool(data as bool)); + if (out) { + bs.setBuffer(out); + if (data == true) { + out = changetype(__renew(changetype(out), 8)); + store(changetype(out), 28429475166421108); + } else { + out = changetype(__renew(changetype(out), 8)); + store(changetype(out), 32370086184550502); + store(changetype(out), 101, 8); + } + return out; + } + return serializeBool(data as bool); } else if (isInteger()) { + if (out) { + out = changetype(__renew(changetype(out), sizeof() << 3)); + // @ts-ignore + const bytes = itoa_buffered(changetype(out), data) << 1; + return (out = changetype(__renew(changetype(out), bytes))); + } // @ts-ignore - return Option.Some(serializeInteger(data)); + return serializeInteger(data); } else if (isFloat(data)) { + if (out) { + out = changetype(__renew(changetype(out), 64)); + // @ts-ignore + const bytes = dtoa_buffered(changetype(out), data) << 1; + return (out = changetype(__renew(changetype(out), bytes))); + } // @ts-ignore - return Option.Some(serializeFloat(data)); + return serializeFloat(data); // @ts-ignore: Function is generated by transform } else if (isNullable() && changetype(data) == 0) { - return Option.Some(NULL_WORD); + if (out) { + out = changetype(__renew(changetype(out), 8)); + store(changetype(out), 30399761348886638); + return out; + } + return NULL_WORD; // @ts-ignore } else if (isString>()) { - return serializeString(changetype(data)); + serializeString(changetype(data), out); + return bs.shrinkTo(); // @ts-ignore: Supplied by transform } else if (isDefined(data.__SERIALIZE)) { /*if (options.pretty) { @@ -109,32 +111,33 @@ export namespace JSON { } else if (data instanceof JSON.Value) { return serializeArbitrary(data); } else { - throw new Error(`Could not serialize data of type ${nameof()}. Make sure to add the correct decorators to classes.`); + ERROR(`Could not serialize data of type ${nameof()}. Make sure to add the correct decorators to classes.`); } } + /** - * Serializes valid JSON data. + * Serializes valid JSON data (safely) * ```js * JSON.stringify(data) * ``` * @param data T * @returns string */ - export function stringify(data: T): string { + export function stringifySafe(data: T): Result { if (isBoolean()) { - return serializeBool(data as bool); + return Result.Ok(serializeBool(data as bool)); } else if (isInteger()) { // @ts-ignore - return serializeInteger(data); + return Result.Ok(serializeInteger(data)); } else if (isFloat(data)) { // @ts-ignore - return serializeFloat(data); + return Result.Ok(serializeFloat(data)); // @ts-ignore: Function is generated by transform } else if (isNullable() && changetype(data) == 0) { - return NULL_WORD; + return Result.Ok(NULL_WORD); // @ts-ignore } else if (isString>()) { - return serializeString(changetype(data)); + return Result.Ok(serializeString(changetype(data))); // @ts-ignore: Supplied by transform } else if (isDefined(data.__SERIALIZE)) { /*if (options.pretty) { @@ -142,43 +145,25 @@ export namespace JSON { return serializeObject_Pretty(changetype>(data)); }*/ // @ts-ignore - return serializeObject(changetype>(data)); + return Result.Ok(serializeObject(changetype>(data))); } else if (data instanceof Date) { // @ts-ignore - return serializeDate(changetype>(data)); + return Result.Ok(serializeDate(changetype>(data))); } else if (data instanceof Array) { // @ts-ignore - return serializeArray(changetype>(data)); + return Result.Ok(serializeArray(changetype>(data))); } else if (data instanceof Map) { // @ts-ignore - return serializeMap(changetype>(data)); + return Result.Ok(serializeMap(changetype>(data))); } else if (data instanceof JSON.Value) { - return serializeArbitrary(data); + return Result.Ok(serializeArbitrary(data)); } else { - throw new Error(`Could not serialize data of type ${nameof()}. Make sure to add the correct decorators to classes.`); - } - } - - /** - * Serializes valid JSON data and outputs it to string - * ```js - * JSON.stringify(data) - * ``` - * @param data T - * @returns string - */ - export function parseTo(data: string, out: T): T { - if (isString()) { - const oldCapacity = changetype(changetype(out) - TOTAL_OVERHEAD).rtSize; - const outPtr = setCapacity(out, oldCapacity, oldCapacity << 3); // this doesn't account for \u0000+ - out = changetype(__renew(outPtr, deserializeString_SIMD(data as string, outPtr))) as T; - return changetype(outPtr) as T; - } else { - return unreachable(); + return Result.Err(new Error(`Could not serialize data of type ${nameof()}. Make sure to add the correct decorators to classes.`)); } } + /** - * Parses valid JSON strings into their original format. + * Parses valid JSON strings into their original format * ```js * JSON.parse(data) * ``` @@ -214,7 +199,48 @@ export namespace JSON { // @ts-ignore return deserializeDate(data); } else { - throw new Error(`Could not deserialize data ${data} to type ${nameof()}. Make sure to add the correct decorators to classes.`); + ERROR(`Could not deserialize data ${data} to type ${nameof()}. Make sure to add the correct decorators to classes.`); + } + } + + /** + * Parses valid JSON strings into their original format (safely) + * ```js + * JSON.parse(data) + * ``` + * @param data string + * @returns T + */ + export function parseSafe(data: string): Result { + if (isBoolean()) { + return Result.Ok(deserializeBoolean(data) as T); + } else if (isInteger()) { + return Result.Ok(deserializeInteger(data)); + } else if (isFloat()) { + return Result.Ok(deserializeFloat(data)); + } else if (isNullable() && data.length == 4 && data == "null") { + // @ts-ignore + return Result.Ok(null); + } else if (isString()) { + // @ts-ignore + return Result.Ok(deserializeString(data)); + } else if (isArray()) { + // @ts-ignore + return Result.Ok(deserializeArray>(data)); + } + let type: nonnull = changetype>(0); + // @ts-ignore: Defined by transform + if (isDefined(type.__DESERIALIZE)) { + // @ts-ignore + return Result.Ok(deserializeObject>(data.trimStart())); + } else if (type instanceof Map) { + // @ts-ignore + return Result.Ok(deserializeMap>(data.trimStart())); + } else if (type instanceof Date) { + // @ts-ignore + return Result.Ok(deserializeDate(data)); + } else { + return Result.Err(new Error(`Could not deserialize data ${data} to type ${nameof()}. Make sure to add the correct decorators to classes.`)); } } @@ -369,7 +395,7 @@ export namespace JSON { * Box for primitive types */ export class Box { - constructor(public value: T) { } + constructor(public value: T) {} /** * Creates a reference to a primitive type * This means that it can create a nullable primitive @@ -384,4 +410,4 @@ export namespace JSON { return new Box(value); } } -} \ No newline at end of file +} diff --git a/assembly/serialize/simd/string.ts b/assembly/serialize/simd/string.ts index fa81d20..ec77ad0 100644 --- a/assembly/serialize/simd/string.ts +++ b/assembly/serialize/simd/string.ts @@ -1,43 +1,6 @@ import { OBJECT, TOTAL_OVERHEAD } from "rt/common"; import { BACK_SLASH } from "../../custom/chars"; - -const ESCAPE_TABLE = memory.data([ - 48, 48, 48, 49, 48, 50, 48, 51, // Pair 0-3 - 48, 52, 48, 53, 48, 54, 48, 55, // Pair 4-7 - - 92, 98, 92, 116, 92, 110, 48, 98, // Pair 8-11 - 92, 102, 92, 114, 48, 101, 48, 102, // Pair 12-15 - - 49, 48, 49, 49, 49, 50, 49, 51, // Pair 16-19 - 49, 52, 49, 53, 49, 54, 49, 55, // Pair 20-23 - - 49, 56, 49, 57, 49, 97, 49, 98, // Pair 24-27 - 49, 99, 49, 100, 49, 101, 49, 102, // Pair 28-31 - - 0, 0, 0, 0, 92, 34, 0, 0, // Pair 32-35 - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 36-39 - - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 40-43 - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 44-47 - - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 48-51 - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 52-55 - - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 56-59 - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 60-63 - - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 64-67 - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 68-71 - - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 72-75 - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 76-79 - - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 80-83 - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 84-87 - - 0, 0, 0, 0, 0, 0, 0, 0, // Pair 88-91 - 92, 92, // Pair 92-93 -]); +import { SERIALIZE_ESCAPE_TABLE } from "../../globals/tables"; const SPLAT_34 = i16x8.splat(34); /* " */ const SPLAT_92 = i16x8.splat(92); /* \ */ @@ -76,11 +39,11 @@ export function serializeString_SIMD(src: string, dst: usize): usize { const dst_offset = dst_ptr + lane_index; const src_offset = src_ptr + lane_index; const code = load(src_offset) << 2; - const escaped = load(ESCAPE_TABLE + code); + const escaped = load(SERIALIZE_ESCAPE_TABLE + code); mask &= mask - 1; - if ((escaped & 0xFFFF) != BACK_SLASH) { + if ((escaped & 0xffff) != BACK_SLASH) { store(dst_offset, 13511005048209500); store(dst_offset, escaped, 8); v128.store(dst_offset, v128.load(src_offset, 2), 12); @@ -92,7 +55,8 @@ export function serializeString_SIMD(src: string, dst: usize): usize { } } - src_ptr += 16; dst_ptr += 16; + src_ptr += 16; + dst_ptr += 16; } let rem = src_end - src_ptr; @@ -113,10 +77,10 @@ export function serializeString_SIMD(src: string, dst: usize): usize { const dst_offset = dst_ptr + lane_index; const src_offset = src_ptr + lane_index; const code = load(src_offset) << 2; - const escaped = load(ESCAPE_TABLE + code); + const escaped = load(SERIALIZE_ESCAPE_TABLE + code); mask &= mask - 1; - if ((escaped & 0xFFFF) != BACK_SLASH) { + if ((escaped & 0xffff) != BACK_SLASH) { store(dst_offset, 13511005048209500); store(dst_offset, escaped, 8); while (lane_index < 6) { @@ -135,17 +99,18 @@ export function serializeString_SIMD(src: string, dst: usize): usize { } } - dst_ptr += 8; src_ptr += 8; + dst_ptr += 8; + src_ptr += 8; } if (rem & 4) { const block = load(src_ptr); - const codeA = block & 0xFFFF; - const codeB = (block >> 16) & 0xFFFF; + const codeA = block & 0xffff; + const codeB = (block >> 16) & 0xffff; if (codeA == 92 || codeA == 34 || codeA < 32) { - const escaped = load(ESCAPE_TABLE + (codeA << 2)); + const escaped = load(SERIALIZE_ESCAPE_TABLE + (codeA << 2)); - if ((escaped & 0xFFFF) != BACK_SLASH) { + if ((escaped & 0xffff) != BACK_SLASH) { store(dst_ptr, 13511005048209500); store(dst_ptr, escaped, 8); dst_ptr += 12; @@ -153,16 +118,15 @@ export function serializeString_SIMD(src: string, dst: usize): usize { store(dst_ptr, escaped); dst_ptr += 4; } - } else { store(dst_ptr, codeA); dst_ptr += 2; } if (codeB == 92 || codeB == 34 || codeB < 32) { - const escaped = load(ESCAPE_TABLE + (codeB << 2)); + const escaped = load(SERIALIZE_ESCAPE_TABLE + (codeB << 2)); - if ((escaped & 0xFFFF) != BACK_SLASH) { + if ((escaped & 0xffff) != BACK_SLASH) { store(dst_ptr, 13511005048209500); store(dst_ptr, escaped, 8); dst_ptr += 12; @@ -170,7 +134,6 @@ export function serializeString_SIMD(src: string, dst: usize): usize { store(dst_ptr, escaped); dst_ptr += 4; } - } else { store(dst_ptr, codeB); dst_ptr += 2; @@ -181,9 +144,9 @@ export function serializeString_SIMD(src: string, dst: usize): usize { if (rem & 2) { const code = load(src_ptr); if (code == 92 || code == 34 || code < 32) { - const escaped = load(ESCAPE_TABLE + (code << 2)); + const escaped = load(SERIALIZE_ESCAPE_TABLE + (code << 2)); - if ((escaped & 0xFFFF) != BACK_SLASH) { + if ((escaped & 0xffff) != BACK_SLASH) { store(dst_ptr, 13511005048209500); store(dst_ptr, escaped, 8); dst_ptr += 12; @@ -191,7 +154,6 @@ export function serializeString_SIMD(src: string, dst: usize): usize { store(dst_ptr, escaped); dst_ptr += 4; } - } else { store(dst_ptr, code); dst_ptr += 2; @@ -200,4 +162,4 @@ export function serializeString_SIMD(src: string, dst: usize): usize { store(dst_ptr, 34); /* " */ return dst_ptr - changetype(dst) + 2; -} \ No newline at end of file +} diff --git a/assembly/serialize/simple/arbitrary.ts b/assembly/serialize/simple/arbitrary.ts index 3bb1d20..142d98e 100644 --- a/assembly/serialize/simple/arbitrary.ts +++ b/assembly/serialize/simple/arbitrary.ts @@ -1,7 +1,6 @@ import { JSON } from "../.."; import { Sink } from "../../custom/sink"; - export function serializeArbitrary(data: JSON.Value): string { switch (data.type) { case JSON.Types.U8: diff --git a/assembly/serialize/simple/array.ts b/assembly/serialize/simple/array.ts index fb9054d..3383816 100644 --- a/assembly/serialize/simple/array.ts +++ b/assembly/serialize/simple/array.ts @@ -1,43 +1,39 @@ -import { JSON } from "../.."; -import { COMMA, COMMA_WORD, EMPTY_BRACKET_WORD, BRACKET_LEFT_WORD, BRACKET_RIGHT, BRACKET_RIGHT_WORD } from "../../custom/chars"; -import { Sink } from "../../custom/sink"; -import { serializeString } from "./string"; +import { serialize } from "."; +import { bs } from "../../custom/bs"; +import { COMMA, BRACKET_RIGHT, BRACKET_LEFT } from "../../custom/chars"; -export function serializeArray(data: T): string { - if (data.length == 0) { - return EMPTY_BRACKET_WORD; - // @ts-ignore - } else if (isString>()) { - let result = BRACKET_LEFT_WORD; - // @ts-ignore - for (let i = 0; i < data.length - 1; i++) { - // @ts-ignore - result += serializeString(unchecked(data[i])); - result += COMMA_WORD; - } - // @ts-ignore - result += serializeString(unchecked(data[data.length - 1])); - result += BRACKET_RIGHT_WORD; - return result; - // @ts-ignore - } else if (isBoolean>()) { - // @ts-ignore - return BRACKET_LEFT_WORD + data.join(COMMA_WORD) + BRACKET_RIGHT_WORD; - // @ts-ignore - } else if (isFloat>() || isInteger>()) { - // @ts-ignore - return BRACKET_LEFT_WORD + data.join(COMMA_WORD) + BRACKET_RIGHT_WORD; - } else { - let result = Sink.fromString(BRACKET_LEFT_WORD); - // @ts-ignore - for (let i = 0; i < data.length - 1; i++) { - // @ts-ignore - result.write(JSON.stringify(unchecked(data[i]))); - result.writeCodePoint(COMMA); - } - // @ts-ignore - result.write(JSON.stringify(unchecked(data[data.length - 1]))); - result.writeCodePoint(BRACKET_RIGHT); - return result.toString(); +export function serializeArray(src: T): void { + const srcSize = load(changetype(src), offsetof("byteLength")); + + if (srcSize == 0) { + if (!bs.buffer) bs.setBuffer(__new(4, idof())); + bs.ensureSize(4); + store(bs.offset, 6094939); + bs.offset += 4; + return; } + + let srcPtr = src.dataStart; + const srcEnd = srcPtr + srcSize - sizeof>(); + // if (!bs.buffer) bs.setBuffer(__new(srcSize << 3, idof())); + // else + bs.ensureSize(srcSize << 3); + + store(bs.offset, BRACKET_LEFT); + bs.offset += 2; + + while (srcPtr < srcEnd) { + const block = load>(srcPtr); + serialize>(block); + bs.ensureCapacity(2); + store(bs.offset, COMMA); + bs.offset += 2; + srcPtr += sizeof(); + } + + const lastBlock = load>(srcPtr); + serialize>(lastBlock); + + store(bs.offset, BRACKET_RIGHT); + bs.offset += 2; } diff --git a/assembly/serialize/simple/bool.ts b/assembly/serialize/simple/bool.ts index 8ee4d72..6529727 100644 --- a/assembly/serialize/simple/bool.ts +++ b/assembly/serialize/simple/bool.ts @@ -1,10 +1,20 @@ +import { bs } from "../../custom/bs"; + /** * Serialize a bool to type string * @param data data to serialize - * @returns string + * @returns void */ - // @ts-ignore: Decorator valid here -@inline export function serializeBool(data: bool): string { - return data ? "true" : "false"; +@inline export function serializeBool(data: bool): void { + if (data == true) { + bs.ensureSize(8); + store(bs.offset, 28429475166421108); + bs.offset += 8; + } else { + bs.ensureSize(10); + store(bs.offset, 32370086184550502); + store(bs.offset, 101, 8); + bs.offset += 10; + } } diff --git a/assembly/serialize/simple/date.ts b/assembly/serialize/simple/date.ts index 4375656..fe934cc 100644 --- a/assembly/serialize/simple/date.ts +++ b/assembly/serialize/simple/date.ts @@ -1,4 +1,14 @@ +import { bs } from "../../custom/bs"; +import { QUOTE } from "../../custom/chars"; +import { bytes } from "../../util/bytes"; + // @ts-ignore: Decorator valid here -@inline export function serializeDate(data: Date): string { - return `"${data.toISOString()}"`; +@inline export function serializeDate(src: Date): void { + const data = src.toISOString(); + const dataSize = bytes(data); + bs.ensureSize(dataSize + 4); + store(bs.offset, QUOTE); + memory.copy(bs.offset + 2, changetype(data), dataSize); + store(bs.offset + dataSize, QUOTE, 2); + bs.offset += dataSize + 4; } diff --git a/assembly/serialize/simple/float.ts b/assembly/serialize/simple/float.ts index 0138007..da210ba 100644 --- a/assembly/serialize/simple/float.ts +++ b/assembly/serialize/simple/float.ts @@ -1,4 +1,8 @@ +import { dtoa_buffered } from "util/number"; +import { bs } from "../../custom/bs"; + // @ts-ignore: Decorator valid here -@inline export function serializeFloat(data: T): string { - return data.toString(); -} +@inline export function serializeFloat(data: T): void { + bs.ensureSize(64); + bs.offset += dtoa_buffered(bs.offset, data) << 1; +} \ No newline at end of file diff --git a/assembly/serialize/simple/index.ts b/assembly/serialize/simple/index.ts new file mode 100644 index 0000000..1e0b401 --- /dev/null +++ b/assembly/serialize/simple/index.ts @@ -0,0 +1,46 @@ +// import { JSON } from "../.."; +import { bs } from "../../custom/bs"; +import { serializeArbitrary } from "./arbitrary"; +import { serializeArray } from "./array"; +import { serializeBool } from "./bool"; +import { serializeDate } from "./date"; +import { serializeFloat } from "./float"; +import { serializeInteger } from "./integer"; +import { serializeMap } from "./map"; +import { serializeString } from "./string"; + +export function serialize(src: T): void { + if (isBoolean()) { + serializeBool(src as bool); + } else if (isInteger()) { + // @ts-ignore + serializeInteger(src); + } else if (isFloat(src)) { + // @ts-ignore + serializeFloat(src); + // @ts-ignore: Function is generated by transform + } else if (changetype(src) == 0) { + bs.ensureSize(8); + store(bs.offset, 30399761348886638); + bs.offset += 8; + } else if (isString>()) { + serializeString(src as string); + // @ts-ignore: Supplied by transform + } else if (isDefined(src.__SERIALIZE)) { + // @ts-ignore + serializeObject(changetype>(src)); + } else if (src instanceof Date) { + // @ts-ignore + serializeDate(changetype>(src)); + } else if (src instanceof Array) { + // @ts-ignore + serializeArray(changetype>(src)); + } else if (src instanceof Map) { + // @ts-ignore + serializeMap(changetype>(src)); + } /*else if (src instanceof JSON.Value) { + serializeArbitrary(src); + }*/ else { + ERROR(`Could not serialize src of type ${nameof()}. Make sure to add the correct decorators to classes.`); + } +} \ No newline at end of file diff --git a/assembly/serialize/simple/integer.ts b/assembly/serialize/simple/integer.ts index 481a78a..c5313c6 100644 --- a/assembly/serialize/simple/integer.ts +++ b/assembly/serialize/simple/integer.ts @@ -1,5 +1,8 @@ +import { itoa_buffered } from "util/number"; +import { bs } from "../../custom/bs"; + // @ts-ignore: Decorator valid here -@inline export function serializeInteger(data: T): string { - // I have a much faster implementation of itoa that I will port over later. Its ~4x faster - return data.toString(); -} +@inline export function serializeInteger(data: T): void { + bs.ensureSize(sizeof() << 3); + bs.offset += itoa_buffered(bs.offset, data) << 1; +} \ No newline at end of file diff --git a/assembly/serialize/simple/map.ts b/assembly/serialize/simple/map.ts index eed1ee5..705a728 100644 --- a/assembly/serialize/simple/map.ts +++ b/assembly/serialize/simple/map.ts @@ -1,23 +1,43 @@ -import { COLON, COMMA, BRACE_LEFT_WORD, BRACE_RIGHT } from "../../custom/chars"; -import { JSON } from "../.."; -import { Sink } from "../../custom/sink"; +import { BRACE_LEFT, BRACE_RIGHT, COLON, COMMA } from "../../custom/chars"; +import { bs } from "../../custom/bs"; +import { serialize } from "."; -export function serializeMap>(data: T): string { - let result = Sink.fromString(BRACE_LEFT_WORD); - if (!data.size) return "{}"; - let keys = data.keys(); - let values = data.values(); - const end = data.size - 1; - for (let i = 0; i < end; i++) { - result.write(JSON.stringify(unchecked(keys[i]).toString())); - result.writeCodePoint(COLON); - result.write(JSON.stringify(unchecked(values[i]))); - result.writeCodePoint(COMMA); +export function serializeMap>(src: T): void { + const srcSize = src.size; + const srcEnd = srcSize - 1; + + if (!srcSize) { + bs.ensureSize(4); + store(bs.offset, 8192123); + bs.offset += 4; + return; + } + + let keys = src.keys(); + let values = src.values(); + + bs.ensureSize(srcSize << 3); // This needs to be predicted better + + store(bs.offset, BRACE_LEFT); + bs.offset += 2; + + for (let i = 0; i < srcEnd; i++) { + serialize(unchecked(keys[i])); + bs.ensureSize(2); + store(bs.offset, COLON); + bs.offset += 2; + serialize(unchecked(values[i])); + bs.ensureSize(2); + store(bs.offset, COMMA); + bs.offset += 2; } - result.write(JSON.stringify(unchecked(keys[end]).toString())); - result.writeCodePoint(COLON); - result.write(JSON.stringify(unchecked(values[end]))); - result.writeCodePoint(BRACE_RIGHT); - return result.toString(); -} + serialize(unchecked(keys[srcEnd])); + bs.ensureSize(2); + store(bs.offset, COLON); + bs.offset += 2; + serialize(unchecked(values[srcEnd])); + bs.ensureSize(2); + store(bs.offset, BRACE_RIGHT); + bs.offset += 2; +} \ No newline at end of file diff --git a/assembly/serialize/simple/string.ts b/assembly/serialize/simple/string.ts index fd6e12c..b66b70a 100644 --- a/assembly/serialize/simple/string.ts +++ b/assembly/serialize/simple/string.ts @@ -1,164 +1,54 @@ import { _intTo16 } from "../../custom/util"; -import { Sink } from "../../custom/sink"; +import { bytes } from "../../util/bytes"; +import { bs } from "../../custom/bs"; +import { BACK_SLASH, QUOTE } from "../../custom/chars"; +import { SERIALIZE_ESCAPE_TABLE } from "../../globals/tables"; /** * Serializes valid strings into their JSON counterpart - * @param data string - * @returns JSON + * @param src string + * @returns void */ // @ts-ignore: Decorator -@inline export function serializeString(data: string): string { - // if (!needsEscaping(data)) { - // return "\"" + data + "\""; - // } - - let result = Sink.fromString('"'); - - let last: i32 = 0; - for (let i = 0; i < data.length; i++) { - const char = load(changetype(data) + (i << 1)); - if (char === 34 || char === 92) { - result.write(data, last, i); - result.writeCodePoint(92); - last = i; - } else if (char < 32) { - if (char < 16) { - result.write(data, last, i); - last = i + 1; - switch (char) { - case 8: { - result.write("\\b"); - break; - } - case 9: { - result.write("\\t"); - break; - } - case 10: { - result.write("\\n"); - break; - } - case 12: { - result.write("\\f"); - break; - } - case 13: { - result.write("\\r"); - break; - } - default: { - // all chars 0-31 must be encoded as a four digit unicode escape sequence - // \u0000 to \u000f handled here - result.write("\\u000"); - result.write(char.toString(16)); - break; - } - } +@inline export function serializeString(src: string): void { + const srcSize = bytes(src); + // if (!bs.buffer) bs.setBuffer(__new(srcSize + 4, idof())); + // else + bs.ensureSize(srcSize + 4); + + let srcPtr = changetype(src); + + const srcEnd = srcPtr + srcSize; + + store(bs.offset, QUOTE); + + bs.offset += 2; + + let lastPtr: i32 = srcPtr; + while (srcPtr < srcEnd) { + const code = load(srcPtr); + if (code == 34 || code == 92 || code < 32) { + const remBytes = srcPtr - lastPtr; + memory.copy(bs.offset, lastPtr, remBytes); + bs.offset += remBytes; + const escaped = load(SERIALIZE_ESCAPE_TABLE + (code << 2)); + if ((escaped & 0xffff) != BACK_SLASH) { + bs.ensureCapacity(12); + store(bs.offset, 13511005048209500, 0); + store(bs.offset, escaped, 8); + bs.offset += 12; } else { - result.write(data, last, i); - last = i + 1; - // all chars 0-31 must be encoded as a four digit unicode escape sequence - // \u0010 to \u001f handled here - result.write("\\u00"); - result.write(char.toString(16)); + bs.ensureCapacity(4); + store(bs.offset, escaped, 0); + bs.offset += 4; } + lastPtr = srcPtr + 2; } + srcPtr += 2; } - result.write(data, last); - result.writeCodePoint(34); - return result.toString(); -} - -// import { _intTo16, nextPowerOf2 } from "../../custom/util"; -// import { OBJECT, TOTAL_OVERHEAD } from "rt/common"; - -// const ESCAPE_TABLE = memory.data([ -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 0-3 -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 4-7 - -// 92, 98, 92, 116, 92, 110, 0, 0, // Pair 8-11 -// 92, 102, 92, 114, 0, 0, 0, 0, // Pair 12-15 - -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 16-19 -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 20-23 - -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 24-27 -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 28-31 - -// 0, 0, 0, 0, 92, 34, 0, 0, // Pair 32-35 -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 36-39 - -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 40-43 -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 44-47 - -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 48-51 -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 52-55 - -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 56-59 -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 60-63 - -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 64-67 -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 68-71 - -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 72-75 -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 76-79 - -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 80-83 -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 84-87 - -// 0, 0, 0, 0, 0, 0, 0, 0, // Pair 88-91 -// 92, 92, 0, 0, 0, 0, 0, 0, // Pair 92-95 -// ]); - -// /** -// * Serializes valid strings into their JSON counterpart -// * @param src string -// * @returns JSON -// */ -// // @ts-ignore: Decorator -// @inline export function serializeString(src: string, dst: usize): string { -// const src_len = changetype(changetype(src) - TOTAL_OVERHEAD).rtSize; -// let dst_len: usize; -// let src_ptr = changetype(src); -// let dst_ptr = dst; - -// if (dst == 0) { -// dst_len = src_len + 4; -// dst = changetype(__new(dst_len, idof())); -// } else if (src_len + 4 > (dst_len = changetype(changetype(dst) - TOTAL_OVERHEAD).rtSize)) { -// const len = src_len + 4; -// dst_ptr = (dst = __renew(dst, len)); -// } - -// let src_end = src_ptr + src_len; - -// store(dst, 34); /* " */ - -// let last: usize = src_ptr; -// while (src_ptr < src_end) { -// const code = load(src_ptr); -// if (code == 34 || code == 92 || code < 32) { -// memory.copy(last, src_ptr - 2, dst_ptr - last); -// if (dst_ptr - dst > dst_len) { -// dst_ptr -= dst; -// dst_ptr += dst = __renew(dst, dst_len += 2); -// } -// const escaped = load(ESCAPE_TABLE + (code << 2)); -// store(dst_ptr, escaped); -// dst_ptr += 4; -// src_ptr += 2; -// last = dst_ptr; -// } else { -// dst_ptr += 2; -// src_ptr += 2; -// } -// } - -// store(dst_ptr, 34, 2); /* " */ - -// dst_ptr -= dst; -// if (dst_len > dst_ptr) { -// dst_ptr += dst = __renew(dst, max(4, dst_ptr)); -// } -// return changetype(dst); -// } + const remBytes = srcEnd - lastPtr; + memory.copy(bs.offset, lastPtr, remBytes); + bs.offset += remBytes; + store(bs.offset, QUOTE); + bs.offset += 2; +} \ No newline at end of file diff --git a/assembly/test.ts b/assembly/test.ts index adb568f..b301cea 100644 --- a/assembly/test.ts +++ b/assembly/test.ts @@ -1,25 +1,25 @@ -import { JSON } from "."; - -// import { Buffer } from "./custom/buffer"; -// import { serializeString_SIMD } from "./serialize/simd/string"; - -// @json -// class Vec3 { -// public x: i32 = 0; -// public y: i32 = 0; -// public z: T; -// } - -let a = "\u0000\u0001"; -let b = '"string \\"with random spa\\nces and \\nnewlines\\n\\n\\n"' -let c = "000000000000000000000000000000000000000"; +import { bs } from "./custom/bs"; +import { serialize } from "./serialize/simple"; +console.log(load(changetype("{}")).toString()) +// console.log(load(changetype("null")).toString()) +// serializeString("hell\"o"); +// console.log(bs.shrinkTo()); +bs.setBuffer(new ArrayBuffer(8)) +serialize(["hello","world"]); +console.log(bs.shrinkTo()); +const map = new Map(); +map.set("hello",new Date(0)); +map.set("foo",new Date(0)); +serialize(map); +console.log(bs.shrinkTo()) // JSON.stringifyTo(a, b) -c = JSON.parseTo(b, c); // console.log(JSON.stringifyTo(a, a)); -console.log("A: " + JSON.stringify(a).toString()); -console.log("B: " + b.toString()); -console.log("C: " + JSON.stringify(c)); +// console.log("A: " + JSON.stringify(a).toString()); +// console.log("B: " + b.toString()); +// console.log("C: " + JSON.stringify(c)); + +// console.log(JSON.stringify(null, "")) // console.log(new Vec3().__SERIALIZE()) @@ -47,4 +47,4 @@ console.log("C: " + JSON.stringify(c)); // const serialized = JSON.stringify(new Foo()); // console.log("Serialized: " + serialized); // const deserialized = JSON.parse(serialized); -// console.log("Deserialized: " + JSON.stringify(deserialized)); \ No newline at end of file +// console.log("Deserialized: " + JSON.stringify(deserialized)); diff --git a/assembly/util/bytes.ts b/assembly/util/bytes.ts new file mode 100644 index 0000000..b5bb9fc --- /dev/null +++ b/assembly/util/bytes.ts @@ -0,0 +1,12 @@ +import { OBJECT, TOTAL_OVERHEAD } from "rt/common"; + +// @ts-ignore: Decorator valid here +@inline export function bytes(o: T): i32 { + if (isInteger() || isFloat()) { + return sizeof(); + } else if (isManaged() || isReference()) { + return changetype(changetype(o) - TOTAL_OVERHEAD).rtSize; + } else { + ERROR("Cannot convert type " + nameof() + " to bytes!"); + } +} diff --git a/assembly/util/concat.ts b/assembly/util/concat.ts new file mode 100644 index 0000000..bed569f --- /dev/null +++ b/assembly/util/concat.ts @@ -0,0 +1,9 @@ +import { bytes } from "./bytes"; +export function concat(left: string, right: string): string { + const leftSize: usize = bytes(left); + const rightSize: usize = bytes(right); + const jointSize: usize = leftSize + rightSize; + const jointPtr = __renew(changetype(left), jointSize); + memory.copy(changetype(left) + leftSize, changetype(right), rightSize); + return changetype(jointPtr); +} diff --git a/assembly/util/nextPowerOf2.ts b/assembly/util/nextPowerOf2.ts new file mode 100644 index 0000000..45dd3a2 --- /dev/null +++ b/assembly/util/nextPowerOf2.ts @@ -0,0 +1,5 @@ + +// @ts-ignore: Decorator valid here +@inline export function nextPowerOf2(n: u32): u32 { + return 1 << (32 - clz(n - 1)); +} \ No newline at end of file diff --git a/index.ts b/index.ts index 5fb591f..67ead65 100644 --- a/index.ts +++ b/index.ts @@ -1 +1 @@ -export { JSON } from "./assembly/index"; \ No newline at end of file +export { JSON } from "./assembly/index"; diff --git a/package.json b/package.json index 0e9fd34..01f833e 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "scripts": { "test": "rm -rf ./build/ && ast test", "build:bench": "rm -rf ./build/ && asc assembly/__benches__/misc.bench.ts -o ./build/bench.wasm --textFile ./build/bench.wat --transform ./transform --optimizeLevel 3 --shrinkLevel 0 --converge --noAssert --uncheckedBehavior always --runtime stub --enable simd", - "build:test": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat -O3 --enable simd", + "build:test": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat -O3 --enable simd --enable bulk-memory", "build:transform": "tsc -p ./transform", "test:wasmtime": "wasmtime ./build/test.wasm", "test:wasmer": "wasmer ./build/test.wasm", diff --git a/transform/lib/builder.js b/transform/lib/builder.js index 1f9e05b..903a365 100644 --- a/transform/lib/builder.js +++ b/transform/lib/builder.js @@ -1,1352 +1,1266 @@ -import { isTypeOmitted, operatorTokenToString, util, } from "assemblyscript/dist/assemblyscript.js"; +import { isTypeOmitted, operatorTokenToString, util } from "assemblyscript/dist/assemblyscript.js"; import { Visitor } from "./visitor.js"; function assert(isTruish, message = "assertion error") { - if (!isTruish) - throw new Error(message); - return isTruish; + if (!isTruish) throw new Error(message); + return isTruish; } export class ASTBuilder extends Visitor { - static build(node) { - var builder = new ASTBuilder(); - builder.visitNode(node); - return builder.finish(); - } - sb = []; - indentLevel = 0; - visitNode(node) { - return this.visit(node); - } - visitSource(source) { - var statements = source.statements; - for (let i = 0, k = statements.length; i < k; ++i) { - this.visitNodeAndTerminate(statements[i]); - } - } - visitTypeNode(node) { - switch (node.kind) { - case 1: { - this.visitNamedTypeNode(node); - break; - } - case 2: { - this.visitFunctionTypeNode(node); - break; - } - default: - assert(false); - } - } - visitTypeName(node) { - this.visitIdentifierExpression(node.identifier); - var sb = this.sb; - var current = node.next; - while (current) { - sb.push("."); - this.visitIdentifierExpression(current.identifier); - current = current.next; - } - } - visitNamedTypeNode(node) { - this.visitTypeName(node.name); - var typeArguments = node.typeArguments; - if (typeArguments) { - let numTypeArguments = typeArguments.length; - let sb = this.sb; - if (numTypeArguments) { - sb.push("<"); - this.visitTypeNode(typeArguments[0]); - for (let i = 1; i < numTypeArguments; ++i) { - sb.push(", "); - this.visitTypeNode(typeArguments[i]); - } - sb.push(">"); - } - if (node.isNullable) - sb.push(" | null"); - } - } - visitFunctionTypeNode(node) { - var isNullable = node.isNullable; - var sb = this.sb; - sb.push(isNullable ? "((" : "("); - var explicitThisType = node.explicitThisType; - if (explicitThisType) { - sb.push("this: "); - this.visitTypeNode(explicitThisType); - } - var parameters = node.parameters; - var numParameters = parameters.length; - if (numParameters) { - if (explicitThisType) - sb.push(", "); - this.serializeParameter(parameters[0]); - for (let i = 1; i < numParameters; ++i) { - sb.push(", "); - this.serializeParameter(parameters[i]); - } - } - var returnType = node.returnType; - if (returnType) { - sb.push(") => "); - this.visitTypeNode(returnType); - } - else { - sb.push(") => void"); - } - if (isNullable) - sb.push(") | null"); - } - visitTypeParameter(node) { - this.visitIdentifierExpression(node.name); - var extendsType = node.extendsType; - if (extendsType) { - this.sb.push(" extends "); - this.visitTypeNode(extendsType); - } - var defaultType = node.defaultType; - if (defaultType) { - this.sb.push("="); - this.visitTypeNode(defaultType); - } - } - visitIdentifierExpression(node) { - if (node.isQuoted) - this.visitStringLiteral(node.text); - else - this.sb.push(node.text); - } - visitArrayLiteralExpression(node) { - var sb = this.sb; - sb.push("["); - var elements = node.elementExpressions; - var numElements = elements.length; - if (numElements) { - let element = elements[0]; - if (element) - this.visitNode(element); - for (let i = 1; i < numElements; ++i) { - element = elements[i]; - sb.push(", "); - if (element) - this.visitNode(element); - } - } - sb.push("]"); - } - visitObjectLiteralExpression(node) { - var sb = this.sb; - var names = node.names; - var values = node.values; - var numElements = names.length; - assert(numElements == values.length); - if (numElements) { - sb.push("{\n"); - util.indent(sb, ++this.indentLevel); - this.visitNode(names[0]); - sb.push(": "); - this.visitNode(values[0]); - for (let i = 1; i < numElements; ++i) { - sb.push(",\n"); - util.indent(sb, this.indentLevel); - let name = names[i]; - let value = values[i]; - if (name == value) { - this.visitNode(name); - } - else { - this.visitNode(name); - sb.push(": "); - this.visitNode(value); - } - } - sb.push("\n"); - util.indent(sb, --this.indentLevel); - sb.push("}"); - } - else { - sb.push("{}"); - } - } - visitAssertionExpression(node) { - var sb = this.sb; - switch (node.assertionKind) { - case 0: { - sb.push("<"); - if (node.toType) - this.visitTypeNode(node.toType); - sb.push(">"); - this.visitNode(node.expression); - break; - } - case 1: { - this.visitNode(node.expression); - sb.push(" as "); - if (node.toType) - this.visitTypeNode(node.toType); - break; - } - case 2: { - this.visitNode(node.expression); - sb.push("!"); - break; - } - case 3: { - this.visitNode(node.expression); - sb.push(" as const"); - break; - } - default: - assert(false); - } - } - visitBinaryExpression(node) { - var sb = this.sb; - this.visitNode(node.left); - sb.push(" "); - sb.push(operatorTokenToString(node.operator)); - sb.push(" "); - this.visitNode(node.right); - } - visitCallExpression(node) { + static build(node) { + var builder = new ASTBuilder(); + builder.visitNode(node); + return builder.finish(); + } + sb = []; + indentLevel = 0; + visitNode(node) { + return this.visit(node); + } + visitSource(source) { + var statements = source.statements; + for (let i = 0, k = statements.length; i < k; ++i) { + this.visitNodeAndTerminate(statements[i]); + } + } + visitTypeNode(node) { + switch (node.kind) { + case 1: { + this.visitNamedTypeNode(node); + break; + } + case 2: { + this.visitFunctionTypeNode(node); + break; + } + default: + assert(false); + } + } + visitTypeName(node) { + this.visitIdentifierExpression(node.identifier); + var sb = this.sb; + var current = node.next; + while (current) { + sb.push("."); + this.visitIdentifierExpression(current.identifier); + current = current.next; + } + } + visitNamedTypeNode(node) { + this.visitTypeName(node.name); + var typeArguments = node.typeArguments; + if (typeArguments) { + let numTypeArguments = typeArguments.length; + let sb = this.sb; + if (numTypeArguments) { + sb.push("<"); + this.visitTypeNode(typeArguments[0]); + for (let i = 1; i < numTypeArguments; ++i) { + sb.push(", "); + this.visitTypeNode(typeArguments[i]); + } + sb.push(">"); + } + if (node.isNullable) sb.push(" | null"); + } + } + visitFunctionTypeNode(node) { + var isNullable = node.isNullable; + var sb = this.sb; + sb.push(isNullable ? "((" : "("); + var explicitThisType = node.explicitThisType; + if (explicitThisType) { + sb.push("this: "); + this.visitTypeNode(explicitThisType); + } + var parameters = node.parameters; + var numParameters = parameters.length; + if (numParameters) { + if (explicitThisType) sb.push(", "); + this.serializeParameter(parameters[0]); + for (let i = 1; i < numParameters; ++i) { + sb.push(", "); + this.serializeParameter(parameters[i]); + } + } + var returnType = node.returnType; + if (returnType) { + sb.push(") => "); + this.visitTypeNode(returnType); + } else { + sb.push(") => void"); + } + if (isNullable) sb.push(") | null"); + } + visitTypeParameter(node) { + this.visitIdentifierExpression(node.name); + var extendsType = node.extendsType; + if (extendsType) { + this.sb.push(" extends "); + this.visitTypeNode(extendsType); + } + var defaultType = node.defaultType; + if (defaultType) { + this.sb.push("="); + this.visitTypeNode(defaultType); + } + } + visitIdentifierExpression(node) { + if (node.isQuoted) this.visitStringLiteral(node.text); + else this.sb.push(node.text); + } + visitArrayLiteralExpression(node) { + var sb = this.sb; + sb.push("["); + var elements = node.elementExpressions; + var numElements = elements.length; + if (numElements) { + let element = elements[0]; + if (element) this.visitNode(element); + for (let i = 1; i < numElements; ++i) { + element = elements[i]; + sb.push(", "); + if (element) this.visitNode(element); + } + } + sb.push("]"); + } + visitObjectLiteralExpression(node) { + var sb = this.sb; + var names = node.names; + var values = node.values; + var numElements = names.length; + assert(numElements == values.length); + if (numElements) { + sb.push("{\n"); + util.indent(sb, ++this.indentLevel); + this.visitNode(names[0]); + sb.push(": "); + this.visitNode(values[0]); + for (let i = 1; i < numElements; ++i) { + sb.push(",\n"); + util.indent(sb, this.indentLevel); + let name = names[i]; + let value = values[i]; + if (name == value) { + this.visitNode(name); + } else { + this.visitNode(name); + sb.push(": "); + this.visitNode(value); + } + } + sb.push("\n"); + util.indent(sb, --this.indentLevel); + sb.push("}"); + } else { + sb.push("{}"); + } + } + visitAssertionExpression(node) { + var sb = this.sb; + switch (node.assertionKind) { + case 0: { + sb.push("<"); + if (node.toType) this.visitTypeNode(node.toType); + sb.push(">"); this.visitNode(node.expression); - this.visitArguments(node.typeArguments, node.args); - } - visitArguments(typeArguments, args) { - var sb = this.sb; - if (typeArguments) { - let numTypeArguments = typeArguments.length; - if (numTypeArguments) { - sb.push("<"); - this.visitTypeNode(typeArguments[0]); - for (let i = 1; i < numTypeArguments; ++i) { - sb.push(", "); - this.visitTypeNode(typeArguments[i]); - } - sb.push(">("); - } - } - else { - sb.push("("); - } - var numArgs = args.length; - if (numArgs) { - this.visitNode(args[0]); - for (let i = 1; i < numArgs; ++i) { - sb.push(", "); - this.visitNode(args[i]); - } - } - sb.push(")"); - } - visitClassExpression(node) { - var declaration = node.declaration; - this.visitClassDeclaration(declaration); - } - visitCommaExpression(node) { - var expressions = node.expressions; - var numExpressions = expressions.length; - this.visitNode(expressions[0]); - var sb = this.sb; - for (let i = 1; i < numExpressions; ++i) { - sb.push(","); - this.visitNode(expressions[i]); - } - } - visitElementAccessExpression(node) { - var sb = this.sb; + break; + } + case 1: { this.visitNode(node.expression); - sb.push("["); - this.visitNode(node.elementExpression); - sb.push("]"); - } - visitFunctionExpression(node) { - var declaration = node.declaration; - if (!declaration.arrowKind) { - if (declaration.name.text.length) { - this.sb.push("function "); - } - else { - this.sb.push("function"); - } - } - else { - assert(declaration.name.text.length == 0); - } - this.visitFunctionCommon(declaration); - } - visitLiteralExpression(node) { - switch (node.literalKind) { - case 0: { - this.visitFloatLiteralExpression(node); - break; - } - case 1: { - this.visitIntegerLiteralExpression(node); - break; - } - case 2: { - this.visitStringLiteralExpression(node); - break; - } - case 3: { - this.visitTemplateLiteralExpression(node); - break; - } - case 4: { - this.visitRegexpLiteralExpression(node); - break; - } - case 5: { - this.visitArrayLiteralExpression(node); - break; - } - case 6: { - this.visitObjectLiteralExpression(node); - break; - } - default: { - assert(false); - break; - } - } - } - visitFloatLiteralExpression(node) { - this.sb.push(node.value.toString()); - } - visitInstanceOfExpression(node) { + sb.push(" as "); + if (node.toType) this.visitTypeNode(node.toType); + break; + } + case 2: { this.visitNode(node.expression); - this.sb.push(" instanceof "); - this.visitTypeNode(node.isType); - } - visitIntegerLiteralExpression(node) { - this.sb.push(i64_to_string(node.value)); - } - visitStringLiteral(str) { - var sb = this.sb; - sb.push('"'); - this.visitRawString(str, 34); - sb.push('"'); - } - visitRawString(str, quote) { - var sb = this.sb; - var off = 0; - var i = 0; - for (let k = str.length; i < k;) { - switch (str.charCodeAt(i)) { - case 0: { - if (i > off) - sb.push(str.substring(off, (off = i + 1))); - sb.push("\\0"); - off = ++i; - break; - } - case 92: { - if (i > off) - sb.push(str.substring(off, i)); - off = ++i; - sb.push("\\b"); - break; - } - case 9: { - if (i > off) - sb.push(str.substring(off, i)); - off = ++i; - sb.push("\\t"); - break; - } - case 10: { - if (i > off) - sb.push(str.substring(off, i)); - off = ++i; - sb.push("\\n"); - break; - } - case 11: { - if (i > off) - sb.push(str.substring(off, i)); - off = ++i; - sb.push("\\v"); - break; - } - case 12: { - if (i > off) - sb.push(str.substring(off, i)); - off = ++i; - sb.push("\\f"); - break; - } - case 13: { - if (i > off) - sb.push(str.substring(off, i)); - sb.push("\\r"); - off = ++i; - break; - } - case 34: { - if (quote == 34) { - if (i > off) - sb.push(str.substring(off, i)); - sb.push('\\"'); - off = ++i; - } - else { - ++i; - } - break; - } - case 39: { - if (quote == 39) { - if (i > off) - sb.push(str.substring(off, i)); - sb.push("\\'"); - off = ++i; - } - else { - ++i; - } - break; - } - case 92: { - if (i > off) - sb.push(str.substring(off, i)); - sb.push("\\\\"); - off = ++i; - break; - } - case 96: { - if (quote == 96) { - if (i > off) - sb.push(str.substring(off, i)); - sb.push("\\`"); - off = ++i; - } - else { - ++i; - } - break; - } - default: { - ++i; - break; - } - } - } - if (i > off) - sb.push(str.substring(off, i)); - } - visitStringLiteralExpression(node) { - this.visitStringLiteral(node.value); - } - visitTemplateLiteralExpression(node) { - var sb = this.sb; - var tag = node.tag; - var parts = node.parts; - var expressions = node.expressions; - if (tag) - this.visitNode(tag); - sb.push("`"); - this.visitRawString(parts[0], 96); - assert(parts.length == expressions.length + 1); - for (let i = 0, k = expressions.length; i < k; ++i) { - sb.push("${"); - this.visitNode(expressions[i]); - sb.push("}"); - this.visitRawString(parts[i + 1], 96); - } - sb.push("`"); - } - visitRegexpLiteralExpression(node) { - var sb = this.sb; - sb.push("/"); - sb.push(node.pattern); - sb.push("/"); - sb.push(node.patternFlags); - } - visitNewExpression(node) { - this.sb.push("new "); - this.visitTypeName(node.typeName); - this.visitArguments(node.typeArguments, node.args); - } - visitParenthesizedExpression(node) { - var sb = this.sb; - sb.push("("); + sb.push("!"); + break; + } + case 3: { this.visitNode(node.expression); - sb.push(")"); - } - visitPropertyAccessExpression(node) { - this.visitNode(node.expression); - this.sb.push("."); - this.visitIdentifierExpression(node.property); - } - visitTernaryExpression(node) { - var sb = this.sb; - this.visitNode(node.condition); - sb.push(" ? "); - this.visitNode(node.ifThen); - sb.push(" : "); - this.visitNode(node.ifElse); - } - visitUnaryExpression(node) { - switch (node.kind) { - case 27: { - this.visitUnaryPostfixExpression(node); - break; - } - case 28: { - this.visitUnaryPrefixExpression(node); - break; - } - default: - assert(false); - } - } - visitUnaryPostfixExpression(node) { - this.visitNode(node.operand); - this.sb.push(operatorTokenToString(node.operator)); - } - visitUnaryPrefixExpression(node) { - this.sb.push(operatorTokenToString(node.operator)); - this.visitNode(node.operand); - } - visitNodeAndTerminate(node) { - this.visitNode(node); - var sb = this.sb; - if (!sb.length || - node.kind == 47 || - node.kind == 38) { - sb.push(";\n"); - } - else { - let last = sb[sb.length - 1]; - let lastCharPos = last.length - 1; - if (lastCharPos >= 0 && - (last.charCodeAt(lastCharPos) == 125 || - last.charCodeAt(lastCharPos) == 59)) { - sb.push("\n"); - } - else { - sb.push(";\n"); - } - } - } - visitBlockStatement(node) { - var sb = this.sb; - var statements = node.statements; - var numStatements = statements.length; - if (numStatements) { - sb.push("{\n"); - let indentLevel = ++this.indentLevel; - for (let i = 0; i < numStatements; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(statements[i]); - } - util.indent(sb, --this.indentLevel); - sb.push("}"); - } - else { - sb.push("{}"); - } - } - visitBreakStatement(node) { - var label = node.label; - if (label) { - this.sb.push("break "); - this.visitIdentifierExpression(label); - } - else { - this.sb.push("break"); - } - } - visitContinueStatement(node) { - var label = node.label; - if (label) { - this.sb.push("continue "); - this.visitIdentifierExpression(label); - } - else { - this.sb.push("continue"); - } - } - visitClassDeclaration(node, isDefault = false) { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - var sb = this.sb; - if (isDefault) { - sb.push("export default "); - } - else { - this.serializeExternalModifiers(node); - } - if (node.is(128)) - sb.push("abstract "); - if (node.name.text.length) { - sb.push("class "); - this.visitIdentifierExpression(node.name); - } - else { - sb.push("class"); - } - var typeParameters = node.typeParameters; - if (typeParameters != null && typeParameters.length > 0) { - sb.push("<"); - this.visitTypeParameter(typeParameters[0]); - for (let i = 1, k = typeParameters.length; i < k; ++i) { - sb.push(", "); - this.visitTypeParameter(typeParameters[i]); - } - sb.push(">"); - } - var extendsType = node.extendsType; - if (extendsType) { - sb.push(" extends "); - this.visitTypeNode(extendsType); - } - var implementsTypes = node.implementsTypes; - if (implementsTypes) { - let numImplementsTypes = implementsTypes.length; - if (numImplementsTypes) { - sb.push(" implements "); - this.visitTypeNode(implementsTypes[0]); - for (let i = 1; i < numImplementsTypes; ++i) { - sb.push(", "); - this.visitTypeNode(implementsTypes[i]); - } - } - } - var indexSignature = node.indexSignature; - var members = node.members; - var numMembers = members.length; - if (indexSignature !== null || numMembers) { - sb.push(" {\n"); - let indentLevel = ++this.indentLevel; - if (indexSignature) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(indexSignature); - } - for (let i = 0, k = members.length; i < k; ++i) { - let member = members[i]; - if (member.kind != 54 || - member.parameterIndex < 0) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(member); - } - } - util.indent(sb, --this.indentLevel); - sb.push("}"); - } - else { - sb.push(" {}"); - } - } - visitDoStatement(node) { - var sb = this.sb; - sb.push("do "); - this.visitNode(node.body); - if (node.body.kind == 30) { - sb.push(" while ("); - } - else { - util.indent(sb, this.indentLevel); - sb.push("while ("); - } - this.visitNode(node.condition); - sb.push(")"); - } - visitEmptyStatement(node) { - } - visitEnumDeclaration(node, isDefault = false) { - var sb = this.sb; - if (isDefault) { - sb.push("export default "); - } - else { - this.serializeExternalModifiers(node); - } - if (node.is(8)) - sb.push("const "); - sb.push("enum "); - this.visitIdentifierExpression(node.name); - var values = node.values; - var numValues = values.length; - if (numValues) { - sb.push(" {\n"); - let indentLevel = ++this.indentLevel; - util.indent(sb, indentLevel); - this.visitEnumValueDeclaration(node.values[0]); - for (let i = 1; i < numValues; ++i) { - sb.push(",\n"); - util.indent(sb, indentLevel); - this.visitEnumValueDeclaration(node.values[i]); - } - sb.push("\n"); - util.indent(sb, --this.indentLevel); - sb.push("}"); - } - else { - sb.push(" {}"); - } - } - visitEnumValueDeclaration(node) { - this.visitIdentifierExpression(node.name); - var initializer = node.initializer; - if (initializer) { - this.sb.push(" = "); - this.visitNode(initializer); - } - } - visitExportImportStatement(node) { - var sb = this.sb; - sb.push("export import "); - this.visitIdentifierExpression(node.externalName); - sb.push(" = "); - this.visitIdentifierExpression(node.name); - } - visitExportMember(node) { - this.visitIdentifierExpression(node.localName); - if (node.exportedName.text != node.localName.text) { - this.sb.push(" as "); - this.visitIdentifierExpression(node.exportedName); - } - } - visitExportStatement(node) { - var sb = this.sb; - if (node.isDeclare) { - sb.push("declare "); - } - var members = node.members; - if (members == null) { - sb.push("export *"); - } - else if (members.length > 0) { - let numMembers = members.length; - sb.push("export {\n"); - let indentLevel = ++this.indentLevel; - util.indent(sb, indentLevel); - this.visitExportMember(members[0]); - for (let i = 1; i < numMembers; ++i) { - sb.push(",\n"); - util.indent(sb, indentLevel); - this.visitExportMember(members[i]); - } - --this.indentLevel; - sb.push("\n}"); - } - else { - sb.push("export {}"); - } - var path = node.path; - if (path) { - sb.push(" from "); - this.visitStringLiteralExpression(path); - } - sb.push(";"); - } - visitExportDefaultStatement(node) { - var declaration = node.declaration; - switch (declaration.kind) { - case 52: { - this.visitEnumDeclaration(declaration, true); - break; - } - case 55: { - this.visitFunctionDeclaration(declaration, true); - break; - } - case 51: { - this.visitClassDeclaration(declaration, true); - break; - } - case 57: { - this.visitInterfaceDeclaration(declaration, true); - break; - } - case 59: { - this.visitNamespaceDeclaration(declaration, true); - break; - } - default: - assert(false); - } - } - visitExpressionStatement(node) { - this.visitNode(node.expression); - } - visitFieldDeclaration(node) { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - this.serializeAccessModifiers(node); - this.visitIdentifierExpression(node.name); - var sb = this.sb; - if (node.flags & 16384) { - sb.push("!"); - } - var type = node.type; - if (type) { - sb.push(": "); - this.visitTypeNode(type); - } - var initializer = node.initializer; - if (initializer) { - sb.push(" = "); - this.visitNode(initializer); - } - } - visitForStatement(node) { - var sb = this.sb; - sb.push("for ("); - var initializer = node.initializer; - if (initializer) { - this.visitNode(initializer); - } - var condition = node.condition; - if (condition) { - sb.push("; "); - this.visitNode(condition); - } - else { - sb.push(";"); - } - var incrementor = node.incrementor; - if (incrementor) { - sb.push("; "); - this.visitNode(incrementor); - } - else { - sb.push(";"); - } - sb.push(") "); - this.visitNode(node.body); - } - visitForOfStatement(node) { - var sb = this.sb; - sb.push("for ("); - this.visitNode(node.variable); - sb.push(" of "); - this.visitNode(node.iterable); - sb.push(") "); - this.visitNode(node.body); - } - visitFunctionDeclaration(node, isDefault = false) { - var sb = this.sb; - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - if (isDefault) { - sb.push("export default "); - } - else { - this.serializeExternalModifiers(node); - this.serializeAccessModifiers(node); - } - if (node.name.text.length) { - sb.push("function "); - } - else { - sb.push("function"); - } - this.visitFunctionCommon(node); - } - visitFunctionCommon(node) { - var sb = this.sb; - this.visitIdentifierExpression(node.name); - var signature = node.signature; - var typeParameters = node.typeParameters; - if (typeParameters) { - let numTypeParameters = typeParameters.length; - if (numTypeParameters) { - sb.push("<"); - this.visitTypeParameter(typeParameters[0]); - for (let i = 1; i < numTypeParameters; ++i) { - sb.push(", "); - this.visitTypeParameter(typeParameters[i]); - } - sb.push(">"); - } - } + sb.push(" as const"); + break; + } + default: + assert(false); + } + } + visitBinaryExpression(node) { + var sb = this.sb; + this.visitNode(node.left); + sb.push(" "); + sb.push(operatorTokenToString(node.operator)); + sb.push(" "); + this.visitNode(node.right); + } + visitCallExpression(node) { + this.visitNode(node.expression); + this.visitArguments(node.typeArguments, node.args); + } + visitArguments(typeArguments, args) { + var sb = this.sb; + if (typeArguments) { + let numTypeArguments = typeArguments.length; + if (numTypeArguments) { + sb.push("<"); + this.visitTypeNode(typeArguments[0]); + for (let i = 1; i < numTypeArguments; ++i) { + sb.push(", "); + this.visitTypeNode(typeArguments[i]); + } + sb.push(">("); + } + } else { + sb.push("("); + } + var numArgs = args.length; + if (numArgs) { + this.visitNode(args[0]); + for (let i = 1; i < numArgs; ++i) { + sb.push(", "); + this.visitNode(args[i]); + } + } + sb.push(")"); + } + visitClassExpression(node) { + var declaration = node.declaration; + this.visitClassDeclaration(declaration); + } + visitCommaExpression(node) { + var expressions = node.expressions; + var numExpressions = expressions.length; + this.visitNode(expressions[0]); + var sb = this.sb; + for (let i = 1; i < numExpressions; ++i) { + sb.push(","); + this.visitNode(expressions[i]); + } + } + visitElementAccessExpression(node) { + var sb = this.sb; + this.visitNode(node.expression); + sb.push("["); + this.visitNode(node.elementExpression); + sb.push("]"); + } + visitFunctionExpression(node) { + var declaration = node.declaration; + if (!declaration.arrowKind) { + if (declaration.name.text.length) { + this.sb.push("function "); + } else { + this.sb.push("function"); + } + } else { + assert(declaration.name.text.length == 0); + } + this.visitFunctionCommon(declaration); + } + visitLiteralExpression(node) { + switch (node.literalKind) { + case 0: { + this.visitFloatLiteralExpression(node); + break; + } + case 1: { + this.visitIntegerLiteralExpression(node); + break; + } + case 2: { + this.visitStringLiteralExpression(node); + break; + } + case 3: { + this.visitTemplateLiteralExpression(node); + break; + } + case 4: { + this.visitRegexpLiteralExpression(node); + break; + } + case 5: { + this.visitArrayLiteralExpression(node); + break; + } + case 6: { + this.visitObjectLiteralExpression(node); + break; + } + default: { + assert(false); + break; + } + } + } + visitFloatLiteralExpression(node) { + this.sb.push(node.value.toString()); + } + visitInstanceOfExpression(node) { + this.visitNode(node.expression); + this.sb.push(" instanceof "); + this.visitTypeNode(node.isType); + } + visitIntegerLiteralExpression(node) { + this.sb.push(i64_to_string(node.value)); + } + visitStringLiteral(str) { + var sb = this.sb; + sb.push('"'); + this.visitRawString(str, 34); + sb.push('"'); + } + visitRawString(str, quote) { + var sb = this.sb; + var off = 0; + var i = 0; + for (let k = str.length; i < k; ) { + switch (str.charCodeAt(i)) { + case 0: { + if (i > off) sb.push(str.substring(off, (off = i + 1))); + sb.push("\\0"); + off = ++i; + break; + } + case 92: { + if (i > off) sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\b"); + break; + } + case 9: { + if (i > off) sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\t"); + break; + } + case 10: { + if (i > off) sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\n"); + break; + } + case 11: { + if (i > off) sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\v"); + break; + } + case 12: { + if (i > off) sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\f"); + break; + } + case 13: { + if (i > off) sb.push(str.substring(off, i)); + sb.push("\\r"); + off = ++i; + break; + } + case 34: { + if (quote == 34) { + if (i > off) sb.push(str.substring(off, i)); + sb.push('\\"'); + off = ++i; + } else { + ++i; + } + break; + } + case 39: { + if (quote == 39) { + if (i > off) sb.push(str.substring(off, i)); + sb.push("\\'"); + off = ++i; + } else { + ++i; + } + break; + } + case 92: { + if (i > off) sb.push(str.substring(off, i)); + sb.push("\\\\"); + off = ++i; + break; + } + case 96: { + if (quote == 96) { + if (i > off) sb.push(str.substring(off, i)); + sb.push("\\`"); + off = ++i; + } else { + ++i; + } + break; + } + default: { + ++i; + break; + } + } + } + if (i > off) sb.push(str.substring(off, i)); + } + visitStringLiteralExpression(node) { + this.visitStringLiteral(node.value); + } + visitTemplateLiteralExpression(node) { + var sb = this.sb; + var tag = node.tag; + var parts = node.parts; + var expressions = node.expressions; + if (tag) this.visitNode(tag); + sb.push("`"); + this.visitRawString(parts[0], 96); + assert(parts.length == expressions.length + 1); + for (let i = 0, k = expressions.length; i < k; ++i) { + sb.push("${"); + this.visitNode(expressions[i]); + sb.push("}"); + this.visitRawString(parts[i + 1], 96); + } + sb.push("`"); + } + visitRegexpLiteralExpression(node) { + var sb = this.sb; + sb.push("/"); + sb.push(node.pattern); + sb.push("/"); + sb.push(node.patternFlags); + } + visitNewExpression(node) { + this.sb.push("new "); + this.visitTypeName(node.typeName); + this.visitArguments(node.typeArguments, node.args); + } + visitParenthesizedExpression(node) { + var sb = this.sb; + sb.push("("); + this.visitNode(node.expression); + sb.push(")"); + } + visitPropertyAccessExpression(node) { + this.visitNode(node.expression); + this.sb.push("."); + this.visitIdentifierExpression(node.property); + } + visitTernaryExpression(node) { + var sb = this.sb; + this.visitNode(node.condition); + sb.push(" ? "); + this.visitNode(node.ifThen); + sb.push(" : "); + this.visitNode(node.ifElse); + } + visitUnaryExpression(node) { + switch (node.kind) { + case 27: { + this.visitUnaryPostfixExpression(node); + break; + } + case 28: { + this.visitUnaryPrefixExpression(node); + break; + } + default: + assert(false); + } + } + visitUnaryPostfixExpression(node) { + this.visitNode(node.operand); + this.sb.push(operatorTokenToString(node.operator)); + } + visitUnaryPrefixExpression(node) { + this.sb.push(operatorTokenToString(node.operator)); + this.visitNode(node.operand); + } + visitNodeAndTerminate(node) { + this.visitNode(node); + var sb = this.sb; + if (!sb.length || node.kind == 47 || node.kind == 38) { + sb.push(";\n"); + } else { + let last = sb[sb.length - 1]; + let lastCharPos = last.length - 1; + if (lastCharPos >= 0 && (last.charCodeAt(lastCharPos) == 125 || last.charCodeAt(lastCharPos) == 59)) { + sb.push("\n"); + } else { + sb.push(";\n"); + } + } + } + visitBlockStatement(node) { + var sb = this.sb; + var statements = node.statements; + var numStatements = statements.length; + if (numStatements) { + sb.push("{\n"); + let indentLevel = ++this.indentLevel; + for (let i = 0; i < numStatements; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(statements[i]); + } + util.indent(sb, --this.indentLevel); + sb.push("}"); + } else { + sb.push("{}"); + } + } + visitBreakStatement(node) { + var label = node.label; + if (label) { + this.sb.push("break "); + this.visitIdentifierExpression(label); + } else { + this.sb.push("break"); + } + } + visitContinueStatement(node) { + var label = node.label; + if (label) { + this.sb.push("continue "); + this.visitIdentifierExpression(label); + } else { + this.sb.push("continue"); + } + } + visitClassDeclaration(node, isDefault = false) { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + var sb = this.sb; + if (isDefault) { + sb.push("export default "); + } else { + this.serializeExternalModifiers(node); + } + if (node.is(128)) sb.push("abstract "); + if (node.name.text.length) { + sb.push("class "); + this.visitIdentifierExpression(node.name); + } else { + sb.push("class"); + } + var typeParameters = node.typeParameters; + if (typeParameters != null && typeParameters.length > 0) { + sb.push("<"); + this.visitTypeParameter(typeParameters[0]); + for (let i = 1, k = typeParameters.length; i < k; ++i) { + sb.push(", "); + this.visitTypeParameter(typeParameters[i]); + } + sb.push(">"); + } + var extendsType = node.extendsType; + if (extendsType) { + sb.push(" extends "); + this.visitTypeNode(extendsType); + } + var implementsTypes = node.implementsTypes; + if (implementsTypes) { + let numImplementsTypes = implementsTypes.length; + if (numImplementsTypes) { + sb.push(" implements "); + this.visitTypeNode(implementsTypes[0]); + for (let i = 1; i < numImplementsTypes; ++i) { + sb.push(", "); + this.visitTypeNode(implementsTypes[i]); + } + } + } + var indexSignature = node.indexSignature; + var members = node.members; + var numMembers = members.length; + if (indexSignature !== null || numMembers) { + sb.push(" {\n"); + let indentLevel = ++this.indentLevel; + if (indexSignature) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(indexSignature); + } + for (let i = 0, k = members.length; i < k; ++i) { + let member = members[i]; + if (member.kind != 54 || member.parameterIndex < 0) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(member); + } + } + util.indent(sb, --this.indentLevel); + sb.push("}"); + } else { + sb.push(" {}"); + } + } + visitDoStatement(node) { + var sb = this.sb; + sb.push("do "); + this.visitNode(node.body); + if (node.body.kind == 30) { + sb.push(" while ("); + } else { + util.indent(sb, this.indentLevel); + sb.push("while ("); + } + this.visitNode(node.condition); + sb.push(")"); + } + visitEmptyStatement(node) {} + visitEnumDeclaration(node, isDefault = false) { + var sb = this.sb; + if (isDefault) { + sb.push("export default "); + } else { + this.serializeExternalModifiers(node); + } + if (node.is(8)) sb.push("const "); + sb.push("enum "); + this.visitIdentifierExpression(node.name); + var values = node.values; + var numValues = values.length; + if (numValues) { + sb.push(" {\n"); + let indentLevel = ++this.indentLevel; + util.indent(sb, indentLevel); + this.visitEnumValueDeclaration(node.values[0]); + for (let i = 1; i < numValues; ++i) { + sb.push(",\n"); + util.indent(sb, indentLevel); + this.visitEnumValueDeclaration(node.values[i]); + } + sb.push("\n"); + util.indent(sb, --this.indentLevel); + sb.push("}"); + } else { + sb.push(" {}"); + } + } + visitEnumValueDeclaration(node) { + this.visitIdentifierExpression(node.name); + var initializer = node.initializer; + if (initializer) { + this.sb.push(" = "); + this.visitNode(initializer); + } + } + visitExportImportStatement(node) { + var sb = this.sb; + sb.push("export import "); + this.visitIdentifierExpression(node.externalName); + sb.push(" = "); + this.visitIdentifierExpression(node.name); + } + visitExportMember(node) { + this.visitIdentifierExpression(node.localName); + if (node.exportedName.text != node.localName.text) { + this.sb.push(" as "); + this.visitIdentifierExpression(node.exportedName); + } + } + visitExportStatement(node) { + var sb = this.sb; + if (node.isDeclare) { + sb.push("declare "); + } + var members = node.members; + if (members == null) { + sb.push("export *"); + } else if (members.length > 0) { + let numMembers = members.length; + sb.push("export {\n"); + let indentLevel = ++this.indentLevel; + util.indent(sb, indentLevel); + this.visitExportMember(members[0]); + for (let i = 1; i < numMembers; ++i) { + sb.push(",\n"); + util.indent(sb, indentLevel); + this.visitExportMember(members[i]); + } + --this.indentLevel; + sb.push("\n}"); + } else { + sb.push("export {}"); + } + var path = node.path; + if (path) { + sb.push(" from "); + this.visitStringLiteralExpression(path); + } + sb.push(";"); + } + visitExportDefaultStatement(node) { + var declaration = node.declaration; + switch (declaration.kind) { + case 52: { + this.visitEnumDeclaration(declaration, true); + break; + } + case 55: { + this.visitFunctionDeclaration(declaration, true); + break; + } + case 51: { + this.visitClassDeclaration(declaration, true); + break; + } + case 57: { + this.visitInterfaceDeclaration(declaration, true); + break; + } + case 59: { + this.visitNamespaceDeclaration(declaration, true); + break; + } + default: + assert(false); + } + } + visitExpressionStatement(node) { + this.visitNode(node.expression); + } + visitFieldDeclaration(node) { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + this.serializeAccessModifiers(node); + this.visitIdentifierExpression(node.name); + var sb = this.sb; + if (node.flags & 16384) { + sb.push("!"); + } + var type = node.type; + if (type) { + sb.push(": "); + this.visitTypeNode(type); + } + var initializer = node.initializer; + if (initializer) { + sb.push(" = "); + this.visitNode(initializer); + } + } + visitForStatement(node) { + var sb = this.sb; + sb.push("for ("); + var initializer = node.initializer; + if (initializer) { + this.visitNode(initializer); + } + var condition = node.condition; + if (condition) { + sb.push("; "); + this.visitNode(condition); + } else { + sb.push(";"); + } + var incrementor = node.incrementor; + if (incrementor) { + sb.push("; "); + this.visitNode(incrementor); + } else { + sb.push(";"); + } + sb.push(") "); + this.visitNode(node.body); + } + visitForOfStatement(node) { + var sb = this.sb; + sb.push("for ("); + this.visitNode(node.variable); + sb.push(" of "); + this.visitNode(node.iterable); + sb.push(") "); + this.visitNode(node.body); + } + visitFunctionDeclaration(node, isDefault = false) { + var sb = this.sb; + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + if (isDefault) { + sb.push("export default "); + } else { + this.serializeExternalModifiers(node); + this.serializeAccessModifiers(node); + } + if (node.name.text.length) { + sb.push("function "); + } else { + sb.push("function"); + } + this.visitFunctionCommon(node); + } + visitFunctionCommon(node) { + var sb = this.sb; + this.visitIdentifierExpression(node.name); + var signature = node.signature; + var typeParameters = node.typeParameters; + if (typeParameters) { + let numTypeParameters = typeParameters.length; + if (numTypeParameters) { + sb.push("<"); + this.visitTypeParameter(typeParameters[0]); + for (let i = 1; i < numTypeParameters; ++i) { + sb.push(", "); + this.visitTypeParameter(typeParameters[i]); + } + sb.push(">"); + } + } + if (node.arrowKind == 2) { + let parameters = signature.parameters; + assert(parameters.length == 1); + assert(!signature.explicitThisType); + this.serializeParameter(parameters[0]); + } else { + sb.push("("); + let parameters = signature.parameters; + let numParameters = parameters.length; + let explicitThisType = signature.explicitThisType; + if (explicitThisType) { + sb.push("this: "); + this.visitTypeNode(explicitThisType); + } + if (numParameters) { + if (explicitThisType) sb.push(", "); + this.serializeParameter(parameters[0]); + for (let i = 1; i < numParameters; ++i) { + sb.push(", "); + this.serializeParameter(parameters[i]); + } + } + } + var body = node.body; + var returnType = signature.returnType; + if (node.arrowKind) { + if (body) { if (node.arrowKind == 2) { - let parameters = signature.parameters; - assert(parameters.length == 1); - assert(!signature.explicitThisType); - this.serializeParameter(parameters[0]); - } - else { - sb.push("("); - let parameters = signature.parameters; - let numParameters = parameters.length; - let explicitThisType = signature.explicitThisType; - if (explicitThisType) { - sb.push("this: "); - this.visitTypeNode(explicitThisType); - } - if (numParameters) { - if (explicitThisType) - sb.push(", "); - this.serializeParameter(parameters[0]); - for (let i = 1; i < numParameters; ++i) { - sb.push(", "); - this.serializeParameter(parameters[i]); - } - } - } - var body = node.body; - var returnType = signature.returnType; - if (node.arrowKind) { - if (body) { - if (node.arrowKind == 2) { - assert(isTypeOmitted(returnType)); - } - else { - if (isTypeOmitted(returnType)) { - sb.push(")"); - } - else { - sb.push("): "); - this.visitTypeNode(returnType); - } - } - sb.push(" => "); - this.visitNode(body); - } - else { - assert(!isTypeOmitted(returnType)); - sb.push(" => "); - this.visitTypeNode(returnType); - } - } - else { - if (!isTypeOmitted(returnType) && - !node.isAny(524288 | 4096)) { - sb.push("): "); - this.visitTypeNode(returnType); - } - else { - sb.push(")"); - } - if (body) { - sb.push(" "); - this.visitNode(body); - } - } - } - visitIfStatement(node) { - var sb = this.sb; - sb.push("if ("); - this.visitNode(node.condition); - sb.push(") "); - var ifTrue = node.ifTrue; - this.visitNode(ifTrue); - if (ifTrue.kind != 30) { - sb.push(";\n"); - } - var ifFalse = node.ifFalse; - if (ifFalse) { - if (ifTrue.kind == 30) { - sb.push(" else "); - } - else { - sb.push("else "); - } - this.visitNode(ifFalse); - } - } - visitImportDeclaration(node) { - var externalName = node.foreignName; - var name = node.name; - this.visitIdentifierExpression(externalName); - if (externalName.text != name.text) { - this.sb.push(" as "); - this.visitIdentifierExpression(name); - } - } - visitImportStatement(node) { - var sb = this.sb; - sb.push("import "); - var declarations = node.declarations; - var namespaceName = node.namespaceName; - if (declarations) { - let numDeclarations = declarations.length; - if (numDeclarations) { - sb.push("{\n"); - let indentLevel = ++this.indentLevel; - util.indent(sb, indentLevel); - this.visitImportDeclaration(declarations[0]); - for (let i = 1; i < numDeclarations; ++i) { - sb.push(",\n"); - util.indent(sb, indentLevel); - this.visitImportDeclaration(declarations[i]); - } - --this.indentLevel; - sb.push("\n} from "); - } - else { - sb.push("{} from "); - } - } - else if (namespaceName) { - sb.push("* as "); - this.visitIdentifierExpression(namespaceName); - sb.push(" from "); - } - this.visitStringLiteralExpression(node.path); - } - visitIndexSignature(node) { - var sb = this.sb; - sb.push("[key: "); - this.visitTypeNode(node.keyType); - sb.push("]: "); - this.visitTypeNode(node.valueType); - } - visitInterfaceDeclaration(node, isDefault = false) { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - var sb = this.sb; - if (isDefault) { - sb.push("export default "); - } - else { - this.serializeExternalModifiers(node); - } - sb.push("interface "); - this.visitIdentifierExpression(node.name); - var typeParameters = node.typeParameters; - if (typeParameters != null && typeParameters.length > 0) { - sb.push("<"); - this.visitTypeParameter(typeParameters[0]); - for (let i = 1, k = typeParameters.length; i < k; ++i) { - sb.push(", "); - this.visitTypeParameter(typeParameters[i]); - } - sb.push(">"); - } - var extendsType = node.extendsType; - if (extendsType) { - sb.push(" extends "); - this.visitTypeNode(extendsType); - } - sb.push(" {\n"); - var indentLevel = ++this.indentLevel; - var members = node.members; - for (let i = 0, k = members.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(members[i]); - } - --this.indentLevel; - sb.push("}"); - } - visitMethodDeclaration(node) { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - this.serializeAccessModifiers(node); - if (node.is(2048)) { - this.sb.push("get "); - } - else if (node.is(4096)) { - this.sb.push("set "); - } - this.visitFunctionCommon(node); - } - visitNamespaceDeclaration(node, isDefault = false) { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - var sb = this.sb; - if (isDefault) { - sb.push("export default "); - } - else { - this.serializeExternalModifiers(node); - } - sb.push("namespace "); - this.visitIdentifierExpression(node.name); - var members = node.members; - var numMembers = members.length; - if (numMembers) { - sb.push(" {\n"); - let indentLevel = ++this.indentLevel; - for (let i = 0, k = members.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(members[i]); - } - util.indent(sb, --this.indentLevel); - sb.push("}"); - } - else { - sb.push(" {}"); - } - } - visitReturnStatement(node) { - var value = node.value; - if (value) { - this.sb.push("return "); - this.visitNode(value); - } - else { - this.sb.push("return"); - } - } - visitSwitchCase(node) { - var sb = this.sb; - var label = node.label; - if (label) { - sb.push("case "); - this.visitNode(label); - sb.push(":\n"); - } - else { - sb.push("default:\n"); - } - var statements = node.statements; - var numStatements = statements.length; - if (numStatements) { - let indentLevel = ++this.indentLevel; - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(statements[0]); - for (let i = 1; i < numStatements; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(statements[i]); - } - --this.indentLevel; - } - } - visitSwitchStatement(node) { - var sb = this.sb; - sb.push("switch ("); - this.visitNode(node.condition); - sb.push(") {\n"); - var indentLevel = ++this.indentLevel; - var cases = node.cases; - for (let i = 0, k = cases.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitSwitchCase(cases[i]); - sb.push("\n"); - } - --this.indentLevel; - sb.push("}"); - } - visitThrowStatement(node) { - this.sb.push("throw "); - this.visitNode(node.value); - } - visitTryStatement(node) { - var sb = this.sb; - sb.push("try {\n"); - var indentLevel = ++this.indentLevel; - var statements = node.bodyStatements; - for (let i = 0, k = statements.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(statements[i]); - } - var catchVariable = node.catchVariable; - if (catchVariable) { - util.indent(sb, indentLevel - 1); - sb.push("} catch ("); - this.visitIdentifierExpression(catchVariable); - sb.push(") {\n"); - let catchStatements = node.catchStatements; - if (catchStatements) { - for (let i = 0, k = catchStatements.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(catchStatements[i]); - } - } - } - var finallyStatements = node.finallyStatements; - if (finallyStatements) { - util.indent(sb, indentLevel - 1); - sb.push("} finally {\n"); - for (let i = 0, k = finallyStatements.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(finallyStatements[i]); - } - } - util.indent(sb, indentLevel - 1); - sb.push("}"); - } - visitTypeDeclaration(node) { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - var sb = this.sb; - this.serializeExternalModifiers(node); - sb.push("type "); - this.visitIdentifierExpression(node.name); - var typeParameters = node.typeParameters; - if (typeParameters) { - let numTypeParameters = typeParameters.length; - if (numTypeParameters) { - sb.push("<"); - for (let i = 0; i < numTypeParameters; ++i) { - this.visitTypeParameter(typeParameters[i]); - } - sb.push(">"); - } - } - sb.push(" = "); - this.visitTypeNode(node.type); - } - visitVariableDeclaration(node) { - this.visitIdentifierExpression(node.name); - var type = node.type; - var sb = this.sb; - if (node.flags & 16384) { - sb.push("!"); - } - if (type) { - sb.push(": "); - this.visitTypeNode(type); - } - var initializer = node.initializer; - if (initializer) { - sb.push(" = "); - this.visitNode(initializer); - } - } - visitVariableStatement(node) { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - var sb = this.sb; - var declarations = node.declarations; - var numDeclarations = declarations.length; - var firstDeclaration = declarations[0]; - this.serializeExternalModifiers(firstDeclaration); - sb.push(firstDeclaration.is(8) - ? "const " - : firstDeclaration.is(16) - ? "let " - : "var "); - this.visitVariableDeclaration(node.declarations[0]); - for (let i = 1; i < numDeclarations; ++i) { - sb.push(", "); - this.visitVariableDeclaration(node.declarations[i]); - } - } - visitWhileStatement(node) { - var sb = this.sb; - sb.push("while ("); - this.visitNode(node.condition); - var statement = node.body; - if (statement.kind == 34) { + assert(isTypeOmitted(returnType)); + } else { + if (isTypeOmitted(returnType)) { sb.push(")"); + } else { + sb.push("): "); + this.visitTypeNode(returnType); + } + } + sb.push(" => "); + this.visitNode(body); + } else { + assert(!isTypeOmitted(returnType)); + sb.push(" => "); + this.visitTypeNode(returnType); + } + } else { + if (!isTypeOmitted(returnType) && !node.isAny(524288 | 4096)) { + sb.push("): "); + this.visitTypeNode(returnType); + } else { + sb.push(")"); + } + if (body) { + sb.push(" "); + this.visitNode(body); + } + } + } + visitIfStatement(node) { + var sb = this.sb; + sb.push("if ("); + this.visitNode(node.condition); + sb.push(") "); + var ifTrue = node.ifTrue; + this.visitNode(ifTrue); + if (ifTrue.kind != 30) { + sb.push(";\n"); + } + var ifFalse = node.ifFalse; + if (ifFalse) { + if (ifTrue.kind == 30) { + sb.push(" else "); + } else { + sb.push("else "); + } + this.visitNode(ifFalse); + } + } + visitImportDeclaration(node) { + var externalName = node.foreignName; + var name = node.name; + this.visitIdentifierExpression(externalName); + if (externalName.text != name.text) { + this.sb.push(" as "); + this.visitIdentifierExpression(name); + } + } + visitImportStatement(node) { + var sb = this.sb; + sb.push("import "); + var declarations = node.declarations; + var namespaceName = node.namespaceName; + if (declarations) { + let numDeclarations = declarations.length; + if (numDeclarations) { + sb.push("{\n"); + let indentLevel = ++this.indentLevel; + util.indent(sb, indentLevel); + this.visitImportDeclaration(declarations[0]); + for (let i = 1; i < numDeclarations; ++i) { + sb.push(",\n"); + util.indent(sb, indentLevel); + this.visitImportDeclaration(declarations[i]); } - else { - sb.push(") "); - this.visitNode(node.body); - } - } - serializeDecorator(node) { - var sb = this.sb; - sb.push("@"); - this.visitNode(node.name); - var args = node.args; - if (args) { - sb.push("("); - let numArgs = args.length; - if (numArgs) { - this.visitNode(args[0]); - for (let i = 1; i < numArgs; ++i) { - sb.push(", "); - this.visitNode(args[i]); - } - } - sb.push(")\n"); - } - else { - sb.push("\n"); - } - util.indent(sb, this.indentLevel); - } - serializeParameter(node) { - var sb = this.sb; - var kind = node.parameterKind; - var implicitFieldDeclaration = node.implicitFieldDeclaration; - if (implicitFieldDeclaration) { - this.serializeAccessModifiers(implicitFieldDeclaration); - } - if (kind == 2) { - sb.push("..."); - } - this.visitIdentifierExpression(node.name); - var type = node.type; - var initializer = node.initializer; - if (type) { - if (kind == 1 && !initializer) - sb.push("?"); - if (!isTypeOmitted(type)) { - sb.push(": "); - this.visitTypeNode(type); - } - } - if (initializer) { - sb.push(" = "); - this.visitNode(initializer); - } - } - serializeExternalModifiers(node) { - var sb = this.sb; - if (node.is(2)) { - sb.push("export "); - } - else if (node.is(1)) { - sb.push("import "); - } - else if (node.is(4)) { - sb.push("declare "); - } - } - serializeAccessModifiers(node) { - var sb = this.sb; - if (node.is(256)) { - sb.push("public "); - } - else if (node.is(512)) { - sb.push("private "); - } - else if (node.is(1024)) { - sb.push("protected "); - } - if (node.is(32)) { - sb.push("static "); - } - else if (node.is(128)) { - sb.push("abstract "); - } - if (node.is(64)) { - sb.push("readonly "); - } - } - finish() { - var ret = this.sb.join(""); - this.sb = []; - return ret; - } + --this.indentLevel; + sb.push("\n} from "); + } else { + sb.push("{} from "); + } + } else if (namespaceName) { + sb.push("* as "); + this.visitIdentifierExpression(namespaceName); + sb.push(" from "); + } + this.visitStringLiteralExpression(node.path); + } + visitIndexSignature(node) { + var sb = this.sb; + sb.push("[key: "); + this.visitTypeNode(node.keyType); + sb.push("]: "); + this.visitTypeNode(node.valueType); + } + visitInterfaceDeclaration(node, isDefault = false) { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + var sb = this.sb; + if (isDefault) { + sb.push("export default "); + } else { + this.serializeExternalModifiers(node); + } + sb.push("interface "); + this.visitIdentifierExpression(node.name); + var typeParameters = node.typeParameters; + if (typeParameters != null && typeParameters.length > 0) { + sb.push("<"); + this.visitTypeParameter(typeParameters[0]); + for (let i = 1, k = typeParameters.length; i < k; ++i) { + sb.push(", "); + this.visitTypeParameter(typeParameters[i]); + } + sb.push(">"); + } + var extendsType = node.extendsType; + if (extendsType) { + sb.push(" extends "); + this.visitTypeNode(extendsType); + } + sb.push(" {\n"); + var indentLevel = ++this.indentLevel; + var members = node.members; + for (let i = 0, k = members.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(members[i]); + } + --this.indentLevel; + sb.push("}"); + } + visitMethodDeclaration(node) { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + this.serializeAccessModifiers(node); + if (node.is(2048)) { + this.sb.push("get "); + } else if (node.is(4096)) { + this.sb.push("set "); + } + this.visitFunctionCommon(node); + } + visitNamespaceDeclaration(node, isDefault = false) { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + var sb = this.sb; + if (isDefault) { + sb.push("export default "); + } else { + this.serializeExternalModifiers(node); + } + sb.push("namespace "); + this.visitIdentifierExpression(node.name); + var members = node.members; + var numMembers = members.length; + if (numMembers) { + sb.push(" {\n"); + let indentLevel = ++this.indentLevel; + for (let i = 0, k = members.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(members[i]); + } + util.indent(sb, --this.indentLevel); + sb.push("}"); + } else { + sb.push(" {}"); + } + } + visitReturnStatement(node) { + var value = node.value; + if (value) { + this.sb.push("return "); + this.visitNode(value); + } else { + this.sb.push("return"); + } + } + visitSwitchCase(node) { + var sb = this.sb; + var label = node.label; + if (label) { + sb.push("case "); + this.visitNode(label); + sb.push(":\n"); + } else { + sb.push("default:\n"); + } + var statements = node.statements; + var numStatements = statements.length; + if (numStatements) { + let indentLevel = ++this.indentLevel; + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(statements[0]); + for (let i = 1; i < numStatements; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(statements[i]); + } + --this.indentLevel; + } + } + visitSwitchStatement(node) { + var sb = this.sb; + sb.push("switch ("); + this.visitNode(node.condition); + sb.push(") {\n"); + var indentLevel = ++this.indentLevel; + var cases = node.cases; + for (let i = 0, k = cases.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitSwitchCase(cases[i]); + sb.push("\n"); + } + --this.indentLevel; + sb.push("}"); + } + visitThrowStatement(node) { + this.sb.push("throw "); + this.visitNode(node.value); + } + visitTryStatement(node) { + var sb = this.sb; + sb.push("try {\n"); + var indentLevel = ++this.indentLevel; + var statements = node.bodyStatements; + for (let i = 0, k = statements.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(statements[i]); + } + var catchVariable = node.catchVariable; + if (catchVariable) { + util.indent(sb, indentLevel - 1); + sb.push("} catch ("); + this.visitIdentifierExpression(catchVariable); + sb.push(") {\n"); + let catchStatements = node.catchStatements; + if (catchStatements) { + for (let i = 0, k = catchStatements.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(catchStatements[i]); + } + } + } + var finallyStatements = node.finallyStatements; + if (finallyStatements) { + util.indent(sb, indentLevel - 1); + sb.push("} finally {\n"); + for (let i = 0, k = finallyStatements.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(finallyStatements[i]); + } + } + util.indent(sb, indentLevel - 1); + sb.push("}"); + } + visitTypeDeclaration(node) { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + var sb = this.sb; + this.serializeExternalModifiers(node); + sb.push("type "); + this.visitIdentifierExpression(node.name); + var typeParameters = node.typeParameters; + if (typeParameters) { + let numTypeParameters = typeParameters.length; + if (numTypeParameters) { + sb.push("<"); + for (let i = 0; i < numTypeParameters; ++i) { + this.visitTypeParameter(typeParameters[i]); + } + sb.push(">"); + } + } + sb.push(" = "); + this.visitTypeNode(node.type); + } + visitVariableDeclaration(node) { + this.visitIdentifierExpression(node.name); + var type = node.type; + var sb = this.sb; + if (node.flags & 16384) { + sb.push("!"); + } + if (type) { + sb.push(": "); + this.visitTypeNode(type); + } + var initializer = node.initializer; + if (initializer) { + sb.push(" = "); + this.visitNode(initializer); + } + } + visitVariableStatement(node) { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + var sb = this.sb; + var declarations = node.declarations; + var numDeclarations = declarations.length; + var firstDeclaration = declarations[0]; + this.serializeExternalModifiers(firstDeclaration); + sb.push(firstDeclaration.is(8) ? "const " : firstDeclaration.is(16) ? "let " : "var "); + this.visitVariableDeclaration(node.declarations[0]); + for (let i = 1; i < numDeclarations; ++i) { + sb.push(", "); + this.visitVariableDeclaration(node.declarations[i]); + } + } + visitWhileStatement(node) { + var sb = this.sb; + sb.push("while ("); + this.visitNode(node.condition); + var statement = node.body; + if (statement.kind == 34) { + sb.push(")"); + } else { + sb.push(") "); + this.visitNode(node.body); + } + } + serializeDecorator(node) { + var sb = this.sb; + sb.push("@"); + this.visitNode(node.name); + var args = node.args; + if (args) { + sb.push("("); + let numArgs = args.length; + if (numArgs) { + this.visitNode(args[0]); + for (let i = 1; i < numArgs; ++i) { + sb.push(", "); + this.visitNode(args[i]); + } + } + sb.push(")\n"); + } else { + sb.push("\n"); + } + util.indent(sb, this.indentLevel); + } + serializeParameter(node) { + var sb = this.sb; + var kind = node.parameterKind; + var implicitFieldDeclaration = node.implicitFieldDeclaration; + if (implicitFieldDeclaration) { + this.serializeAccessModifiers(implicitFieldDeclaration); + } + if (kind == 2) { + sb.push("..."); + } + this.visitIdentifierExpression(node.name); + var type = node.type; + var initializer = node.initializer; + if (type) { + if (kind == 1 && !initializer) sb.push("?"); + if (!isTypeOmitted(type)) { + sb.push(": "); + this.visitTypeNode(type); + } + } + if (initializer) { + sb.push(" = "); + this.visitNode(initializer); + } + } + serializeExternalModifiers(node) { + var sb = this.sb; + if (node.is(2)) { + sb.push("export "); + } else if (node.is(1)) { + sb.push("import "); + } else if (node.is(4)) { + sb.push("declare "); + } + } + serializeAccessModifiers(node) { + var sb = this.sb; + if (node.is(256)) { + sb.push("public "); + } else if (node.is(512)) { + sb.push("private "); + } else if (node.is(1024)) { + sb.push("protected "); + } + if (node.is(32)) { + sb.push("static "); + } else if (node.is(128)) { + sb.push("abstract "); + } + if (node.is(64)) { + sb.push("readonly "); + } + } + finish() { + var ret = this.sb.join(""); + this.sb = []; + return ret; + } } -//# sourceMappingURL=builder.js.map \ No newline at end of file +//# sourceMappingURL=builder.js.map diff --git a/transform/lib/index.js b/transform/lib/index.js index 9a13f80..0234abb 100644 --- a/transform/lib/index.js +++ b/transform/lib/index.js @@ -5,527 +5,452 @@ import { SimpleParser, toString } from "./util.js"; import * as path from "path"; import { fileURLToPath } from "url"; class JSONTransform extends Visitor { - parser; - schemasList = []; - schema; - sources = new Set(); - imports = []; - requiredImport = null; - visitImportStatement(node) { - super.visitImportStatement(node); - const source = this.parser.sources.find(src => src.internalPath == node.internalPath); - if (!source) - return; - let valid = false; - for (const src of source.statements) { - if (src.kind == 59) { - const namespace = src; - if (namespace.name.text == "JSON") { - valid = true; - break; - } - } + parser; + schemasList = []; + schema; + sources = new Set(); + imports = []; + requiredImport = null; + visitImportStatement(node) { + super.visitImportStatement(node); + const source = this.parser.sources.find((src) => src.internalPath == node.internalPath); + if (!source) return; + let valid = false; + for (const src of source.statements) { + if (src.kind == 59) { + const namespace = src; + if (namespace.name.text == "JSON") { + valid = true; + break; } - if (!valid) - return; - this.imports.push(node); + } } - visitClassDeclaration(node) { - if (!node.decorators?.length) - return; - let found = false; - for (const decorator of node.decorators) { - const name = decorator.name.text; - if (name == "json" || name == "serializable") { - found = true; - break; - } - } - if (!found) - return; - console.log(toString(node)); - this.schema = new SchemaData(); - this.schema.node = node; - this.schema.name = node.name.text; - const members = [...node.members.filter((v) => v.kind == 54)]; - if (node.extendsType) { - this.schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text); - if (this.schema.parent?.members) { - for (let i = this.schema.parent.members.length - 1; i >= 0; i--) { - const replace = this.schema.members.find((v) => v.name == this.schema.parent?.members[i]?.name); - if (!replace) { - members.unshift(this.schema.parent?.members[i].node); - } - } - } - } - if (!members.length) { - let SERIALIZE_RAW_EMPTY = '__SERIALIZE(ptr: usize = 0): string {\n return "{}";\n}'; - let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}"; - let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}"; - if (process.env["JSON_DEBUG"]) { - console.log(SERIALIZE_RAW_EMPTY); - console.log(INITIALIZE_EMPTY); - console.log(DESERIALIZE_EMPTY); - } - const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node); - const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node); - const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node); - if (!node.members.find((v) => v.name.text == "__SERIALIZE")) - node.members.push(SERIALIZE_RAW_METHOD_EMPTY); - if (!node.members.find((v) => v.name.text == "__INITIALIZE")) - node.members.push(INITIALIZE_METHOD_EMPTY); - if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) - node.members.push(DESERIALIZE_METHOD_EMPTY); - this.schemasList.push(this.schema); - } - for (const _member of members) { - if (_member.kind !== 54) - continue; - const member = _member; - if (!member.type) { - throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath); - } - if (member.flags == 32) - continue; - if (member.flags == 512) - continue; - if (member.flags == 1024) - continue; - const type = toString(member.type); - const name = member.name; - const value = member.initializer ? toString(member.initializer) : null; - if (type.startsWith("(") && type.includes("=>")) - continue; - const mem = new Property(); - mem.name = name.text; - mem.type = type; - mem.value = value; - mem.node = member; - this.schema.members.push(mem); - if (type.includes("JSON.Raw")) { - mem.flags.set(PropertyFlags.JSON_Raw, []); - } - if (member.type.isNullable) { - mem.flags.set(PropertyFlags.Null, []); - } - if (member.decorators) { - for (const decorator of member.decorators) { - const decoratorName = decorator.name.text; - const args = getArgs(decorator.args); - switch (decoratorName) { - case "alias": { - if (!args.length) - throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath); - mem.alias = args[0]; - mem.flags.set(PropertyFlags.Alias, args); - break; - } - case "omit": { - mem.flags.set(PropertyFlags.Omit, args); - break; - } - case "omitif": { - if (!decorator.args?.length) - throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath); - mem.flags.set(PropertyFlags.OmitIf, args); - break; - } - case "omitnull": { - mem.flags.set(PropertyFlags.OmitNull, args); - break; - } - } - } - } - mem.generate(); - if (this.schemasList.find((v) => v.name == type)) { - mem.initialize = "this." + name.text + " = changetype>(__new(offsetof>(), idof>()));\n changetype>(this." + name.text + ").__INITIALIZE()"; - } - else if (mem.value) { - mem.initialize = "this." + name.text + " = " + mem.value; - } - else if (type == "Map") { - mem.initialize = "this." + name.text + " = new " + mem.type + "()"; - } - else if (type == "string") { - mem.initialize = "this." + name.text + ' = ""'; - } - else if (type == "Array") { - mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()"; - } - else if (type == "bool" || type == "boolean") { - mem.initialize = "this." + name.text + " = false"; - } - else if (type == "JSON.Raw") { - mem.initialize = "this." + name.text + ' = ""'; - } - else if (type == "u8" || type == "u16" || type == "u32" || type == "u64" || type == "i8" || type == "i16" || type == "i32" || type == "i64") { - mem.initialize = "this." + name.text + " = 0"; - } - else if (type == "f32" || type == "f64") { - mem.initialize = "this." + name.text + " = 0.0"; - } - } - let SERIALIZE_RAW = "__SERIALIZE(ptr: usize = 0): string {\n if (ptr == 0) ptr = changetype(this);\n let out = `{"; - let SERIALIZE_PRETTY = "__SERIALIZE_PRETTY(): string {\n let out = `{"; - let INITIALIZE = "__INITIALIZE(): this {\n"; - let DESERIALIZE = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n const len = key_end - key_start;\n"; - let indent = " "; - found = false; - if (!this.imports.find(i => i.declarations.find(d => d.foreignName.text == "JSON"))) { - const __filename = fileURLToPath(import.meta.url); - const __dirname = path.dirname(__filename); - let relativePath = path.relative(path.dirname(node.range.source.normalizedPath), path.resolve(__dirname, "../../assembly/index.ts")); - if (!relativePath.startsWith(".") && !relativePath.startsWith("/")) - relativePath = "./" + relativePath; - const txt = "import { JSON } from \"" + relativePath + "\";"; - if (!this.requiredImport) { - this.requiredImport = txt; - if (process.env["JSON_DEBUG"]) - console.log(txt + "\n"); - } - } - if (this.schema.members[0]?.flags.has(PropertyFlags.OmitNull) || this.schema.members[0]?.flags.has(PropertyFlags.OmitIf)) { - SERIALIZE_RAW += this.schema.members[0]?.serialize; - SERIALIZE_PRETTY += "\\n" + this.schema.members[0]?.serialize; - } - else { - SERIALIZE_RAW += this.schema.members[0]?.serialize + ","; - SERIALIZE_PRETTY += "\\n" + this.schema.members[0]?.serialize + ",\\n"; - found = true; - } - if (this.schema.members[0]?.initialize) - INITIALIZE += " " + this.schema.members[0]?.initialize + ";\n"; - for (let i = 1; i < this.schema.members.length; i++) { - const member = this.schema.members[i]; - if (member.initialize) - INITIALIZE += " " + member.initialize + ";\n"; - if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) { - SERIALIZE_RAW += member.serialize; - SERIALIZE_PRETTY += member.serialize; - } - else { - SERIALIZE_RAW += member.serialize + ","; - SERIALIZE_PRETTY += indent + member.serialize + ",\\n"; - found = true; - } - } - if (found) { - SERIALIZE_RAW += "`;\n store(changetype(out) + ((out.length - 1) << 1), 125);\n return out;\n}"; - SERIALIZE_PRETTY += "`;\n store(changetype(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}"; + if (!valid) return; + this.imports.push(node); + } + visitClassDeclaration(node) { + if (!node.decorators?.length) return; + let found = false; + for (const decorator of node.decorators) { + const name = decorator.name.text; + if (name == "json" || name == "serializable") { + found = true; + break; + } + } + if (!found) return; + console.log(toString(node)); + this.schema = new SchemaData(); + this.schema.node = node; + this.schema.name = node.name.text; + const members = [...node.members.filter((v) => v.kind == 54)]; + if (node.extendsType) { + this.schema.parent = this.schemasList.find((v) => v.name == node.extendsType?.name.identifier.text); + if (this.schema.parent?.members) { + for (let i = this.schema.parent.members.length - 1; i >= 0; i--) { + const replace = this.schema.members.find((v) => v.name == this.schema.parent?.members[i]?.name); + if (!replace) { + members.unshift(this.schema.parent?.members[i].node); + } } - else { - SERIALIZE_RAW += "}`;\n return out;\n}"; - SERIALIZE_PRETTY += "}`;\n return out;\n}"; + } + } + if (!members.length) { + let SERIALIZE_RAW_EMPTY = '__SERIALIZE(ptr: usize = 0): string {\n return "{}";\n}'; + let INITIALIZE_EMPTY = "__INITIALIZE(): this {\n return this;\n}"; + let DESERIALIZE_EMPTY = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n return false;\n}"; + if (process.env["JSON_DEBUG"]) { + console.log(SERIALIZE_RAW_EMPTY); + console.log(INITIALIZE_EMPTY); + console.log(DESERIALIZE_EMPTY); + } + const SERIALIZE_RAW_METHOD_EMPTY = SimpleParser.parseClassMember(SERIALIZE_RAW_EMPTY, node); + const INITIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(INITIALIZE_EMPTY, node); + const DESERIALIZE_METHOD_EMPTY = SimpleParser.parseClassMember(DESERIALIZE_EMPTY, node); + if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD_EMPTY); + if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD_EMPTY); + if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD_EMPTY); + this.schemasList.push(this.schema); + } + for (const _member of members) { + if (_member.kind !== 54) continue; + const member = _member; + if (!member.type) { + throw new Error("Fields must be strongly typed! Found " + toString(member) + " at " + node.range.source.normalizedPath); + } + if (member.flags == 32) continue; + if (member.flags == 512) continue; + if (member.flags == 1024) continue; + const type = toString(member.type); + const name = member.name; + const value = member.initializer ? toString(member.initializer) : null; + if (type.startsWith("(") && type.includes("=>")) continue; + const mem = new Property(); + mem.name = name.text; + mem.type = type; + mem.value = value; + mem.node = member; + this.schema.members.push(mem); + if (type.includes("JSON.Raw")) { + mem.flags.set(PropertyFlags.JSON_Raw, []); + } + if (member.type.isNullable) { + mem.flags.set(PropertyFlags.Null, []); + } + if (member.decorators) { + for (const decorator of member.decorators) { + const decoratorName = decorator.name.text; + const args = getArgs(decorator.args); + switch (decoratorName) { + case "alias": { + if (!args.length) throw new Error("Expected 1 argument but got zero at @alias in " + node.range.source.normalizedPath); + mem.alias = args[0]; + mem.flags.set(PropertyFlags.Alias, args); + break; + } + case "omit": { + mem.flags.set(PropertyFlags.Omit, args); + break; + } + case "omitif": { + if (!decorator.args?.length) throw new Error("Expected 1 argument but got zero at @omitif in " + node.range.source.normalizedPath); + mem.flags.set(PropertyFlags.OmitIf, args); + break; + } + case "omitnull": { + mem.flags.set(PropertyFlags.OmitNull, args); + break; + } + } } - INITIALIZE += " return this;\n}"; - const sortedMembers = []; - const _sorted = this.schema.members.sort((a, b) => (a.alias?.length || a.name.length) - (b.alias?.length || b.name.length)); - let len = -1; - let offset = -1; - for (let i = 0; i < _sorted.length; i++) { - const member = _sorted[i]; - const _name = member.alias || member.name; - if (_name.length == len) { - sortedMembers[offset]?.push(member); - } - else { - sortedMembers.push([member]); - len = _name.length; - offset++; - } + } + mem.generate(); + if (this.schemasList.find((v) => v.name == type)) { + mem.initialize = "this." + name.text + " = changetype>(__new(offsetof>(), idof>()));\n changetype>(this." + name.text + ").__INITIALIZE()"; + } else if (mem.value) { + mem.initialize = "this." + name.text + " = " + mem.value; + } else if (type == "Map") { + mem.initialize = "this." + name.text + " = new " + mem.type + "()"; + } else if (type == "string") { + mem.initialize = "this." + name.text + ' = ""'; + } else if (type == "Array") { + mem.initialize = "this." + name.text + " = instantiate<" + mem.type + ">()"; + } else if (type == "bool" || type == "boolean") { + mem.initialize = "this." + name.text + " = false"; + } else if (type == "JSON.Raw") { + mem.initialize = "this." + name.text + ' = ""'; + } else if (type == "u8" || type == "u16" || type == "u32" || type == "u64" || type == "i8" || type == "i16" || type == "i32" || type == "i64") { + mem.initialize = "this." + name.text + " = 0"; + } else if (type == "f32" || type == "f64") { + mem.initialize = "this." + name.text + " = 0.0"; + } + } + let SERIALIZE_RAW = "__SERIALIZE(ptr: usize = 0): string {\n if (ptr == 0) ptr = changetype(this);\n let out = `{"; + let SERIALIZE_PRETTY = "__SERIALIZE_PRETTY(): string {\n let out = `{"; + let INITIALIZE = "__INITIALIZE(): this {\n"; + let DESERIALIZE = "__DESERIALIZE(data: string, key_start: i32, key_end: i32, value_start: i32, value_end: i32): boolean {\n const len = key_end - key_start;\n"; + let indent = " "; + found = false; + if (!this.imports.find((i) => i.declarations.find((d) => d.foreignName.text == "JSON"))) { + const __filename = fileURLToPath(import.meta.url); + const __dirname = path.dirname(__filename); + let relativePath = path.relative(path.dirname(node.range.source.normalizedPath), path.resolve(__dirname, "../../assembly/index.ts")); + if (!relativePath.startsWith(".") && !relativePath.startsWith("/")) relativePath = "./" + relativePath; + const txt = 'import { JSON } from "' + relativePath + '";'; + if (!this.requiredImport) { + this.requiredImport = txt; + if (process.env["JSON_DEBUG"]) console.log(txt + "\n"); + } + } + if (this.schema.members[0]?.flags.has(PropertyFlags.OmitNull) || this.schema.members[0]?.flags.has(PropertyFlags.OmitIf)) { + SERIALIZE_RAW += this.schema.members[0]?.serialize; + SERIALIZE_PRETTY += "\\n" + this.schema.members[0]?.serialize; + } else { + SERIALIZE_RAW += this.schema.members[0]?.serialize + ","; + SERIALIZE_PRETTY += "\\n" + this.schema.members[0]?.serialize + ",\\n"; + found = true; + } + if (this.schema.members[0]?.initialize) INITIALIZE += " " + this.schema.members[0]?.initialize + ";\n"; + for (let i = 1; i < this.schema.members.length; i++) { + const member = this.schema.members[i]; + if (member.initialize) INITIALIZE += " " + member.initialize + ";\n"; + if (member.flags.has(PropertyFlags.OmitNull) || member.flags.has(PropertyFlags.OmitIf)) { + SERIALIZE_RAW += member.serialize; + SERIALIZE_PRETTY += member.serialize; + } else { + SERIALIZE_RAW += member.serialize + ","; + SERIALIZE_PRETTY += indent + member.serialize + ",\\n"; + found = true; + } + } + if (found) { + SERIALIZE_RAW += "`;\n store(changetype(out) + ((out.length - 1) << 1), 125);\n return out;\n}"; + SERIALIZE_PRETTY += "`;\n store(changetype(out) + ((out.length - 2) << 1), 8192010);\n return out;\n}"; + } else { + SERIALIZE_RAW += "}`;\n return out;\n}"; + SERIALIZE_PRETTY += "}`;\n return out;\n}"; + } + INITIALIZE += " return this;\n}"; + const sortedMembers = []; + const _sorted = this.schema.members.sort((a, b) => (a.alias?.length || a.name.length) - (b.alias?.length || b.name.length)); + let len = -1; + let offset = -1; + for (let i = 0; i < _sorted.length; i++) { + const member = _sorted[i]; + const _name = member.alias || member.name; + if (_name.length == len) { + sortedMembers[offset]?.push(member); + } else { + sortedMembers.push([member]); + len = _name.length; + offset++; + } + } + let first = true; + for (const memberSet of sortedMembers) { + const firstMember = memberSet[0]; + const _name = encodeKey(firstMember.alias || firstMember.name); + if (_name.length == 1) { + if (first) { + DESERIALIZE += " if (1 == len) {\n switch (load(changetype(data) + (key_start << 1))) {\n"; + first = false; + } else { + DESERIALIZE += "else if (1 == len) {\n switch (load(changetype(data) + (key_start << 1))) {\n"; } - let first = true; - for (const memberSet of sortedMembers) { - const firstMember = memberSet[0]; - const _name = encodeKey(firstMember.alias || firstMember.name); - if (_name.length == 1) { - if (first) { - DESERIALIZE += " if (1 == len) {\n switch (load(changetype(data) + (key_start << 1))) {\n"; - first = false; - } - else { - DESERIALIZE += "else if (1 == len) {\n switch (load(changetype(data) + (key_start << 1))) {\n"; - } - } - else if (_name.length == 2) { - if (first) { - DESERIALIZE += " if (2 == len) {\n switch (load(changetype(data) + (key_start << 1))) {\n"; - first = false; - } - else { - DESERIALIZE += "else if (2 == len) {\n switch (load(changetype(data) + (key_start << 1))) {\n"; - } - } - else if (_name.length == 4) { - if (first) { - DESERIALIZE += " if (4 == len) {\n const code = load(changetype(data) + (key_start << 1));\n"; - first = false; - } - else { - DESERIALIZE += "else if (4 == len) {\n const code = load(changetype(data) + (key_start << 1));\n"; - } - } - else { - if (first) { - DESERIALIZE += " if (" + _name.length + " == len) {\n"; - first = false; - } - else { - DESERIALIZE += "else if (" + _name.length + " == len) {\n"; - } - } - let f = true; - for (let i = 0; i < memberSet.length; i++) { - const member = memberSet[i]; - if (!member.deserialize) - continue; - const _name = encodeKey(member.alias || member.name); - if (_name.length == 1) { - DESERIALIZE += ` case ${_name.charCodeAt(0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; - } - else if (_name.length == 2) { - DESERIALIZE += ` case ${charCodeAt32(_name, 0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; - } - else if (_name.length == 4) { - if (f) { - f = false; - DESERIALIZE += ` if (${charCodeAt64(_name, 0)} == code) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; - } - else { - DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} == code) {\n ${member.deserialize}\n return true;\n }\n`; - } - } - else { - if (f) { - f = false; - DESERIALIZE += ` if (0 == memory.compare(changetype("${escapeQuote(escapeSlash(_name))}"), changetype(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; - } - else { - DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else if (0 == memory.compare(changetype("${escapeQuote(escapeSlash(_name))}"), changetype(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; - } - } - } - if (_name.length < 3) { - DESERIALIZE += ` default: {\n return false;\n }\n }\n`; - } - else if (_name.length == 4) { - DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; - } - else { - DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; - } - DESERIALIZE += " } "; + } else if (_name.length == 2) { + if (first) { + DESERIALIZE += " if (2 == len) {\n switch (load(changetype(data) + (key_start << 1))) {\n"; + first = false; + } else { + DESERIALIZE += "else if (2 == len) {\n switch (load(changetype(data) + (key_start << 1))) {\n"; } - DESERIALIZE += "\n return false;\n}"; - if (process.env["JSON_DEBUG"]) { - console.log(SERIALIZE_RAW); - console.log(INITIALIZE); - console.log(DESERIALIZE); + } else if (_name.length == 4) { + if (first) { + DESERIALIZE += " if (4 == len) {\n const code = load(changetype(data) + (key_start << 1));\n"; + first = false; + } else { + DESERIALIZE += "else if (4 == len) {\n const code = load(changetype(data) + (key_start << 1));\n"; } - const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node); - const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node); - const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node); - if (!node.members.find((v) => v.name.text == "__SERIALIZE")) - node.members.push(SERIALIZE_RAW_METHOD); - if (!node.members.find((v) => v.name.text == "__INITIALIZE")) - node.members.push(INITIALIZE_METHOD); - if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) - node.members.push(DESERIALIZE_METHOD); - super.visitClassDeclaration(node); - } - visitCallExpression(node, ref) { - super.visitCallExpression(node, ref); - if (!(node.expression.kind == 21 && - node.expression.property.text == "stringifyTo") - && - !(node.expression.kind == 6 && - node.expression.text == "stringifyTo")) - return; - const source = node.range.source; - if (ref.kind == 9) { - const newNode = Node.createBinaryExpression(101, node.args[1], node, node.range); - ref.args[ref.args.indexOf(node)] = newNode; + } else { + if (first) { + DESERIALIZE += " if (" + _name.length + " == len) {\n"; + first = false; + } else { + DESERIALIZE += "else if (" + _name.length + " == len) {\n"; } - else { - const newNode = Node.createExpressionStatement(Node.createBinaryExpression(101, node.args[1], node, node.range)); - const nodeIndex = source.statements.findIndex((n) => { - if (n == node) - return true; - if (n.kind == 38 && n.expression == node) - return true; - return false; - }); - if (nodeIndex > 0) - source.statements[nodeIndex] = newNode; + } + let f = true; + for (let i = 0; i < memberSet.length; i++) { + const member = memberSet[i]; + if (!member.deserialize) continue; + const _name = encodeKey(member.alias || member.name); + if (_name.length == 1) { + DESERIALIZE += ` case ${_name.charCodeAt(0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; + } else if (_name.length == 2) { + DESERIALIZE += ` case ${charCodeAt32(_name, 0)}: { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; + } else if (_name.length == 4) { + if (f) { + f = false; + DESERIALIZE += ` if (${charCodeAt64(_name, 0)} == code) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; + } else { + DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + `else if (${charCodeAt64(_name, 0)} == code) {\n ${member.deserialize}\n return true;\n }\n`; + } + } else { + if (f) { + f = false; + DESERIALIZE += ` if (0 == memory.compare(changetype("${escapeQuote(escapeSlash(_name))}"), changetype(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; + } else { + DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else if (0 == memory.compare(changetype("${escapeQuote(escapeSlash(_name))}"), changetype(data) + (key_start << 1), ${_name.length << 1})) { /* ${_name} */\n ${member.deserialize}\n return true;\n }\n`; + } } + } + if (_name.length < 3) { + DESERIALIZE += ` default: {\n return false;\n }\n }\n`; + } else if (_name.length == 4) { + DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; + } else { + DESERIALIZE = DESERIALIZE.slice(0, DESERIALIZE.length - 1) + ` else {\n return false;\n }\n`; + } + DESERIALIZE += " } "; } - visitBinaryExpression(node, ref) { + DESERIALIZE += "\n return false;\n}"; + if (process.env["JSON_DEBUG"]) { + console.log(SERIALIZE_RAW); + console.log(INITIALIZE); + console.log(DESERIALIZE); } - visitSource(node) { - this.imports = []; - super.visitSource(node); + const SERIALIZE_RAW_METHOD = SimpleParser.parseClassMember(SERIALIZE_RAW, node); + const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node); + const DESERIALIZE_METHOD = SimpleParser.parseClassMember(DESERIALIZE, node); + if (!node.members.find((v) => v.name.text == "__SERIALIZE")) node.members.push(SERIALIZE_RAW_METHOD); + if (!node.members.find((v) => v.name.text == "__INITIALIZE")) node.members.push(INITIALIZE_METHOD); + if (!node.members.find((v) => v.name.text == "__DESERIALIZE")) node.members.push(DESERIALIZE_METHOD); + super.visitClassDeclaration(node); + } + visitCallExpression(node, ref) { + super.visitCallExpression(node, ref); + if (!(node.expression.kind == 21 && node.expression.property.text == "stringifyTo") && !(node.expression.kind == 6 && node.expression.text == "stringifyTo")) return; + const source = node.range.source; + if (ref.kind == 9) { + const newNode = Node.createBinaryExpression(101, node.args[1], node, node.range); + ref.args[ref.args.indexOf(node)] = newNode; + } else { + const newNode = Node.createExpressionStatement(Node.createBinaryExpression(101, node.args[1], node, node.range)); + const nodeIndex = source.statements.findIndex((n) => { + if (n == node) return true; + if (n.kind == 38 && n.expression == node) return true; + return false; + }); + if (nodeIndex > 0) source.statements[nodeIndex] = newNode; } + } + visitBinaryExpression(node, ref) {} + visitSource(node) { + this.imports = []; + super.visitSource(node); + } } export default class Transformer extends Transform { - afterParse(parser) { - const transformer = new JSONTransform(); - const sources = parser.sources - .sort((_a, _b) => { - const a = _a.internalPath; - const b = _b.internalPath; - if (a[0] == "~" && b[0] !== "~") { - return -1; - } - else if (a[0] !== "~" && b[0] == "~") { - return 1; - } - else { - return 0; - } - }); - transformer.parser = parser; - for (const source of sources) { - transformer.imports = []; - transformer.currentSource = source; - transformer.visit(source); - if (transformer.requiredImport) { - const tokenizer = new Tokenizer(new Source(0, source.normalizedPath, transformer.requiredImport)); - parser.currentSource = tokenizer.source; - source.statements.unshift(parser.parseTopLevelStatement(tokenizer)); - parser.currentSource = source; - transformer.requiredImport = null; - } - } - const schemas = transformer.schemasList; - for (const schema of schemas) { - if (schema.parent) { - const parent = schemas.find((v) => v.name == schema.parent?.name); - if (!parent) - throw new Error(`Class ${schema.name} extends its parent class ${schema.parent}, but ${schema.parent} does not include a @json or @serializable decorator! Add the decorator and rebuild.`); - } - } + afterParse(parser) { + const transformer = new JSONTransform(); + const sources = parser.sources.sort((_a, _b) => { + const a = _a.internalPath; + const b = _b.internalPath; + if (a[0] == "~" && b[0] !== "~") { + return -1; + } else if (a[0] !== "~" && b[0] == "~") { + return 1; + } else { + return 0; + } + }); + transformer.parser = parser; + for (const source of sources) { + transformer.imports = []; + transformer.currentSource = source; + transformer.visit(source); + if (transformer.requiredImport) { + const tokenizer = new Tokenizer(new Source(0, source.normalizedPath, transformer.requiredImport)); + parser.currentSource = tokenizer.source; + source.statements.unshift(parser.parseTopLevelStatement(tokenizer)); + parser.currentSource = source; + transformer.requiredImport = null; + } + } + const schemas = transformer.schemasList; + for (const schema of schemas) { + if (schema.parent) { + const parent = schemas.find((v) => v.name == schema.parent?.name); + if (!parent) throw new Error(`Class ${schema.name} extends its parent class ${schema.parent}, but ${schema.parent} does not include a @json or @serializable decorator! Add the decorator and rebuild.`); + } } + } } var PropertyFlags; (function (PropertyFlags) { - PropertyFlags[PropertyFlags["Null"] = 0] = "Null"; - PropertyFlags[PropertyFlags["Omit"] = 1] = "Omit"; - PropertyFlags[PropertyFlags["OmitNull"] = 2] = "OmitNull"; - PropertyFlags[PropertyFlags["OmitIf"] = 3] = "OmitIf"; - PropertyFlags[PropertyFlags["Alias"] = 4] = "Alias"; - PropertyFlags[PropertyFlags["JSON_Raw"] = 5] = "JSON_Raw"; + PropertyFlags[(PropertyFlags["Null"] = 0)] = "Null"; + PropertyFlags[(PropertyFlags["Omit"] = 1)] = "Omit"; + PropertyFlags[(PropertyFlags["OmitNull"] = 2)] = "OmitNull"; + PropertyFlags[(PropertyFlags["OmitIf"] = 3)] = "OmitIf"; + PropertyFlags[(PropertyFlags["Alias"] = 4)] = "Alias"; + PropertyFlags[(PropertyFlags["JSON_Raw"] = 5)] = "JSON_Raw"; })(PropertyFlags || (PropertyFlags = {})); class Property { - name = ""; - alias = null; - type = ""; - value = null; - flags = new Map(); - serialize = null; - deserialize = null; - initialize = null; - node; - right_s = ""; - right_d = ""; - generate() { - const name = this.name; - const escapedName = escapeString(JSON.stringify(this.alias || this.name)); - const type = this.type; - if (this.flags.has(PropertyFlags.Omit)) - return; - if (this.flags.has(PropertyFlags.JSON_Raw)) { - if (this.flags.has(PropertyFlags.Null)) { - this.right_s = "(load<" + type + '>(ptr, offsetof("' + name + '")) || "null")'; - this.right_d = "value_start == value_end - 4 && 30399761348886638 == load(changetype(data) + (value_start << 1)) ? null : data.substring(value_start, value_end)"; - } - else { - this.right_s = "load<" + type + '>(ptr, offsetof("' + name + '"))'; - this.right_d = "data.substring(value_start, value_end)"; - } - } - else { - this.right_s = "JSON.stringify<" + type + ">(load<" + type + '>(ptr, offsetof("' + name + '")))'; - this.right_d = "JSON.parse<" + type + ">(data.substring(value_start, value_end))"; - } - if (this.flags.has(PropertyFlags.OmitIf)) { - const condition = this.flags.get(PropertyFlags.OmitIf)[0]; - if (!condition) - throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition"); - this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; - this.deserialize = "this." + name + " = " + this.right_d + ";"; - } - else if (this.flags.has(PropertyFlags.OmitNull)) { - this.serialize = "${changetype(this." + name + ") == 0" + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; - this.deserialize = "this." + name + " = " + this.right_d + ";"; - } - else { - this.serialize = escapedName + ":${" + this.right_s + "}"; - this.deserialize = "this." + name + " = " + this.right_d + ";"; - } + name = ""; + alias = null; + type = ""; + value = null; + flags = new Map(); + serialize = null; + deserialize = null; + initialize = null; + node; + right_s = ""; + right_d = ""; + generate() { + const name = this.name; + const escapedName = escapeString(JSON.stringify(this.alias || this.name)); + const type = this.type; + if (this.flags.has(PropertyFlags.Omit)) return; + if (this.flags.has(PropertyFlags.JSON_Raw)) { + if (this.flags.has(PropertyFlags.Null)) { + this.right_s = "(load<" + type + '>(ptr, offsetof("' + name + '")) || "null")'; + this.right_d = "value_start == value_end - 4 && 30399761348886638 == load(changetype(data) + (value_start << 1)) ? null : data.substring(value_start, value_end)"; + } else { + this.right_s = "load<" + type + '>(ptr, offsetof("' + name + '"))'; + this.right_d = "data.substring(value_start, value_end)"; + } + } else { + this.right_s = "JSON.stringify<" + type + ">(load<" + type + '>(ptr, offsetof("' + name + '")))'; + this.right_d = "JSON.parse<" + type + ">(data.substring(value_start, value_end))"; } + if (this.flags.has(PropertyFlags.OmitIf)) { + const condition = this.flags.get(PropertyFlags.OmitIf)[0]; + if (!condition) throw new Error("Could not find condition when using decorator @omitif! Provide at least one condition"); + this.serialize = "${" + condition + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; + this.deserialize = "this." + name + " = " + this.right_d + ";"; + } else if (this.flags.has(PropertyFlags.OmitNull)) { + this.serialize = "${changetype(this." + name + ") == 0" + ' ? "" : \'' + escapedName + ":' + " + this.right_s + ' + ","}'; + this.deserialize = "this." + name + " = " + this.right_d + ";"; + } else { + this.serialize = escapedName + ":${" + this.right_s + "}"; + this.deserialize = "this." + name + " = " + this.right_d + ";"; + } + } } class SchemaData { - name = ""; - members = []; - parent = null; - node; + name = ""; + members = []; + parent = null; + node; } function charCodeAt32(data, offset) { - return (data.charCodeAt(offset + 1) << 16) | data.charCodeAt(offset); + return (data.charCodeAt(offset + 1) << 16) | data.charCodeAt(offset); } function charCodeAt64(data, offset) { - if (offset + 3 >= data.length) { - throw new Error("The string must have at least 4 characters from the specified offset."); - } - const firstCharCode = BigInt(data.charCodeAt(offset)); - const secondCharCode = BigInt(data.charCodeAt(offset + 1)); - const thirdCharCode = BigInt(data.charCodeAt(offset + 2)); - const fourthCharCode = BigInt(data.charCodeAt(offset + 3)); - const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode; - return u64Value; + if (offset + 3 >= data.length) { + throw new Error("The string must have at least 4 characters from the specified offset."); + } + const firstCharCode = BigInt(data.charCodeAt(offset)); + const secondCharCode = BigInt(data.charCodeAt(offset + 1)); + const thirdCharCode = BigInt(data.charCodeAt(offset + 2)); + const fourthCharCode = BigInt(data.charCodeAt(offset + 3)); + const u64Value = (fourthCharCode << 48n) | (thirdCharCode << 32n) | (secondCharCode << 16n) | firstCharCode; + return u64Value; } function encodeKey(key) { - const data = JSON.stringify(key); - return data.slice(1, data.length - 1); + const data = JSON.stringify(key); + return data.slice(1, data.length - 1); } function escapeString(data) { - return data.replace(/\\/g, "\\\\").replace(/\`/g, "\\`"); + return data.replace(/\\/g, "\\\\").replace(/\`/g, "\\`"); } function escapeSlash(data) { - return data.replace(/\\/g, "\\\\").replace(/\`/g, "\\`"); + return data.replace(/\\/g, "\\\\").replace(/\`/g, "\\`"); } function escapeQuote(data) { - return data.replace(/\"/g, '\\"'); + return data.replace(/\"/g, '\\"'); } function getArgs(args) { - if (!args) - return []; - let out = []; - for (const arg of args) { - if (arg instanceof StringLiteralExpression) { - out.push(arg.value); - } - else if (arg instanceof IntegerLiteralExpression) { - out.push(i64_to_string(arg.value)); - } - else if (arg instanceof FloatLiteralExpression) { - out.push(arg.value.toString()); - } - else if (arg instanceof NullExpression) { - out.push(arg.text); - } - else if (arg instanceof TrueExpression) { - out.push(arg.text); - } - else if (arg instanceof FalseExpression) { - out.push(arg.text); - } - else if (arg instanceof IdentifierExpression) { - out.push(arg.text); - } + if (!args) return []; + let out = []; + for (const arg of args) { + if (arg instanceof StringLiteralExpression) { + out.push(arg.value); + } else if (arg instanceof IntegerLiteralExpression) { + out.push(i64_to_string(arg.value)); + } else if (arg instanceof FloatLiteralExpression) { + out.push(arg.value.toString()); + } else if (arg instanceof NullExpression) { + out.push(arg.text); + } else if (arg instanceof TrueExpression) { + out.push(arg.text); + } else if (arg instanceof FalseExpression) { + out.push(arg.text); + } else if (arg instanceof IdentifierExpression) { + out.push(arg.text); } - return out; + } + return out; } -//# sourceMappingURL=index.js.map \ No newline at end of file +//# sourceMappingURL=index.js.map diff --git a/transform/lib/util.js b/transform/lib/util.js index dc31491..a0ad4ba 100644 --- a/transform/lib/util.js +++ b/transform/lib/util.js @@ -1,47 +1,47 @@ -import { Parser, Tokenizer, Source, } from "assemblyscript/dist/assemblyscript.js"; +import { Parser, Tokenizer, Source } from "assemblyscript/dist/assemblyscript.js"; import { ASTBuilder } from "./builder.js"; export class SimpleParser { - static get parser() { - return new Parser(); + static get parser() { + return new Parser(); + } + static getTokenizer(s, file = "index.ts") { + return new Tokenizer(new Source(0, file, s)); + } + static parseExpression(s) { + const res = this.parser.parseExpression(this.getTokenizer(s)); + if (res == null) { + throw new Error("Failed to parse the expression: '" + s + "'"); } - static getTokenizer(s, file = "index.ts") { - return new Tokenizer(new Source(0, file, s)); + return res; + } + static parseStatement(s, topLevel = false) { + const res = this.parser.parseStatement(this.getTokenizer(s), topLevel); + if (res == null) { + throw new Error("Failed to parse the statement: '" + s + "'"); } - static parseExpression(s) { - const res = this.parser.parseExpression(this.getTokenizer(s)); - if (res == null) { - throw new Error("Failed to parse the expression: '" + s + "'"); - } - return res; + return res; + } + static parseTopLevelStatement(s, namespace) { + const res = this.parser.parseTopLevelStatement(this.getTokenizer(s), namespace); + if (res == null) { + throw new Error("Failed to parse the top level statement: '" + s + "'"); } - static parseStatement(s, topLevel = false) { - const res = this.parser.parseStatement(this.getTokenizer(s), topLevel); - if (res == null) { - throw new Error("Failed to parse the statement: '" + s + "'"); - } - return res; - } - static parseTopLevelStatement(s, namespace) { - const res = this.parser.parseTopLevelStatement(this.getTokenizer(s), namespace); - if (res == null) { - throw new Error("Failed to parse the top level statement: '" + s + "'"); - } - return res; - } - static parseClassMember(s, _class) { - let res = this.parser.parseClassMember(this.getTokenizer(s, _class.range.source.normalizedPath), _class); - if (res == null) { - throw new Error("Failed to parse the class member: '" + s + "'"); - } - return res; + return res; + } + static parseClassMember(s, _class) { + let res = this.parser.parseClassMember(this.getTokenizer(s, _class.range.source.normalizedPath), _class); + if (res == null) { + throw new Error("Failed to parse the class member: '" + s + "'"); } + return res; + } } let isStdlibRegex = /\~lib\/(?:array|arraybuffer|atomics|builtins|crypto|console|compat|dataview|date|diagnostics|error|function|iterator|map|math|number|object|process|reference|regexp|set|staticarray|string|symbol|table|typedarray|vector|rt\/?|bindings\/|shared\/typeinfo)|util\/|uri|polyfills|memory/; export function isStdlib(s) { - let source = s instanceof Source ? s : s.range.source; - return isStdlibRegex.test(source.internalPath); + let source = s instanceof Source ? s : s.range.source; + return isStdlibRegex.test(source.internalPath); } export function toString(node) { - return ASTBuilder.build(node); + return ASTBuilder.build(node); } -//# sourceMappingURL=util.js.map \ No newline at end of file +//# sourceMappingURL=util.js.map diff --git a/transform/lib/visitor.js b/transform/lib/visitor.js index 6c8dc4c..d544886 100644 --- a/transform/lib/visitor.js +++ b/transform/lib/visitor.js @@ -1,531 +1,528 @@ export class Visitor { - currentSource = null; - visit(node, ref = null) { - if (node == null) - return; - if (node instanceof Array) { - for (const n of node) { - this._visit(n, ref); - } - } - else { - this._visit(node, ref); - } - } - _visit(node, ref) { - switch (node.kind) { - case 0: - this.visitSource(node, ref); - break; - case 1: - this.visitNamedTypeNode(node, ref); - break; - case 2: - this.visitFunctionTypeNode(node, ref); - break; - case 3: - this.visitTypeName(node, ref); - break; - case 4: - this.visitTypeParameter(node, ref); - break; - case 6: - this.visitIdentifierExpression(node, ref); - break; - case 7: - this.visitAssertionExpression(node, ref); - break; - case 8: - this.visitBinaryExpression(node, ref); - break; - case 9: - this.visitCallExpression(node, ref); - break; - case 10: - this.visitClassExpression(node, ref); - break; - case 11: - this.visitCommaExpression(node, ref); - break; - case 12: - this.visitElementAccessExpression(node, ref); - break; - case 14: - this.visitFunctionExpression(node, ref); - break; - case 15: - this.visitInstanceOfExpression(node, ref); - break; - case 16: - this.visitLiteralExpression(node, ref); - break; - case 17: - this.visitNewExpression(node, ref); - break; - case 20: - this.visitParenthesizedExpression(node, ref); - break; - case 21: - this.visitPropertyAccessExpression(node, ref); - break; - case 22: - this.visitTernaryExpression(node, ref); - break; - case 27: - this.visitUnaryPostfixExpression(node, ref); - break; - case 28: - this.visitUnaryPrefixExpression(node, ref); - break; - case 30: - this.visitBlockStatement(node, ref); - break; - case 31: - this.visitBreakStatement(node, ref); - break; - case 32: - this.visitContinueStatement(node, ref); - break; - case 33: - this.visitDoStatement(node, ref); - break; - case 34: - this.visitEmptyStatement(node, ref); - break; - case 35: - this.visitExportStatement(node, ref); - break; - case 36: - this.visitExportDefaultStatement(node, ref); - break; - case 37: - this.visitExportImportStatement(node, ref); - break; - case 38: - this.visitExpressionStatement(node, ref); - break; - case 39: - this.visitForStatement(node, ref); - break; - case 41: - this.visitIfStatement(node, ref); - break; - case 42: - this.visitImportStatement(node, ref); - break; - case 43: - this.visitReturnStatement(node, ref); - break; - case 44: - this.visitSwitchStatement(node, ref); - break; - case 45: - this.visitThrowStatement(node, ref); - break; - case 46: - this.visitTryStatement(node, ref); - break; - case 47: - this.visitVariableStatement(node, ref); - break; - case 49: - this.visitWhileStatement(node, ref); - break; - case 51: - this.visitClassDeclaration(node, false, ref); - break; - case 52: - this.visitEnumDeclaration(node, false, ref); - break; - case 53: - this.visitEnumValueDeclaration(node, ref); - break; - case 54: - this.visitFieldDeclaration(node, ref); - break; - case 55: - this.visitFunctionDeclaration(node, false, ref); - break; - case 56: - this.visitImportDeclaration(node, ref); - break; - case 57: - this.visitInterfaceDeclaration(node, false, ref); - break; - case 58: - this.visitMethodDeclaration(node, ref); - break; - case 59: - this.visitNamespaceDeclaration(node, false, ref); - break; - case 60: - this.visitTypeDeclaration(node, ref); - break; - case 61: - this.visitVariableDeclaration(node, ref); - break; - case 62: - this.visitDecoratorNode(node, ref); - break; - case 63: - this.visitExportMember(node, ref); - break; - case 64: - this.visitSwitchCase(node, ref); - break; - case 65: - this.visitIndexSignature(node, ref); - break; - case 18: - this.visitNullExpression(node, ref); - break; - case 25: { - this.visitTrueExpression(node, ref); - break; - } - case 13: { - this.visitFalseExpression(node, ref); - break; - } - case 29: { - this.visitCompiledExpression(node, ref); - break; - } - case 26: { - this.visitConstructorExpression(node, ref); - break; - } - case 66: { - this.visitComment(node, ref); - break; - } - case 40: { - this.visitForOfStatement(node, ref); - break; - } - case 50: { - this.visitModuleDeclaration(node, ref); - break; - } - case 19: { - this.visitOmittedExpression(node, ref); - break; - } - case 5: { - this.visitParameter(node, ref); - break; - } - case 23: { - this.visitSuperExpression(node, ref); - break; - } - case 24: { - this.visitThisExpression(node, ref); - break; - } - case 48: { - this.visitVoidStatement(node, ref); - break; - } - default: - throw new Error("Could not visit invalid type!"); - } - } - visitSource(node, ref = null) { - this.currentSource = node; - this.visit(node.statements, node); - this.currentSource = null; - } - visitTypeNode(node, ref = null) { } - visitTypeName(node, ref = null) { - this.visit(node.identifier, node); - this.visit(node.next, node); - } - visitNamedTypeNode(node, ref = null) { - this.visit(node.name, node); - this.visit(node.typeArguments, node); - } - visitFunctionTypeNode(node, ref = null) { - this.visit(node.parameters, node); - this.visit(node.returnType, node); - this.visit(node.explicitThisType, node); - } - visitTypeParameter(node, ref = null) { - this.visit(node.name, node); - this.visit(node.extendsType, node); - this.visit(node.defaultType, node); - } - visitIdentifierExpression(node, ref = null) { } - visitArrayLiteralExpression(node, ref = null) { - this.visit(node.elementExpressions, node); - } - visitObjectLiteralExpression(node, ref = null) { - this.visit(node.names, node); - this.visit(node.values, node); - } - visitAssertionExpression(node, ref = null) { - this.visit(node.toType, node); - this.visit(node.expression, node); - } - visitBinaryExpression(node, ref = null) { - this.visit(node.left, node); - this.visit(node.right, node); - } - visitCallExpression(node, ref = null) { - this.visit(node.expression, node); - this.visit(node.typeArguments, node); - this.visit(node.args, node); - } - visitClassExpression(node, ref = null) { - this.visit(node.declaration, node); - } - visitCommaExpression(node, ref = null) { - this.visit(node.expressions, node); - } - visitElementAccessExpression(node, ref = null) { - this.visit(node.elementExpression, node); - this.visit(node.expression, node); - } - visitFunctionExpression(node, ref = null) { - this.visit(node.declaration, node); - } - visitLiteralExpression(node, ref = null) { - switch (node.literalKind) { - case 0: - this.visitFloatLiteralExpression(node); - break; - case 1: - this.visitIntegerLiteralExpression(node); - break; - case 2: - this.visitStringLiteralExpression(node); - break; - case 3: - this.visitTemplateLiteralExpression(node); - break; - case 4: - this.visitRegexpLiteralExpression(node); - break; - case 5: - this.visitArrayLiteralExpression(node); - break; - case 6: - this.visitObjectLiteralExpression(node); - break; - default: - throw new Error("Invalid LiteralKind at visitLiteralExpression(): " + node.literalKind); - } - } - visitFloatLiteralExpression(node, ref = null) { } - visitInstanceOfExpression(node, ref = null) { - this.visit(node.expression, node); - this.visit(node.isType, node); - } - visitIntegerLiteralExpression(node, ref = null) { } - visitStringLiteralExpression(node, ref = null) { } - visitTemplateLiteralExpression(node, ref = null) { } - visitRegexpLiteralExpression(node, ref = null) { } - visitNewExpression(node, ref = null) { - this.visit(node.typeName, node); - this.visit(node.typeArguments, node); - this.visit(node.args, node); - } - visitParenthesizedExpression(node, ref = null) { - this.visit(node.expression, node); - } - visitPropertyAccessExpression(node, ref = null) { - this.visit(node.property, node); - this.visit(node.expression, node); - } - visitTernaryExpression(node, ref = null) { - this.visit(node.condition, node); - this.visit(node.ifThen, node); - this.visit(node.ifElse, node); - } - visitUnaryExpression(node, ref = null) { - this.visit(node.operand, node); - } - visitUnaryPostfixExpression(node, ref = null) { - this.visit(node.operand, node); - } - visitUnaryPrefixExpression(node, ref = null) { - this.visit(node.operand, node); - } - visitSuperExpression(node, ref = null) { } - visitFalseExpression(node, ref = null) { } - visitTrueExpression(node, ref = null) { } - visitThisExpression(node, ref = null) { } - visitNullExpression(node, ref = null) { } - visitConstructorExpression(node, ref = null) { } - visitNodeAndTerminate(statement, ref = null) { } - visitBlockStatement(node, ref = null) { - this.visit(node.statements, node); - } - visitBreakStatement(node, ref = null) { - this.visit(node.label, node); - } - visitContinueStatement(node, ref = null) { - this.visit(node.label, node); - } - visitClassDeclaration(node, isDefault = false, ref = null) { - this.visit(node.name, node); - this.visit(node.decorators, node); - if (node.isGeneric ? node.typeParameters != null : node.typeParameters == null) { - this.visit(node.typeParameters, node); - this.visit(node.extendsType, node); - this.visit(node.implementsTypes, node); - this.visit(node.members, node); - } - else { - throw new Error("Expected to type parameters to match class declaration, but found type mismatch instead!"); - } - } - visitDoStatement(node, ref = null) { - this.visit(node.condition, node); - this.visit(node.body, node); - } - visitEmptyStatement(node, ref = null) { } - visitEnumDeclaration(node, isDefault = false, ref = null) { - this.visit(node.name, node); - this.visit(node.decorators, node); - this.visit(node.values, node); - } - visitEnumValueDeclaration(node, ref = null) { - this.visit(node.name, node); - this.visit(node.initializer, node); - } - visitExportImportStatement(node, ref = null) { - this.visit(node.name, node); - this.visit(node.externalName, node); - } - visitExportMember(node, ref = null) { - this.visit(node.localName, node); - this.visit(node.exportedName, node); - } - visitExportStatement(node, ref = null) { - this.visit(node.path, node); - this.visit(node.members, node); - } - visitExportDefaultStatement(node, ref = null) { - this.visit(node.declaration, node); - } - visitExpressionStatement(node, ref = null) { - this.visit(node.expression, ref); - } - visitFieldDeclaration(node, ref = null) { - this.visit(node.name, node); - this.visit(node.type, node); - this.visit(node.initializer, node); - this.visit(node.decorators, node); - } - visitForStatement(node, ref = null) { - this.visit(node.initializer, node); - this.visit(node.condition, node); - this.visit(node.incrementor, node); - this.visit(node.body, node); - } - visitFunctionDeclaration(node, isDefault = false, ref = null) { - this.visit(node.name, node); - this.visit(node.decorators, node); - this.visit(node.typeParameters, node); - this.visit(node.signature, node); - this.visit(node.body, node); - } - visitIfStatement(node, ref = null) { - this.visit(node.condition, node); - this.visit(node.ifTrue, node); - this.visit(node.ifFalse, node); - } - visitImportDeclaration(node, ref = null) { - this.visit(node.foreignName, node); - this.visit(node.name, node); - this.visit(node.decorators, node); - } - visitImportStatement(node, ref = null) { - this.visit(node.namespaceName, node); - this.visit(node.declarations, node); - } - visitIndexSignature(node, ref = null) { - this.visit(node.keyType, node); - this.visit(node.valueType, node); - } - visitInterfaceDeclaration(node, isDefault = false, ref = null) { - this.visit(node.name, node); - this.visit(node.typeParameters, node); - this.visit(node.implementsTypes, node); - this.visit(node.extendsType, node); - this.visit(node.members, node); - } - visitMethodDeclaration(node, ref = null) { - this.visit(node.name, node); - this.visit(node.typeParameters, node); - this.visit(node.signature, node); - this.visit(node.decorators, node); - this.visit(node.body, node); - } - visitNamespaceDeclaration(node, isDefault = false, ref = null) { - this.visit(node.name, node); - this.visit(node.decorators, node); - this.visit(node.members, node); - } - visitReturnStatement(node, ref = null) { - this.visit(node.value, node); - } - visitSwitchCase(node, ref = null) { - this.visit(node.label, node); - this.visit(node.statements, node); - } - visitSwitchStatement(node, ref = null) { - this.visit(node.condition, node); - this.visit(node.cases, node); - } - visitThrowStatement(node, ref = null) { - this.visit(node.value, node); - } - visitTryStatement(node, ref = null) { - this.visit(node.bodyStatements, node); - this.visit(node.catchVariable, node); - this.visit(node.catchStatements, node); - this.visit(node.finallyStatements, node); - } - visitTypeDeclaration(node, ref = null) { - this.visit(node.name, node); - this.visit(node.decorators, node); - this.visit(node.type, node); - this.visit(node.typeParameters, node); - } - visitVariableDeclaration(node, ref = null) { - this.visit(node.name, node); - this.visit(node.type, node); - this.visit(node.initializer, node); - } - visitVariableStatement(node, ref = null) { - this.visit(node.decorators, node); - this.visit(node.declarations, node); - } - visitWhileStatement(node, ref = null) { - this.visit(node.condition, node); - this.visit(node.body, node); - } - visitVoidStatement(node, ref = null) { } - visitComment(node, ref = null) { } - visitDecoratorNode(node, ref = null) { - this.visit(node.name, node); - this.visit(node.args, node); - } - visitParameter(node, ref = null) { - this.visit(node.name, node); - this.visit(node.implicitFieldDeclaration, node); - this.visit(node.initializer, node); - this.visit(node.type, node); - } - visitCompiledExpression(node, ref = null) { } - visitForOfStatement(node, ref = null) { - this.visit(node.body, node); - this.visit(node.variable, node); - this.visit(node.iterable, node); - } - visitModuleDeclaration(node, ref = null) { } - visitOmittedExpression(node, ref = null) { } + currentSource = null; + visit(node, ref = null) { + if (node == null) return; + if (node instanceof Array) { + for (const n of node) { + this._visit(n, ref); + } + } else { + this._visit(node, ref); + } + } + _visit(node, ref) { + switch (node.kind) { + case 0: + this.visitSource(node, ref); + break; + case 1: + this.visitNamedTypeNode(node, ref); + break; + case 2: + this.visitFunctionTypeNode(node, ref); + break; + case 3: + this.visitTypeName(node, ref); + break; + case 4: + this.visitTypeParameter(node, ref); + break; + case 6: + this.visitIdentifierExpression(node, ref); + break; + case 7: + this.visitAssertionExpression(node, ref); + break; + case 8: + this.visitBinaryExpression(node, ref); + break; + case 9: + this.visitCallExpression(node, ref); + break; + case 10: + this.visitClassExpression(node, ref); + break; + case 11: + this.visitCommaExpression(node, ref); + break; + case 12: + this.visitElementAccessExpression(node, ref); + break; + case 14: + this.visitFunctionExpression(node, ref); + break; + case 15: + this.visitInstanceOfExpression(node, ref); + break; + case 16: + this.visitLiteralExpression(node, ref); + break; + case 17: + this.visitNewExpression(node, ref); + break; + case 20: + this.visitParenthesizedExpression(node, ref); + break; + case 21: + this.visitPropertyAccessExpression(node, ref); + break; + case 22: + this.visitTernaryExpression(node, ref); + break; + case 27: + this.visitUnaryPostfixExpression(node, ref); + break; + case 28: + this.visitUnaryPrefixExpression(node, ref); + break; + case 30: + this.visitBlockStatement(node, ref); + break; + case 31: + this.visitBreakStatement(node, ref); + break; + case 32: + this.visitContinueStatement(node, ref); + break; + case 33: + this.visitDoStatement(node, ref); + break; + case 34: + this.visitEmptyStatement(node, ref); + break; + case 35: + this.visitExportStatement(node, ref); + break; + case 36: + this.visitExportDefaultStatement(node, ref); + break; + case 37: + this.visitExportImportStatement(node, ref); + break; + case 38: + this.visitExpressionStatement(node, ref); + break; + case 39: + this.visitForStatement(node, ref); + break; + case 41: + this.visitIfStatement(node, ref); + break; + case 42: + this.visitImportStatement(node, ref); + break; + case 43: + this.visitReturnStatement(node, ref); + break; + case 44: + this.visitSwitchStatement(node, ref); + break; + case 45: + this.visitThrowStatement(node, ref); + break; + case 46: + this.visitTryStatement(node, ref); + break; + case 47: + this.visitVariableStatement(node, ref); + break; + case 49: + this.visitWhileStatement(node, ref); + break; + case 51: + this.visitClassDeclaration(node, false, ref); + break; + case 52: + this.visitEnumDeclaration(node, false, ref); + break; + case 53: + this.visitEnumValueDeclaration(node, ref); + break; + case 54: + this.visitFieldDeclaration(node, ref); + break; + case 55: + this.visitFunctionDeclaration(node, false, ref); + break; + case 56: + this.visitImportDeclaration(node, ref); + break; + case 57: + this.visitInterfaceDeclaration(node, false, ref); + break; + case 58: + this.visitMethodDeclaration(node, ref); + break; + case 59: + this.visitNamespaceDeclaration(node, false, ref); + break; + case 60: + this.visitTypeDeclaration(node, ref); + break; + case 61: + this.visitVariableDeclaration(node, ref); + break; + case 62: + this.visitDecoratorNode(node, ref); + break; + case 63: + this.visitExportMember(node, ref); + break; + case 64: + this.visitSwitchCase(node, ref); + break; + case 65: + this.visitIndexSignature(node, ref); + break; + case 18: + this.visitNullExpression(node, ref); + break; + case 25: { + this.visitTrueExpression(node, ref); + break; + } + case 13: { + this.visitFalseExpression(node, ref); + break; + } + case 29: { + this.visitCompiledExpression(node, ref); + break; + } + case 26: { + this.visitConstructorExpression(node, ref); + break; + } + case 66: { + this.visitComment(node, ref); + break; + } + case 40: { + this.visitForOfStatement(node, ref); + break; + } + case 50: { + this.visitModuleDeclaration(node, ref); + break; + } + case 19: { + this.visitOmittedExpression(node, ref); + break; + } + case 5: { + this.visitParameter(node, ref); + break; + } + case 23: { + this.visitSuperExpression(node, ref); + break; + } + case 24: { + this.visitThisExpression(node, ref); + break; + } + case 48: { + this.visitVoidStatement(node, ref); + break; + } + default: + throw new Error("Could not visit invalid type!"); + } + } + visitSource(node, ref = null) { + this.currentSource = node; + this.visit(node.statements, node); + this.currentSource = null; + } + visitTypeNode(node, ref = null) {} + visitTypeName(node, ref = null) { + this.visit(node.identifier, node); + this.visit(node.next, node); + } + visitNamedTypeNode(node, ref = null) { + this.visit(node.name, node); + this.visit(node.typeArguments, node); + } + visitFunctionTypeNode(node, ref = null) { + this.visit(node.parameters, node); + this.visit(node.returnType, node); + this.visit(node.explicitThisType, node); + } + visitTypeParameter(node, ref = null) { + this.visit(node.name, node); + this.visit(node.extendsType, node); + this.visit(node.defaultType, node); + } + visitIdentifierExpression(node, ref = null) {} + visitArrayLiteralExpression(node, ref = null) { + this.visit(node.elementExpressions, node); + } + visitObjectLiteralExpression(node, ref = null) { + this.visit(node.names, node); + this.visit(node.values, node); + } + visitAssertionExpression(node, ref = null) { + this.visit(node.toType, node); + this.visit(node.expression, node); + } + visitBinaryExpression(node, ref = null) { + this.visit(node.left, node); + this.visit(node.right, node); + } + visitCallExpression(node, ref = null) { + this.visit(node.expression, node); + this.visit(node.typeArguments, node); + this.visit(node.args, node); + } + visitClassExpression(node, ref = null) { + this.visit(node.declaration, node); + } + visitCommaExpression(node, ref = null) { + this.visit(node.expressions, node); + } + visitElementAccessExpression(node, ref = null) { + this.visit(node.elementExpression, node); + this.visit(node.expression, node); + } + visitFunctionExpression(node, ref = null) { + this.visit(node.declaration, node); + } + visitLiteralExpression(node, ref = null) { + switch (node.literalKind) { + case 0: + this.visitFloatLiteralExpression(node); + break; + case 1: + this.visitIntegerLiteralExpression(node); + break; + case 2: + this.visitStringLiteralExpression(node); + break; + case 3: + this.visitTemplateLiteralExpression(node); + break; + case 4: + this.visitRegexpLiteralExpression(node); + break; + case 5: + this.visitArrayLiteralExpression(node); + break; + case 6: + this.visitObjectLiteralExpression(node); + break; + default: + throw new Error("Invalid LiteralKind at visitLiteralExpression(): " + node.literalKind); + } + } + visitFloatLiteralExpression(node, ref = null) {} + visitInstanceOfExpression(node, ref = null) { + this.visit(node.expression, node); + this.visit(node.isType, node); + } + visitIntegerLiteralExpression(node, ref = null) {} + visitStringLiteralExpression(node, ref = null) {} + visitTemplateLiteralExpression(node, ref = null) {} + visitRegexpLiteralExpression(node, ref = null) {} + visitNewExpression(node, ref = null) { + this.visit(node.typeName, node); + this.visit(node.typeArguments, node); + this.visit(node.args, node); + } + visitParenthesizedExpression(node, ref = null) { + this.visit(node.expression, node); + } + visitPropertyAccessExpression(node, ref = null) { + this.visit(node.property, node); + this.visit(node.expression, node); + } + visitTernaryExpression(node, ref = null) { + this.visit(node.condition, node); + this.visit(node.ifThen, node); + this.visit(node.ifElse, node); + } + visitUnaryExpression(node, ref = null) { + this.visit(node.operand, node); + } + visitUnaryPostfixExpression(node, ref = null) { + this.visit(node.operand, node); + } + visitUnaryPrefixExpression(node, ref = null) { + this.visit(node.operand, node); + } + visitSuperExpression(node, ref = null) {} + visitFalseExpression(node, ref = null) {} + visitTrueExpression(node, ref = null) {} + visitThisExpression(node, ref = null) {} + visitNullExpression(node, ref = null) {} + visitConstructorExpression(node, ref = null) {} + visitNodeAndTerminate(statement, ref = null) {} + visitBlockStatement(node, ref = null) { + this.visit(node.statements, node); + } + visitBreakStatement(node, ref = null) { + this.visit(node.label, node); + } + visitContinueStatement(node, ref = null) { + this.visit(node.label, node); + } + visitClassDeclaration(node, isDefault = false, ref = null) { + this.visit(node.name, node); + this.visit(node.decorators, node); + if (node.isGeneric ? node.typeParameters != null : node.typeParameters == null) { + this.visit(node.typeParameters, node); + this.visit(node.extendsType, node); + this.visit(node.implementsTypes, node); + this.visit(node.members, node); + } else { + throw new Error("Expected to type parameters to match class declaration, but found type mismatch instead!"); + } + } + visitDoStatement(node, ref = null) { + this.visit(node.condition, node); + this.visit(node.body, node); + } + visitEmptyStatement(node, ref = null) {} + visitEnumDeclaration(node, isDefault = false, ref = null) { + this.visit(node.name, node); + this.visit(node.decorators, node); + this.visit(node.values, node); + } + visitEnumValueDeclaration(node, ref = null) { + this.visit(node.name, node); + this.visit(node.initializer, node); + } + visitExportImportStatement(node, ref = null) { + this.visit(node.name, node); + this.visit(node.externalName, node); + } + visitExportMember(node, ref = null) { + this.visit(node.localName, node); + this.visit(node.exportedName, node); + } + visitExportStatement(node, ref = null) { + this.visit(node.path, node); + this.visit(node.members, node); + } + visitExportDefaultStatement(node, ref = null) { + this.visit(node.declaration, node); + } + visitExpressionStatement(node, ref = null) { + this.visit(node.expression, ref); + } + visitFieldDeclaration(node, ref = null) { + this.visit(node.name, node); + this.visit(node.type, node); + this.visit(node.initializer, node); + this.visit(node.decorators, node); + } + visitForStatement(node, ref = null) { + this.visit(node.initializer, node); + this.visit(node.condition, node); + this.visit(node.incrementor, node); + this.visit(node.body, node); + } + visitFunctionDeclaration(node, isDefault = false, ref = null) { + this.visit(node.name, node); + this.visit(node.decorators, node); + this.visit(node.typeParameters, node); + this.visit(node.signature, node); + this.visit(node.body, node); + } + visitIfStatement(node, ref = null) { + this.visit(node.condition, node); + this.visit(node.ifTrue, node); + this.visit(node.ifFalse, node); + } + visitImportDeclaration(node, ref = null) { + this.visit(node.foreignName, node); + this.visit(node.name, node); + this.visit(node.decorators, node); + } + visitImportStatement(node, ref = null) { + this.visit(node.namespaceName, node); + this.visit(node.declarations, node); + } + visitIndexSignature(node, ref = null) { + this.visit(node.keyType, node); + this.visit(node.valueType, node); + } + visitInterfaceDeclaration(node, isDefault = false, ref = null) { + this.visit(node.name, node); + this.visit(node.typeParameters, node); + this.visit(node.implementsTypes, node); + this.visit(node.extendsType, node); + this.visit(node.members, node); + } + visitMethodDeclaration(node, ref = null) { + this.visit(node.name, node); + this.visit(node.typeParameters, node); + this.visit(node.signature, node); + this.visit(node.decorators, node); + this.visit(node.body, node); + } + visitNamespaceDeclaration(node, isDefault = false, ref = null) { + this.visit(node.name, node); + this.visit(node.decorators, node); + this.visit(node.members, node); + } + visitReturnStatement(node, ref = null) { + this.visit(node.value, node); + } + visitSwitchCase(node, ref = null) { + this.visit(node.label, node); + this.visit(node.statements, node); + } + visitSwitchStatement(node, ref = null) { + this.visit(node.condition, node); + this.visit(node.cases, node); + } + visitThrowStatement(node, ref = null) { + this.visit(node.value, node); + } + visitTryStatement(node, ref = null) { + this.visit(node.bodyStatements, node); + this.visit(node.catchVariable, node); + this.visit(node.catchStatements, node); + this.visit(node.finallyStatements, node); + } + visitTypeDeclaration(node, ref = null) { + this.visit(node.name, node); + this.visit(node.decorators, node); + this.visit(node.type, node); + this.visit(node.typeParameters, node); + } + visitVariableDeclaration(node, ref = null) { + this.visit(node.name, node); + this.visit(node.type, node); + this.visit(node.initializer, node); + } + visitVariableStatement(node, ref = null) { + this.visit(node.decorators, node); + this.visit(node.declarations, node); + } + visitWhileStatement(node, ref = null) { + this.visit(node.condition, node); + this.visit(node.body, node); + } + visitVoidStatement(node, ref = null) {} + visitComment(node, ref = null) {} + visitDecoratorNode(node, ref = null) { + this.visit(node.name, node); + this.visit(node.args, node); + } + visitParameter(node, ref = null) { + this.visit(node.name, node); + this.visit(node.implicitFieldDeclaration, node); + this.visit(node.initializer, node); + this.visit(node.type, node); + } + visitCompiledExpression(node, ref = null) {} + visitForOfStatement(node, ref = null) { + this.visit(node.body, node); + this.visit(node.variable, node); + this.visit(node.iterable, node); + } + visitModuleDeclaration(node, ref = null) {} + visitOmittedExpression(node, ref = null) {} } -//# sourceMappingURL=visitor.js.map \ No newline at end of file +//# sourceMappingURL=visitor.js.map diff --git a/transform/src/builder.ts b/transform/src/builder.ts index 1706a48..64665e7 100644 --- a/transform/src/builder.ts +++ b/transform/src/builder.ts @@ -1,1467 +1,1361 @@ // Taken from https://github.com/as-pect/visitor-as/blob/master/src/astBuilder.ts // tslint:disable: as-internal-case -import { - CommonFlags, - TypeNode, - Node, - NodeKind, - Source, - NamedTypeNode, - FunctionTypeNode, - TypeParameterNode, - IdentifierExpression, - CallExpression, - ClassExpression, - ElementAccessExpression, - FunctionExpression, - InstanceOfExpression, - LiteralExpression, - NewExpression, - ParenthesizedExpression, - PropertyAccessExpression, - TernaryExpression, - UnaryPostfixExpression, - UnaryPrefixExpression, - BlockStatement, - BreakStatement, - ContinueStatement, - DoStatement, - EmptyStatement, - ExportStatement, - ExportDefaultStatement, - ExportImportStatement, - ExpressionStatement, - ForStatement, - IfStatement, - ImportStatement, - ReturnStatement, - SwitchStatement, - ThrowStatement, - TryStatement, - VariableStatement, - WhileStatement, - ClassDeclaration, - EnumDeclaration, - EnumValueDeclaration, - FieldDeclaration, - FunctionDeclaration, - ImportDeclaration, - InterfaceDeclaration, - MethodDeclaration, - NamespaceDeclaration, - TypeDeclaration, - VariableDeclaration, - DecoratorNode, - ExportMember, - ParameterNode, - SwitchCase, - TypeName, - ArrayLiteralExpression, - Expression, - ObjectLiteralExpression, - AssertionKind, - LiteralKind, - FloatLiteralExpression, - StringLiteralExpression, - RegexpLiteralExpression, - UnaryExpression, - ArrowKind, - ParameterKind, - DeclarationStatement, - AssertionExpression, - BinaryExpression, - CommaExpression, - IntegerLiteralExpression, - isTypeOmitted, - operatorTokenToString, - ForOfStatement, - IndexSignatureNode, - TemplateLiteralExpression, - util, -} from "assemblyscript/dist/assemblyscript.js"; +import { CommonFlags, TypeNode, Node, NodeKind, Source, NamedTypeNode, FunctionTypeNode, TypeParameterNode, IdentifierExpression, CallExpression, ClassExpression, ElementAccessExpression, FunctionExpression, InstanceOfExpression, LiteralExpression, NewExpression, ParenthesizedExpression, PropertyAccessExpression, TernaryExpression, UnaryPostfixExpression, UnaryPrefixExpression, BlockStatement, BreakStatement, ContinueStatement, DoStatement, EmptyStatement, ExportStatement, ExportDefaultStatement, ExportImportStatement, ExpressionStatement, ForStatement, IfStatement, ImportStatement, ReturnStatement, SwitchStatement, ThrowStatement, TryStatement, VariableStatement, WhileStatement, ClassDeclaration, EnumDeclaration, EnumValueDeclaration, FieldDeclaration, FunctionDeclaration, ImportDeclaration, InterfaceDeclaration, MethodDeclaration, NamespaceDeclaration, TypeDeclaration, VariableDeclaration, DecoratorNode, ExportMember, ParameterNode, SwitchCase, TypeName, ArrayLiteralExpression, Expression, ObjectLiteralExpression, AssertionKind, LiteralKind, FloatLiteralExpression, StringLiteralExpression, RegexpLiteralExpression, UnaryExpression, ArrowKind, ParameterKind, DeclarationStatement, AssertionExpression, BinaryExpression, CommaExpression, IntegerLiteralExpression, isTypeOmitted, operatorTokenToString, ForOfStatement, IndexSignatureNode, TemplateLiteralExpression, util } from "assemblyscript/dist/assemblyscript.js"; import { Visitor } from "./visitor.js"; function assert(isTruish: T, message: string = "assertion error"): T { - if (!isTruish) throw new Error(message); - return isTruish; + if (!isTruish) throw new Error(message); + return isTruish; } /** An AST builder. */ export class ASTBuilder extends Visitor { - /** Rebuilds the textual source from the specified AST, as far as possible. */ - static build(node: Node): string { - var builder = new ASTBuilder(); - builder.visitNode(node); - return builder.finish(); - } - - private sb: string[] = []; - private indentLevel: number = 0; - visitNode(node: Node) { - return this.visit(node); - } - - visitSource(source: Source): void { - var statements = source.statements; - for (let i = 0, k = statements.length; i < k; ++i) { - this.visitNodeAndTerminate(statements[i]); - } - } - - // types - - visitTypeNode(node: TypeNode): void { - switch (node.kind) { - case NodeKind.NamedType: { - this.visitNamedTypeNode(node); - break; - } - case NodeKind.FunctionType: { - this.visitFunctionTypeNode(node); - break; - } - default: - assert(false); - } - } - - visitTypeName(node: TypeName): void { - this.visitIdentifierExpression(node.identifier); - var sb = this.sb; - var current = node.next; - while (current) { - sb.push("."); - this.visitIdentifierExpression(current.identifier); - current = current.next; - } - } - - visitNamedTypeNode(node: NamedTypeNode): void { - this.visitTypeName(node.name); - var typeArguments = node.typeArguments; - if (typeArguments) { - let numTypeArguments = typeArguments.length; - let sb = this.sb; - if (numTypeArguments) { - sb.push("<"); - this.visitTypeNode(typeArguments[0]); - for (let i = 1; i < numTypeArguments; ++i) { - sb.push(", "); - this.visitTypeNode(typeArguments[i]); - } - sb.push(">"); - } - if (node.isNullable) sb.push(" | null"); - } - } - - visitFunctionTypeNode(node: FunctionTypeNode): void { - var isNullable = node.isNullable; - var sb = this.sb; - sb.push(isNullable ? "((" : "("); - var explicitThisType = node.explicitThisType; - if (explicitThisType) { - sb.push("this: "); - this.visitTypeNode(explicitThisType); - } - var parameters = node.parameters; - var numParameters = parameters.length; - if (numParameters) { - if (explicitThisType) sb.push(", "); - this.serializeParameter(parameters[0]); - for (let i = 1; i < numParameters; ++i) { - sb.push(", "); - this.serializeParameter(parameters[i]); - } - } - var returnType = node.returnType; - if (returnType) { - sb.push(") => "); - this.visitTypeNode(returnType); - } else { - sb.push(") => void"); - } - if (isNullable) sb.push(") | null"); - } - - visitTypeParameter(node: TypeParameterNode): void { - this.visitIdentifierExpression(node.name); - var extendsType = node.extendsType; - if (extendsType) { - this.sb.push(" extends "); - this.visitTypeNode(extendsType); - } - var defaultType = node.defaultType; - if (defaultType) { - this.sb.push("="); - this.visitTypeNode(defaultType); - } - } - - // expressions - - visitIdentifierExpression(node: IdentifierExpression): void { - if (node.isQuoted) this.visitStringLiteral(node.text); - else this.sb.push(node.text); - } - - visitArrayLiteralExpression(node: ArrayLiteralExpression): void { - var sb = this.sb; - sb.push("["); - var elements = node.elementExpressions; - var numElements = elements.length; - if (numElements) { - let element = elements[0]; - if (element) this.visitNode(element); - for (let i = 1; i < numElements; ++i) { - element = elements[i]; - sb.push(", "); - if (element) this.visitNode(element); - } - } - sb.push("]"); - } - - visitObjectLiteralExpression(node: ObjectLiteralExpression): void { - var sb = this.sb; - var names = node.names; - var values = node.values; - var numElements = names.length; - assert(numElements == values.length); - if (numElements) { - sb.push("{\n"); - util.indent(sb, ++this.indentLevel); - this.visitNode(names[0]); - sb.push(": "); - this.visitNode(values[0]); - for (let i = 1; i < numElements; ++i) { - sb.push(",\n"); - util.indent(sb, this.indentLevel); - let name = names[i]; - let value = values[i]; - if (name == value) { - this.visitNode(name); - } else { - this.visitNode(name); - sb.push(": "); - this.visitNode(value); - } - } - sb.push("\n"); - util.indent(sb, --this.indentLevel); - sb.push("}"); + /** Rebuilds the textual source from the specified AST, as far as possible. */ + static build(node: Node): string { + var builder = new ASTBuilder(); + builder.visitNode(node); + return builder.finish(); + } + + private sb: string[] = []; + private indentLevel: number = 0; + visitNode(node: Node) { + return this.visit(node); + } + + visitSource(source: Source): void { + var statements = source.statements; + for (let i = 0, k = statements.length; i < k; ++i) { + this.visitNodeAndTerminate(statements[i]); + } + } + + // types + + visitTypeNode(node: TypeNode): void { + switch (node.kind) { + case NodeKind.NamedType: { + this.visitNamedTypeNode(node); + break; + } + case NodeKind.FunctionType: { + this.visitFunctionTypeNode(node); + break; + } + default: + assert(false); + } + } + + visitTypeName(node: TypeName): void { + this.visitIdentifierExpression(node.identifier); + var sb = this.sb; + var current = node.next; + while (current) { + sb.push("."); + this.visitIdentifierExpression(current.identifier); + current = current.next; + } + } + + visitNamedTypeNode(node: NamedTypeNode): void { + this.visitTypeName(node.name); + var typeArguments = node.typeArguments; + if (typeArguments) { + let numTypeArguments = typeArguments.length; + let sb = this.sb; + if (numTypeArguments) { + sb.push("<"); + this.visitTypeNode(typeArguments[0]); + for (let i = 1; i < numTypeArguments; ++i) { + sb.push(", "); + this.visitTypeNode(typeArguments[i]); + } + sb.push(">"); + } + if (node.isNullable) sb.push(" | null"); + } + } + + visitFunctionTypeNode(node: FunctionTypeNode): void { + var isNullable = node.isNullable; + var sb = this.sb; + sb.push(isNullable ? "((" : "("); + var explicitThisType = node.explicitThisType; + if (explicitThisType) { + sb.push("this: "); + this.visitTypeNode(explicitThisType); + } + var parameters = node.parameters; + var numParameters = parameters.length; + if (numParameters) { + if (explicitThisType) sb.push(", "); + this.serializeParameter(parameters[0]); + for (let i = 1; i < numParameters; ++i) { + sb.push(", "); + this.serializeParameter(parameters[i]); + } + } + var returnType = node.returnType; + if (returnType) { + sb.push(") => "); + this.visitTypeNode(returnType); + } else { + sb.push(") => void"); + } + if (isNullable) sb.push(") | null"); + } + + visitTypeParameter(node: TypeParameterNode): void { + this.visitIdentifierExpression(node.name); + var extendsType = node.extendsType; + if (extendsType) { + this.sb.push(" extends "); + this.visitTypeNode(extendsType); + } + var defaultType = node.defaultType; + if (defaultType) { + this.sb.push("="); + this.visitTypeNode(defaultType); + } + } + + // expressions + + visitIdentifierExpression(node: IdentifierExpression): void { + if (node.isQuoted) this.visitStringLiteral(node.text); + else this.sb.push(node.text); + } + + visitArrayLiteralExpression(node: ArrayLiteralExpression): void { + var sb = this.sb; + sb.push("["); + var elements = node.elementExpressions; + var numElements = elements.length; + if (numElements) { + let element = elements[0]; + if (element) this.visitNode(element); + for (let i = 1; i < numElements; ++i) { + element = elements[i]; + sb.push(", "); + if (element) this.visitNode(element); + } + } + sb.push("]"); + } + + visitObjectLiteralExpression(node: ObjectLiteralExpression): void { + var sb = this.sb; + var names = node.names; + var values = node.values; + var numElements = names.length; + assert(numElements == values.length); + if (numElements) { + sb.push("{\n"); + util.indent(sb, ++this.indentLevel); + this.visitNode(names[0]); + sb.push(": "); + this.visitNode(values[0]); + for (let i = 1; i < numElements; ++i) { + sb.push(",\n"); + util.indent(sb, this.indentLevel); + let name = names[i]; + let value = values[i]; + if (name == value) { + this.visitNode(name); } else { - sb.push("{}"); - } - } - - visitAssertionExpression(node: AssertionExpression): void { - var sb = this.sb; - switch (node.assertionKind) { - case AssertionKind.Prefix: { - sb.push("<"); - if (node.toType) this.visitTypeNode(node.toType); - sb.push(">"); - this.visitNode(node.expression); - break; - } - case AssertionKind.As: { - this.visitNode(node.expression); - sb.push(" as "); - if (node.toType) this.visitTypeNode(node.toType); - break; - } - case AssertionKind.NonNull: { - this.visitNode(node.expression); - sb.push("!"); - break; - } - case AssertionKind.Const: { - this.visitNode(node.expression); - sb.push(" as const"); - break; - } - default: - assert(false); - } - } - - visitBinaryExpression(node: BinaryExpression): void { - var sb = this.sb; - this.visitNode(node.left); - sb.push(" "); - sb.push(operatorTokenToString(node.operator)); - sb.push(" "); - this.visitNode(node.right); - } - - visitCallExpression(node: CallExpression): void { + this.visitNode(name); + sb.push(": "); + this.visitNode(value); + } + } + sb.push("\n"); + util.indent(sb, --this.indentLevel); + sb.push("}"); + } else { + sb.push("{}"); + } + } + + visitAssertionExpression(node: AssertionExpression): void { + var sb = this.sb; + switch (node.assertionKind) { + case AssertionKind.Prefix: { + sb.push("<"); + if (node.toType) this.visitTypeNode(node.toType); + sb.push(">"); this.visitNode(node.expression); - this.visitArguments(node.typeArguments, node.args); - } - - visitArguments( - typeArguments: TypeNode[] | null, - args: Expression[] - ): void { - var sb = this.sb; - if (typeArguments) { - let numTypeArguments = typeArguments.length; - if (numTypeArguments) { - sb.push("<"); - this.visitTypeNode(typeArguments[0]); - for (let i = 1; i < numTypeArguments; ++i) { - sb.push(", "); - this.visitTypeNode(typeArguments[i]); - } - sb.push(">("); - } - } else { - sb.push("("); - } - var numArgs = args.length; - if (numArgs) { - this.visitNode(args[0]); - for (let i = 1; i < numArgs; ++i) { - sb.push(", "); - this.visitNode(args[i]); - } - } - sb.push(")"); - } - - visitClassExpression(node: ClassExpression): void { - var declaration = node.declaration; - this.visitClassDeclaration(declaration); - } - - visitCommaExpression(node: CommaExpression): void { - var expressions = node.expressions; - var numExpressions = expressions.length; - this.visitNode(expressions[0]); - var sb = this.sb; - for (let i = 1; i < numExpressions; ++i) { - sb.push(","); - this.visitNode(expressions[i]); - } - } - - visitElementAccessExpression(node: ElementAccessExpression): void { - var sb = this.sb; + break; + } + case AssertionKind.As: { this.visitNode(node.expression); - sb.push("["); - this.visitNode(node.elementExpression); - sb.push("]"); - } - - visitFunctionExpression(node: FunctionExpression): void { - var declaration = node.declaration; - if (!declaration.arrowKind) { - if (declaration.name.text.length) { - this.sb.push("function "); - } else { - this.sb.push("function"); - } - } else { - assert(declaration.name.text.length == 0); - } - this.visitFunctionCommon(declaration); - } - - visitLiteralExpression(node: LiteralExpression): void { - switch (node.literalKind) { - case LiteralKind.Float: { - this.visitFloatLiteralExpression(node); - break; - } - case LiteralKind.Integer: { - this.visitIntegerLiteralExpression(node); - break; - } - case LiteralKind.String: { - this.visitStringLiteralExpression(node); - break; - } - case LiteralKind.Template: { - this.visitTemplateLiteralExpression(node); - break; - } - case LiteralKind.RegExp: { - this.visitRegexpLiteralExpression(node); - break; - } - case LiteralKind.Array: { - this.visitArrayLiteralExpression(node); - break; - } - case LiteralKind.Object: { - this.visitObjectLiteralExpression(node); - break; - } - default: { - assert(false); - break; - } - } - } - - visitFloatLiteralExpression(node: FloatLiteralExpression): void { - this.sb.push(node.value.toString()); - } - - visitInstanceOfExpression(node: InstanceOfExpression): void { + sb.push(" as "); + if (node.toType) this.visitTypeNode(node.toType); + break; + } + case AssertionKind.NonNull: { this.visitNode(node.expression); - this.sb.push(" instanceof "); - this.visitTypeNode(node.isType); - } - - visitIntegerLiteralExpression(node: IntegerLiteralExpression): void { - this.sb.push(i64_to_string(node.value)); - } - - visitStringLiteral(str: string): void { - var sb = this.sb; - sb.push('"'); - this.visitRawString(str, util.CharCode.DoubleQuote); - sb.push('"'); - } - - private visitRawString(str: string, quote: util.CharCode): void { - var sb = this.sb; - var off = 0; - var i = 0; - for (let k = str.length; i < k;) { - switch (str.charCodeAt(i)) { - case util.CharCode.Null: { - if (i > off) sb.push(str.substring(off, (off = i + 1))); - sb.push("\\0"); - off = ++i; - break; - } - case util.CharCode.Backslash: { - if (i > off) sb.push(str.substring(off, i)); - off = ++i; - sb.push("\\b"); - break; - } - case util.CharCode.Tab: { - if (i > off) sb.push(str.substring(off, i)); - off = ++i; - sb.push("\\t"); - break; - } - case util.CharCode.LineFeed: { - if (i > off) sb.push(str.substring(off, i)); - off = ++i; - sb.push("\\n"); - break; - } - case util.CharCode.VerticalTab: { - if (i > off) sb.push(str.substring(off, i)); - off = ++i; - sb.push("\\v"); - break; - } - case util.CharCode.FormFeed: { - if (i > off) sb.push(str.substring(off, i)); - off = ++i; - sb.push("\\f"); - break; - } - case util.CharCode.CarriageReturn: { - if (i > off) sb.push(str.substring(off, i)); - sb.push("\\r"); - off = ++i; - break; - } - case util.CharCode.DoubleQuote: { - if (quote == util.CharCode.DoubleQuote) { - if (i > off) sb.push(str.substring(off, i)); - sb.push('\\"'); - off = ++i; - } else { - ++i; - } - break; - } - case util.CharCode.SingleQuote: { - if (quote == util.CharCode.SingleQuote) { - if (i > off) sb.push(str.substring(off, i)); - sb.push("\\'"); - off = ++i; - } else { - ++i; - } - break; - } - case util.CharCode.Backslash: { - if (i > off) sb.push(str.substring(off, i)); - sb.push("\\\\"); - off = ++i; - break; - } - case util.CharCode.Backtick: { - if (quote == util.CharCode.Backtick) { - if (i > off) sb.push(str.substring(off, i)); - sb.push("\\`"); - off = ++i; - } else { - ++i; - } - break; - } - default: { - ++i; - break; - } - } - } - if (i > off) sb.push(str.substring(off, i)); - } - - visitStringLiteralExpression(node: StringLiteralExpression): void { - this.visitStringLiteral(node.value); - } - - visitTemplateLiteralExpression(node: TemplateLiteralExpression): void { - var sb = this.sb; - var tag = node.tag; - var parts = node.parts; - var expressions = node.expressions; - if (tag) this.visitNode(tag); - sb.push("`"); - this.visitRawString(parts[0], util.CharCode.Backtick); - assert(parts.length == expressions.length + 1); - for (let i = 0, k = expressions.length; i < k; ++i) { - sb.push("${"); - this.visitNode(expressions[i]); - sb.push("}"); - this.visitRawString(parts[i + 1], util.CharCode.Backtick); - } - sb.push("`"); - } - - visitRegexpLiteralExpression(node: RegexpLiteralExpression): void { - var sb = this.sb; - sb.push("/"); - sb.push(node.pattern); - sb.push("/"); - sb.push(node.patternFlags); - } - - visitNewExpression(node: NewExpression): void { - this.sb.push("new "); - this.visitTypeName(node.typeName); - this.visitArguments(node.typeArguments, node.args); - } - - visitParenthesizedExpression(node: ParenthesizedExpression): void { - var sb = this.sb; - sb.push("("); - this.visitNode(node.expression); - sb.push(")"); - } - - visitPropertyAccessExpression(node: PropertyAccessExpression): void { - this.visitNode(node.expression); - this.sb.push("."); - this.visitIdentifierExpression(node.property); - } - - visitTernaryExpression(node: TernaryExpression): void { - var sb = this.sb; - this.visitNode(node.condition); - sb.push(" ? "); - this.visitNode(node.ifThen); - sb.push(" : "); - this.visitNode(node.ifElse); - } - - visitUnaryExpression(node: UnaryExpression): void { - switch (node.kind) { - case NodeKind.UnaryPostfix: { - this.visitUnaryPostfixExpression(node); - break; - } - case NodeKind.UnaryPrefix: { - this.visitUnaryPrefixExpression(node); - break; - } - default: - assert(false); - } - } - - visitUnaryPostfixExpression(node: UnaryPostfixExpression): void { - this.visitNode(node.operand); - this.sb.push(operatorTokenToString(node.operator)); - } - - visitUnaryPrefixExpression(node: UnaryPrefixExpression): void { - this.sb.push(operatorTokenToString(node.operator)); - this.visitNode(node.operand); - } - - // statements - - visitNodeAndTerminate(node: Node): void { - this.visitNode(node); - var sb = this.sb; - if ( - !sb.length || // leading EmptyStatement - node.kind == NodeKind.Variable || // potentially assigns a FunctionExpression - node.kind == NodeKind.Expression // potentially assigns a FunctionExpression - ) { - sb.push(";\n"); - } else { - let last = sb[sb.length - 1]; - let lastCharPos = last.length - 1; - if ( - lastCharPos >= 0 && - (last.charCodeAt(lastCharPos) == util.CharCode.CloseBrace || - last.charCodeAt(lastCharPos) == util.CharCode.Semicolon) - ) { - sb.push("\n"); - } else { - sb.push(";\n"); - } - } - } - - visitBlockStatement(node: BlockStatement): void { - var sb = this.sb; - var statements = node.statements; - var numStatements = statements.length; - if (numStatements) { - sb.push("{\n"); - let indentLevel = ++this.indentLevel; - for (let i = 0; i < numStatements; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(statements[i]); - } - util.indent(sb, --this.indentLevel); - sb.push("}"); - } else { - sb.push("{}"); - } - } - - visitBreakStatement(node: BreakStatement): void { - var label = node.label; - if (label) { - this.sb.push("break "); - this.visitIdentifierExpression(label); - } else { - this.sb.push("break"); - } - } - - visitContinueStatement(node: ContinueStatement): void { - var label = node.label; - if (label) { - this.sb.push("continue "); - this.visitIdentifierExpression(label); - } else { - this.sb.push("continue"); - } - } - - visitClassDeclaration(node: ClassDeclaration, isDefault = false): void { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - var sb = this.sb; - if (isDefault) { - sb.push("export default "); - } else { - this.serializeExternalModifiers(node); - } - if (node.is(CommonFlags.Abstract)) sb.push("abstract "); - if (node.name.text.length) { - sb.push("class "); - this.visitIdentifierExpression(node.name); - } else { - sb.push("class"); - } - var typeParameters = node.typeParameters; - if (typeParameters != null && typeParameters.length > 0) { - sb.push("<"); - this.visitTypeParameter(typeParameters[0]); - for (let i = 1, k = typeParameters.length; i < k; ++i) { - sb.push(", "); - this.visitTypeParameter(typeParameters[i]); - } - sb.push(">"); - } - var extendsType = node.extendsType; - if (extendsType) { - sb.push(" extends "); - this.visitTypeNode(extendsType); - } - var implementsTypes = node.implementsTypes; - if (implementsTypes) { - let numImplementsTypes = implementsTypes.length; - if (numImplementsTypes) { - sb.push(" implements "); - this.visitTypeNode(implementsTypes[0]); - for (let i = 1; i < numImplementsTypes; ++i) { - sb.push(", "); - this.visitTypeNode(implementsTypes[i]); - } - } - } - var indexSignature = node.indexSignature; - var members = node.members; - var numMembers = members.length; - if (indexSignature !== null || numMembers) { - sb.push(" {\n"); - let indentLevel = ++this.indentLevel; - if (indexSignature) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(indexSignature); - } - for (let i = 0, k = members.length; i < k; ++i) { - let member = members[i]; - if ( - member.kind != NodeKind.FieldDeclaration || - (member).parameterIndex < 0 - ) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(member); - } - } - util.indent(sb, --this.indentLevel); - sb.push("}"); - } else { - sb.push(" {}"); - } - } - - visitDoStatement(node: DoStatement): void { - var sb = this.sb; - sb.push("do "); - this.visitNode(node.body); - if (node.body.kind == NodeKind.Block) { - sb.push(" while ("); - } else { - util.indent(sb, this.indentLevel); - sb.push("while ("); - } - this.visitNode(node.condition); - sb.push(")"); - } - - visitEmptyStatement(node: EmptyStatement): void { - /* nop */ - } - - visitEnumDeclaration(node: EnumDeclaration, isDefault = false): void { - var sb = this.sb; - if (isDefault) { - sb.push("export default "); - } else { - this.serializeExternalModifiers(node); - } - if (node.is(CommonFlags.Const)) sb.push("const "); - sb.push("enum "); - this.visitIdentifierExpression(node.name); - var values = node.values; - var numValues = values.length; - if (numValues) { - sb.push(" {\n"); - let indentLevel = ++this.indentLevel; - util.indent(sb, indentLevel); - this.visitEnumValueDeclaration(node.values[0]); - for (let i = 1; i < numValues; ++i) { - sb.push(",\n"); - util.indent(sb, indentLevel); - this.visitEnumValueDeclaration(node.values[i]); - } - sb.push("\n"); - util.indent(sb, --this.indentLevel); - sb.push("}"); - } else { - sb.push(" {}"); - } - } - - visitEnumValueDeclaration(node: EnumValueDeclaration): void { - this.visitIdentifierExpression(node.name); - var initializer = node.initializer; - if (initializer) { - this.sb.push(" = "); - this.visitNode(initializer); - } - } - - visitExportImportStatement(node: ExportImportStatement): void { - var sb = this.sb; - sb.push("export import "); - this.visitIdentifierExpression(node.externalName); - sb.push(" = "); - this.visitIdentifierExpression(node.name); - } - - visitExportMember(node: ExportMember): void { - this.visitIdentifierExpression(node.localName); - if (node.exportedName.text != node.localName.text) { - this.sb.push(" as "); - this.visitIdentifierExpression(node.exportedName); - } - } - - visitExportStatement(node: ExportStatement): void { - var sb = this.sb; - if (node.isDeclare) { - sb.push("declare "); - } - var members = node.members; - if (members == null) { - sb.push("export *"); - } else if (members.length > 0) { - let numMembers = members.length; - sb.push("export {\n"); - let indentLevel = ++this.indentLevel; - util.indent(sb, indentLevel); - this.visitExportMember(members[0]); - for (let i = 1; i < numMembers; ++i) { - sb.push(",\n"); - util.indent(sb, indentLevel); - this.visitExportMember(members[i]); - } - --this.indentLevel; - sb.push("\n}"); - } else { - sb.push("export {}"); - } - var path = node.path; - if (path) { - sb.push(" from "); - this.visitStringLiteralExpression(path); - } - sb.push(";"); - } - - visitExportDefaultStatement(node: ExportDefaultStatement): void { - var declaration = node.declaration; - switch (declaration.kind) { - case NodeKind.EnumDeclaration: { - this.visitEnumDeclaration(declaration, true); - break; - } - case NodeKind.FunctionDeclaration: { - this.visitFunctionDeclaration(declaration, true); - break; - } - case NodeKind.ClassDeclaration: { - this.visitClassDeclaration(declaration, true); - break; - } - case NodeKind.InterfaceDeclaration: { - this.visitInterfaceDeclaration(declaration, true); - break; - } - case NodeKind.NamespaceDeclaration: { - this.visitNamespaceDeclaration(declaration, true); - break; - } - default: - assert(false); - } - } - - visitExpressionStatement(node: ExpressionStatement): void { + sb.push("!"); + break; + } + case AssertionKind.Const: { this.visitNode(node.expression); - } - - visitFieldDeclaration(node: FieldDeclaration): void { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - this.serializeAccessModifiers(node); - this.visitIdentifierExpression(node.name); - var sb = this.sb; - if (node.flags & CommonFlags.DefinitelyAssigned) { - sb.push("!"); - } - var type = node.type; - if (type) { - sb.push(": "); - this.visitTypeNode(type); - } - var initializer = node.initializer; - if (initializer) { - sb.push(" = "); - this.visitNode(initializer); - } - } - - visitForStatement(node: ForStatement): void { - var sb = this.sb; - sb.push("for ("); - var initializer = node.initializer; - if (initializer) { - this.visitNode(initializer); - } - var condition = node.condition; - if (condition) { - sb.push("; "); - this.visitNode(condition); - } else { - sb.push(";"); - } - var incrementor = node.incrementor; - if (incrementor) { - sb.push("; "); - this.visitNode(incrementor); - } else { - sb.push(";"); - } - sb.push(") "); - this.visitNode(node.body); - } - - visitForOfStatement(node: ForOfStatement): void { - var sb = this.sb; - sb.push("for ("); - this.visitNode(node.variable); - sb.push(" of "); - this.visitNode(node.iterable); - sb.push(") "); - this.visitNode(node.body); - } - - visitFunctionDeclaration( - node: FunctionDeclaration, - isDefault = false - ): void { - var sb = this.sb; - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - if (isDefault) { - sb.push("export default "); - } else { - this.serializeExternalModifiers(node); - this.serializeAccessModifiers(node); - } - if (node.name.text.length) { - sb.push("function "); - } else { - sb.push("function"); - } - this.visitFunctionCommon(node); - } - - visitFunctionCommon(node: FunctionDeclaration): void { - var sb = this.sb; - this.visitIdentifierExpression(node.name); - var signature = node.signature; - var typeParameters = node.typeParameters; - if (typeParameters) { - let numTypeParameters = typeParameters.length; - if (numTypeParameters) { - sb.push("<"); - this.visitTypeParameter(typeParameters[0]); - for (let i = 1; i < numTypeParameters; ++i) { - sb.push(", "); - this.visitTypeParameter(typeParameters[i]); - } - sb.push(">"); - } - } + sb.push(" as const"); + break; + } + default: + assert(false); + } + } + + visitBinaryExpression(node: BinaryExpression): void { + var sb = this.sb; + this.visitNode(node.left); + sb.push(" "); + sb.push(operatorTokenToString(node.operator)); + sb.push(" "); + this.visitNode(node.right); + } + + visitCallExpression(node: CallExpression): void { + this.visitNode(node.expression); + this.visitArguments(node.typeArguments, node.args); + } + + visitArguments(typeArguments: TypeNode[] | null, args: Expression[]): void { + var sb = this.sb; + if (typeArguments) { + let numTypeArguments = typeArguments.length; + if (numTypeArguments) { + sb.push("<"); + this.visitTypeNode(typeArguments[0]); + for (let i = 1; i < numTypeArguments; ++i) { + sb.push(", "); + this.visitTypeNode(typeArguments[i]); + } + sb.push(">("); + } + } else { + sb.push("("); + } + var numArgs = args.length; + if (numArgs) { + this.visitNode(args[0]); + for (let i = 1; i < numArgs; ++i) { + sb.push(", "); + this.visitNode(args[i]); + } + } + sb.push(")"); + } + + visitClassExpression(node: ClassExpression): void { + var declaration = node.declaration; + this.visitClassDeclaration(declaration); + } + + visitCommaExpression(node: CommaExpression): void { + var expressions = node.expressions; + var numExpressions = expressions.length; + this.visitNode(expressions[0]); + var sb = this.sb; + for (let i = 1; i < numExpressions; ++i) { + sb.push(","); + this.visitNode(expressions[i]); + } + } + + visitElementAccessExpression(node: ElementAccessExpression): void { + var sb = this.sb; + this.visitNode(node.expression); + sb.push("["); + this.visitNode(node.elementExpression); + sb.push("]"); + } + + visitFunctionExpression(node: FunctionExpression): void { + var declaration = node.declaration; + if (!declaration.arrowKind) { + if (declaration.name.text.length) { + this.sb.push("function "); + } else { + this.sb.push("function"); + } + } else { + assert(declaration.name.text.length == 0); + } + this.visitFunctionCommon(declaration); + } + + visitLiteralExpression(node: LiteralExpression): void { + switch (node.literalKind) { + case LiteralKind.Float: { + this.visitFloatLiteralExpression(node); + break; + } + case LiteralKind.Integer: { + this.visitIntegerLiteralExpression(node); + break; + } + case LiteralKind.String: { + this.visitStringLiteralExpression(node); + break; + } + case LiteralKind.Template: { + this.visitTemplateLiteralExpression(node); + break; + } + case LiteralKind.RegExp: { + this.visitRegexpLiteralExpression(node); + break; + } + case LiteralKind.Array: { + this.visitArrayLiteralExpression(node); + break; + } + case LiteralKind.Object: { + this.visitObjectLiteralExpression(node); + break; + } + default: { + assert(false); + break; + } + } + } + + visitFloatLiteralExpression(node: FloatLiteralExpression): void { + this.sb.push(node.value.toString()); + } + + visitInstanceOfExpression(node: InstanceOfExpression): void { + this.visitNode(node.expression); + this.sb.push(" instanceof "); + this.visitTypeNode(node.isType); + } + + visitIntegerLiteralExpression(node: IntegerLiteralExpression): void { + this.sb.push(i64_to_string(node.value)); + } + + visitStringLiteral(str: string): void { + var sb = this.sb; + sb.push('"'); + this.visitRawString(str, util.CharCode.DoubleQuote); + sb.push('"'); + } + + private visitRawString(str: string, quote: util.CharCode): void { + var sb = this.sb; + var off = 0; + var i = 0; + for (let k = str.length; i < k; ) { + switch (str.charCodeAt(i)) { + case util.CharCode.Null: { + if (i > off) sb.push(str.substring(off, (off = i + 1))); + sb.push("\\0"); + off = ++i; + break; + } + case util.CharCode.Backslash: { + if (i > off) sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\b"); + break; + } + case util.CharCode.Tab: { + if (i > off) sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\t"); + break; + } + case util.CharCode.LineFeed: { + if (i > off) sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\n"); + break; + } + case util.CharCode.VerticalTab: { + if (i > off) sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\v"); + break; + } + case util.CharCode.FormFeed: { + if (i > off) sb.push(str.substring(off, i)); + off = ++i; + sb.push("\\f"); + break; + } + case util.CharCode.CarriageReturn: { + if (i > off) sb.push(str.substring(off, i)); + sb.push("\\r"); + off = ++i; + break; + } + case util.CharCode.DoubleQuote: { + if (quote == util.CharCode.DoubleQuote) { + if (i > off) sb.push(str.substring(off, i)); + sb.push('\\"'); + off = ++i; + } else { + ++i; + } + break; + } + case util.CharCode.SingleQuote: { + if (quote == util.CharCode.SingleQuote) { + if (i > off) sb.push(str.substring(off, i)); + sb.push("\\'"); + off = ++i; + } else { + ++i; + } + break; + } + case util.CharCode.Backslash: { + if (i > off) sb.push(str.substring(off, i)); + sb.push("\\\\"); + off = ++i; + break; + } + case util.CharCode.Backtick: { + if (quote == util.CharCode.Backtick) { + if (i > off) sb.push(str.substring(off, i)); + sb.push("\\`"); + off = ++i; + } else { + ++i; + } + break; + } + default: { + ++i; + break; + } + } + } + if (i > off) sb.push(str.substring(off, i)); + } + + visitStringLiteralExpression(node: StringLiteralExpression): void { + this.visitStringLiteral(node.value); + } + + visitTemplateLiteralExpression(node: TemplateLiteralExpression): void { + var sb = this.sb; + var tag = node.tag; + var parts = node.parts; + var expressions = node.expressions; + if (tag) this.visitNode(tag); + sb.push("`"); + this.visitRawString(parts[0], util.CharCode.Backtick); + assert(parts.length == expressions.length + 1); + for (let i = 0, k = expressions.length; i < k; ++i) { + sb.push("${"); + this.visitNode(expressions[i]); + sb.push("}"); + this.visitRawString(parts[i + 1], util.CharCode.Backtick); + } + sb.push("`"); + } + + visitRegexpLiteralExpression(node: RegexpLiteralExpression): void { + var sb = this.sb; + sb.push("/"); + sb.push(node.pattern); + sb.push("/"); + sb.push(node.patternFlags); + } + + visitNewExpression(node: NewExpression): void { + this.sb.push("new "); + this.visitTypeName(node.typeName); + this.visitArguments(node.typeArguments, node.args); + } + + visitParenthesizedExpression(node: ParenthesizedExpression): void { + var sb = this.sb; + sb.push("("); + this.visitNode(node.expression); + sb.push(")"); + } + + visitPropertyAccessExpression(node: PropertyAccessExpression): void { + this.visitNode(node.expression); + this.sb.push("."); + this.visitIdentifierExpression(node.property); + } + + visitTernaryExpression(node: TernaryExpression): void { + var sb = this.sb; + this.visitNode(node.condition); + sb.push(" ? "); + this.visitNode(node.ifThen); + sb.push(" : "); + this.visitNode(node.ifElse); + } + + visitUnaryExpression(node: UnaryExpression): void { + switch (node.kind) { + case NodeKind.UnaryPostfix: { + this.visitUnaryPostfixExpression(node); + break; + } + case NodeKind.UnaryPrefix: { + this.visitUnaryPrefixExpression(node); + break; + } + default: + assert(false); + } + } + + visitUnaryPostfixExpression(node: UnaryPostfixExpression): void { + this.visitNode(node.operand); + this.sb.push(operatorTokenToString(node.operator)); + } + + visitUnaryPrefixExpression(node: UnaryPrefixExpression): void { + this.sb.push(operatorTokenToString(node.operator)); + this.visitNode(node.operand); + } + + // statements + + visitNodeAndTerminate(node: Node): void { + this.visitNode(node); + var sb = this.sb; + if ( + !sb.length || // leading EmptyStatement + node.kind == NodeKind.Variable || // potentially assigns a FunctionExpression + node.kind == NodeKind.Expression // potentially assigns a FunctionExpression + ) { + sb.push(";\n"); + } else { + let last = sb[sb.length - 1]; + let lastCharPos = last.length - 1; + if (lastCharPos >= 0 && (last.charCodeAt(lastCharPos) == util.CharCode.CloseBrace || last.charCodeAt(lastCharPos) == util.CharCode.Semicolon)) { + sb.push("\n"); + } else { + sb.push(";\n"); + } + } + } + + visitBlockStatement(node: BlockStatement): void { + var sb = this.sb; + var statements = node.statements; + var numStatements = statements.length; + if (numStatements) { + sb.push("{\n"); + let indentLevel = ++this.indentLevel; + for (let i = 0; i < numStatements; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(statements[i]); + } + util.indent(sb, --this.indentLevel); + sb.push("}"); + } else { + sb.push("{}"); + } + } + + visitBreakStatement(node: BreakStatement): void { + var label = node.label; + if (label) { + this.sb.push("break "); + this.visitIdentifierExpression(label); + } else { + this.sb.push("break"); + } + } + + visitContinueStatement(node: ContinueStatement): void { + var label = node.label; + if (label) { + this.sb.push("continue "); + this.visitIdentifierExpression(label); + } else { + this.sb.push("continue"); + } + } + + visitClassDeclaration(node: ClassDeclaration, isDefault = false): void { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + var sb = this.sb; + if (isDefault) { + sb.push("export default "); + } else { + this.serializeExternalModifiers(node); + } + if (node.is(CommonFlags.Abstract)) sb.push("abstract "); + if (node.name.text.length) { + sb.push("class "); + this.visitIdentifierExpression(node.name); + } else { + sb.push("class"); + } + var typeParameters = node.typeParameters; + if (typeParameters != null && typeParameters.length > 0) { + sb.push("<"); + this.visitTypeParameter(typeParameters[0]); + for (let i = 1, k = typeParameters.length; i < k; ++i) { + sb.push(", "); + this.visitTypeParameter(typeParameters[i]); + } + sb.push(">"); + } + var extendsType = node.extendsType; + if (extendsType) { + sb.push(" extends "); + this.visitTypeNode(extendsType); + } + var implementsTypes = node.implementsTypes; + if (implementsTypes) { + let numImplementsTypes = implementsTypes.length; + if (numImplementsTypes) { + sb.push(" implements "); + this.visitTypeNode(implementsTypes[0]); + for (let i = 1; i < numImplementsTypes; ++i) { + sb.push(", "); + this.visitTypeNode(implementsTypes[i]); + } + } + } + var indexSignature = node.indexSignature; + var members = node.members; + var numMembers = members.length; + if (indexSignature !== null || numMembers) { + sb.push(" {\n"); + let indentLevel = ++this.indentLevel; + if (indexSignature) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(indexSignature); + } + for (let i = 0, k = members.length; i < k; ++i) { + let member = members[i]; + if (member.kind != NodeKind.FieldDeclaration || (member).parameterIndex < 0) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(member); + } + } + util.indent(sb, --this.indentLevel); + sb.push("}"); + } else { + sb.push(" {}"); + } + } + + visitDoStatement(node: DoStatement): void { + var sb = this.sb; + sb.push("do "); + this.visitNode(node.body); + if (node.body.kind == NodeKind.Block) { + sb.push(" while ("); + } else { + util.indent(sb, this.indentLevel); + sb.push("while ("); + } + this.visitNode(node.condition); + sb.push(")"); + } + + visitEmptyStatement(node: EmptyStatement): void { + /* nop */ + } + + visitEnumDeclaration(node: EnumDeclaration, isDefault = false): void { + var sb = this.sb; + if (isDefault) { + sb.push("export default "); + } else { + this.serializeExternalModifiers(node); + } + if (node.is(CommonFlags.Const)) sb.push("const "); + sb.push("enum "); + this.visitIdentifierExpression(node.name); + var values = node.values; + var numValues = values.length; + if (numValues) { + sb.push(" {\n"); + let indentLevel = ++this.indentLevel; + util.indent(sb, indentLevel); + this.visitEnumValueDeclaration(node.values[0]); + for (let i = 1; i < numValues; ++i) { + sb.push(",\n"); + util.indent(sb, indentLevel); + this.visitEnumValueDeclaration(node.values[i]); + } + sb.push("\n"); + util.indent(sb, --this.indentLevel); + sb.push("}"); + } else { + sb.push(" {}"); + } + } + + visitEnumValueDeclaration(node: EnumValueDeclaration): void { + this.visitIdentifierExpression(node.name); + var initializer = node.initializer; + if (initializer) { + this.sb.push(" = "); + this.visitNode(initializer); + } + } + + visitExportImportStatement(node: ExportImportStatement): void { + var sb = this.sb; + sb.push("export import "); + this.visitIdentifierExpression(node.externalName); + sb.push(" = "); + this.visitIdentifierExpression(node.name); + } + + visitExportMember(node: ExportMember): void { + this.visitIdentifierExpression(node.localName); + if (node.exportedName.text != node.localName.text) { + this.sb.push(" as "); + this.visitIdentifierExpression(node.exportedName); + } + } + + visitExportStatement(node: ExportStatement): void { + var sb = this.sb; + if (node.isDeclare) { + sb.push("declare "); + } + var members = node.members; + if (members == null) { + sb.push("export *"); + } else if (members.length > 0) { + let numMembers = members.length; + sb.push("export {\n"); + let indentLevel = ++this.indentLevel; + util.indent(sb, indentLevel); + this.visitExportMember(members[0]); + for (let i = 1; i < numMembers; ++i) { + sb.push(",\n"); + util.indent(sb, indentLevel); + this.visitExportMember(members[i]); + } + --this.indentLevel; + sb.push("\n}"); + } else { + sb.push("export {}"); + } + var path = node.path; + if (path) { + sb.push(" from "); + this.visitStringLiteralExpression(path); + } + sb.push(";"); + } + + visitExportDefaultStatement(node: ExportDefaultStatement): void { + var declaration = node.declaration; + switch (declaration.kind) { + case NodeKind.EnumDeclaration: { + this.visitEnumDeclaration(declaration, true); + break; + } + case NodeKind.FunctionDeclaration: { + this.visitFunctionDeclaration(declaration, true); + break; + } + case NodeKind.ClassDeclaration: { + this.visitClassDeclaration(declaration, true); + break; + } + case NodeKind.InterfaceDeclaration: { + this.visitInterfaceDeclaration(declaration, true); + break; + } + case NodeKind.NamespaceDeclaration: { + this.visitNamespaceDeclaration(declaration, true); + break; + } + default: + assert(false); + } + } + + visitExpressionStatement(node: ExpressionStatement): void { + this.visitNode(node.expression); + } + + visitFieldDeclaration(node: FieldDeclaration): void { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + this.serializeAccessModifiers(node); + this.visitIdentifierExpression(node.name); + var sb = this.sb; + if (node.flags & CommonFlags.DefinitelyAssigned) { + sb.push("!"); + } + var type = node.type; + if (type) { + sb.push(": "); + this.visitTypeNode(type); + } + var initializer = node.initializer; + if (initializer) { + sb.push(" = "); + this.visitNode(initializer); + } + } + + visitForStatement(node: ForStatement): void { + var sb = this.sb; + sb.push("for ("); + var initializer = node.initializer; + if (initializer) { + this.visitNode(initializer); + } + var condition = node.condition; + if (condition) { + sb.push("; "); + this.visitNode(condition); + } else { + sb.push(";"); + } + var incrementor = node.incrementor; + if (incrementor) { + sb.push("; "); + this.visitNode(incrementor); + } else { + sb.push(";"); + } + sb.push(") "); + this.visitNode(node.body); + } + + visitForOfStatement(node: ForOfStatement): void { + var sb = this.sb; + sb.push("for ("); + this.visitNode(node.variable); + sb.push(" of "); + this.visitNode(node.iterable); + sb.push(") "); + this.visitNode(node.body); + } + + visitFunctionDeclaration(node: FunctionDeclaration, isDefault = false): void { + var sb = this.sb; + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + if (isDefault) { + sb.push("export default "); + } else { + this.serializeExternalModifiers(node); + this.serializeAccessModifiers(node); + } + if (node.name.text.length) { + sb.push("function "); + } else { + sb.push("function"); + } + this.visitFunctionCommon(node); + } + + visitFunctionCommon(node: FunctionDeclaration): void { + var sb = this.sb; + this.visitIdentifierExpression(node.name); + var signature = node.signature; + var typeParameters = node.typeParameters; + if (typeParameters) { + let numTypeParameters = typeParameters.length; + if (numTypeParameters) { + sb.push("<"); + this.visitTypeParameter(typeParameters[0]); + for (let i = 1; i < numTypeParameters; ++i) { + sb.push(", "); + this.visitTypeParameter(typeParameters[i]); + } + sb.push(">"); + } + } + if (node.arrowKind == ArrowKind.Single) { + let parameters = signature.parameters; + assert(parameters.length == 1); + assert(!signature.explicitThisType); + this.serializeParameter(parameters[0]); + } else { + sb.push("("); + let parameters = signature.parameters; + let numParameters = parameters.length; + let explicitThisType = signature.explicitThisType; + if (explicitThisType) { + sb.push("this: "); + this.visitTypeNode(explicitThisType); + } + if (numParameters) { + if (explicitThisType) sb.push(", "); + this.serializeParameter(parameters[0]); + for (let i = 1; i < numParameters; ++i) { + sb.push(", "); + this.serializeParameter(parameters[i]); + } + } + } + var body = node.body; + var returnType = signature.returnType; + if (node.arrowKind) { + if (body) { if (node.arrowKind == ArrowKind.Single) { - let parameters = signature.parameters; - assert(parameters.length == 1); - assert(!signature.explicitThisType); - this.serializeParameter(parameters[0]); - } else { - sb.push("("); - let parameters = signature.parameters; - let numParameters = parameters.length; - let explicitThisType = signature.explicitThisType; - if (explicitThisType) { - sb.push("this: "); - this.visitTypeNode(explicitThisType); - } - if (numParameters) { - if (explicitThisType) sb.push(", "); - this.serializeParameter(parameters[0]); - for (let i = 1; i < numParameters; ++i) { - sb.push(", "); - this.serializeParameter(parameters[i]); - } - } - } - var body = node.body; - var returnType = signature.returnType; - if (node.arrowKind) { - if (body) { - if (node.arrowKind == ArrowKind.Single) { - assert(isTypeOmitted(returnType)); - } else { - if (isTypeOmitted(returnType)) { - sb.push(")"); - } else { - sb.push("): "); - this.visitTypeNode(returnType); - } - } - sb.push(" => "); - this.visitNode(body); - } else { - assert(!isTypeOmitted(returnType)); - sb.push(" => "); - this.visitTypeNode(returnType); - } - } else { - if ( - !isTypeOmitted(returnType) && - !node.isAny(CommonFlags.Constructor | CommonFlags.Set) - ) { - sb.push("): "); - this.visitTypeNode(returnType); - } else { - sb.push(")"); - } - if (body) { - sb.push(" "); - this.visitNode(body); - } - } - } - - visitIfStatement(node: IfStatement): void { - var sb = this.sb; - sb.push("if ("); - this.visitNode(node.condition); - sb.push(") "); - var ifTrue = node.ifTrue; - this.visitNode(ifTrue); - if (ifTrue.kind != NodeKind.Block) { - sb.push(";\n"); - } - var ifFalse = node.ifFalse; - if (ifFalse) { - if (ifTrue.kind == NodeKind.Block) { - sb.push(" else "); - } else { - sb.push("else "); - } - this.visitNode(ifFalse); - } - } - - visitImportDeclaration(node: ImportDeclaration): void { - var externalName = node.foreignName; - var name = node.name; - this.visitIdentifierExpression(externalName); - if (externalName.text != name.text) { - this.sb.push(" as "); - this.visitIdentifierExpression(name); - } - } - - visitImportStatement(node: ImportStatement): void { - var sb = this.sb; - sb.push("import "); - var declarations = node.declarations; - var namespaceName = node.namespaceName; - if (declarations) { - let numDeclarations = declarations.length; - if (numDeclarations) { - sb.push("{\n"); - let indentLevel = ++this.indentLevel; - util.indent(sb, indentLevel); - this.visitImportDeclaration(declarations[0]); - for (let i = 1; i < numDeclarations; ++i) { - sb.push(",\n"); - util.indent(sb, indentLevel); - this.visitImportDeclaration(declarations[i]); - } - --this.indentLevel; - sb.push("\n} from "); - } else { - sb.push("{} from "); - } - } else if (namespaceName) { - sb.push("* as "); - this.visitIdentifierExpression(namespaceName); - sb.push(" from "); - } - this.visitStringLiteralExpression(node.path); - } - - visitIndexSignature(node: IndexSignatureNode): void { - var sb = this.sb; - sb.push("[key: "); - this.visitTypeNode(node.keyType); - sb.push("]: "); - this.visitTypeNode(node.valueType); - } - - visitInterfaceDeclaration( - node: InterfaceDeclaration, - isDefault = false - ): void { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - var sb = this.sb; - if (isDefault) { - sb.push("export default "); - } else { - this.serializeExternalModifiers(node); - } - sb.push("interface "); - this.visitIdentifierExpression(node.name); - var typeParameters = node.typeParameters; - if (typeParameters != null && typeParameters.length > 0) { - sb.push("<"); - this.visitTypeParameter(typeParameters[0]); - for (let i = 1, k = typeParameters.length; i < k; ++i) { - sb.push(", "); - this.visitTypeParameter(typeParameters[i]); - } - sb.push(">"); - } - var extendsType = node.extendsType; - if (extendsType) { - sb.push(" extends "); - this.visitTypeNode(extendsType); - } - // must not have implementsTypes - sb.push(" {\n"); - var indentLevel = ++this.indentLevel; - var members = node.members; - for (let i = 0, k = members.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(members[i]); - } - --this.indentLevel; - sb.push("}"); - } - - visitMethodDeclaration(node: MethodDeclaration): void { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - this.serializeAccessModifiers(node); - if (node.is(CommonFlags.Get)) { - this.sb.push("get "); - } else if (node.is(CommonFlags.Set)) { - this.sb.push("set "); - } - this.visitFunctionCommon(node); - } - - visitNamespaceDeclaration( - node: NamespaceDeclaration, - isDefault = false - ): void { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - var sb = this.sb; - if (isDefault) { - sb.push("export default "); - } else { - this.serializeExternalModifiers(node); - } - sb.push("namespace "); - this.visitIdentifierExpression(node.name); - var members = node.members; - var numMembers = members.length; - if (numMembers) { - sb.push(" {\n"); - let indentLevel = ++this.indentLevel; - for (let i = 0, k = members.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(members[i]); - } - util.indent(sb, --this.indentLevel); - sb.push("}"); - } else { - sb.push(" {}"); - } - } - - visitReturnStatement(node: ReturnStatement): void { - var value = node.value; - if (value) { - this.sb.push("return "); - this.visitNode(value); + assert(isTypeOmitted(returnType)); } else { - this.sb.push("return"); - } - } - - visitSwitchCase(node: SwitchCase): void { - var sb = this.sb; - var label = node.label; - if (label) { - sb.push("case "); - this.visitNode(label); - sb.push(":\n"); - } else { - sb.push("default:\n"); - } - var statements = node.statements; - var numStatements = statements.length; - if (numStatements) { - let indentLevel = ++this.indentLevel; - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(statements[0]); - for (let i = 1; i < numStatements; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(statements[i]); - } - --this.indentLevel; - } - } - - visitSwitchStatement(node: SwitchStatement): void { - var sb = this.sb; - sb.push("switch ("); - this.visitNode(node.condition); - sb.push(") {\n"); - var indentLevel = ++this.indentLevel; - var cases = node.cases; - for (let i = 0, k = cases.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitSwitchCase(cases[i]); - sb.push("\n"); - } - --this.indentLevel; - sb.push("}"); - } - - visitThrowStatement(node: ThrowStatement): void { - this.sb.push("throw "); - this.visitNode(node.value); - } - - visitTryStatement(node: TryStatement): void { - var sb = this.sb; - sb.push("try {\n"); - var indentLevel = ++this.indentLevel; - var statements = node.bodyStatements; - for (let i = 0, k = statements.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(statements[i]); - } - var catchVariable = node.catchVariable; - if (catchVariable) { - util.indent(sb, indentLevel - 1); - sb.push("} catch ("); - this.visitIdentifierExpression(catchVariable); - sb.push(") {\n"); - let catchStatements = node.catchStatements; - if (catchStatements) { - for (let i = 0, k = catchStatements.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(catchStatements[i]); - } - } - } - var finallyStatements = node.finallyStatements; - if (finallyStatements) { - util.indent(sb, indentLevel - 1); - sb.push("} finally {\n"); - for (let i = 0, k = finallyStatements.length; i < k; ++i) { - util.indent(sb, indentLevel); - this.visitNodeAndTerminate(finallyStatements[i]); - } - } - util.indent(sb, indentLevel - 1); - sb.push("}"); - } - - visitTypeDeclaration(node: TypeDeclaration): void { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - var sb = this.sb; - this.serializeExternalModifiers(node); - sb.push("type "); - this.visitIdentifierExpression(node.name); - var typeParameters = node.typeParameters; - if (typeParameters) { - let numTypeParameters = typeParameters.length; - if (numTypeParameters) { - sb.push("<"); - for (let i = 0; i < numTypeParameters; ++i) { - this.visitTypeParameter(typeParameters[i]); - } - sb.push(">"); - } - } - sb.push(" = "); - this.visitTypeNode(node.type); - } - - visitVariableDeclaration(node: VariableDeclaration): void { - this.visitIdentifierExpression(node.name); - var type = node.type; - var sb = this.sb; - if (node.flags & CommonFlags.DefinitelyAssigned) { - sb.push("!"); - } - if (type) { - sb.push(": "); - this.visitTypeNode(type); - } - var initializer = node.initializer; - if (initializer) { - sb.push(" = "); - this.visitNode(initializer); - } - } - - visitVariableStatement(node: VariableStatement): void { - var decorators = node.decorators; - if (decorators) { - for (let i = 0, k = decorators.length; i < k; ++i) { - this.serializeDecorator(decorators[i]); - } - } - var sb = this.sb; - var declarations = node.declarations; - var numDeclarations = declarations.length; - var firstDeclaration = declarations[0]; - this.serializeExternalModifiers(firstDeclaration); - sb.push( - firstDeclaration.is(CommonFlags.Const) - ? "const " - : firstDeclaration.is(CommonFlags.Let) - ? "let " - : "var " - ); - this.visitVariableDeclaration(node.declarations[0]); - for (let i = 1; i < numDeclarations; ++i) { - sb.push(", "); - this.visitVariableDeclaration(node.declarations[i]); - } - } - - visitWhileStatement(node: WhileStatement): void { - var sb = this.sb; - sb.push("while ("); - this.visitNode(node.condition); - var statement = node.body; - if (statement.kind == NodeKind.Empty) { + if (isTypeOmitted(returnType)) { sb.push(")"); - } else { - sb.push(") "); - this.visitNode(node.body); - } - } - - // other - - serializeDecorator(node: DecoratorNode): void { - var sb = this.sb; - sb.push("@"); - this.visitNode(node.name); - var args = node.args; - if (args) { - sb.push("("); - let numArgs = args.length; - if (numArgs) { - this.visitNode(args[0]); - for (let i = 1; i < numArgs; ++i) { - sb.push(", "); - this.visitNode(args[i]); - } - } - sb.push(")\n"); - } else { - sb.push("\n"); - } - util.indent(sb, this.indentLevel); - } - - serializeParameter(node: ParameterNode): void { - var sb = this.sb; - var kind = node.parameterKind; - var implicitFieldDeclaration = node.implicitFieldDeclaration; - if (implicitFieldDeclaration) { - this.serializeAccessModifiers(implicitFieldDeclaration); - } - if (kind == ParameterKind.Rest) { - sb.push("..."); - } - this.visitIdentifierExpression(node.name); - var type = node.type; - var initializer = node.initializer; - if (type) { - if (kind == ParameterKind.Optional && !initializer) sb.push("?"); - if (!isTypeOmitted(type)) { - sb.push(": "); - this.visitTypeNode(type); - } - } - if (initializer) { - sb.push(" = "); - this.visitNode(initializer); - } - } - - serializeExternalModifiers(node: DeclarationStatement): void { - var sb = this.sb; - if (node.is(CommonFlags.Export)) { - sb.push("export "); - } else if (node.is(CommonFlags.Import)) { - sb.push("import "); - } else if (node.is(CommonFlags.Declare)) { - sb.push("declare "); - } - } - - serializeAccessModifiers(node: DeclarationStatement): void { - var sb = this.sb; - if (node.is(CommonFlags.Public)) { - sb.push("public "); - } else if (node.is(CommonFlags.Private)) { - sb.push("private "); - } else if (node.is(CommonFlags.Protected)) { - sb.push("protected "); - } - if (node.is(CommonFlags.Static)) { - sb.push("static "); - } else if (node.is(CommonFlags.Abstract)) { - sb.push("abstract "); - } - if (node.is(CommonFlags.Readonly)) { - sb.push("readonly "); + } else { + sb.push("): "); + this.visitTypeNode(returnType); + } + } + sb.push(" => "); + this.visitNode(body); + } else { + assert(!isTypeOmitted(returnType)); + sb.push(" => "); + this.visitTypeNode(returnType); + } + } else { + if (!isTypeOmitted(returnType) && !node.isAny(CommonFlags.Constructor | CommonFlags.Set)) { + sb.push("): "); + this.visitTypeNode(returnType); + } else { + sb.push(")"); + } + if (body) { + sb.push(" "); + this.visitNode(body); + } + } + } + + visitIfStatement(node: IfStatement): void { + var sb = this.sb; + sb.push("if ("); + this.visitNode(node.condition); + sb.push(") "); + var ifTrue = node.ifTrue; + this.visitNode(ifTrue); + if (ifTrue.kind != NodeKind.Block) { + sb.push(";\n"); + } + var ifFalse = node.ifFalse; + if (ifFalse) { + if (ifTrue.kind == NodeKind.Block) { + sb.push(" else "); + } else { + sb.push("else "); + } + this.visitNode(ifFalse); + } + } + + visitImportDeclaration(node: ImportDeclaration): void { + var externalName = node.foreignName; + var name = node.name; + this.visitIdentifierExpression(externalName); + if (externalName.text != name.text) { + this.sb.push(" as "); + this.visitIdentifierExpression(name); + } + } + + visitImportStatement(node: ImportStatement): void { + var sb = this.sb; + sb.push("import "); + var declarations = node.declarations; + var namespaceName = node.namespaceName; + if (declarations) { + let numDeclarations = declarations.length; + if (numDeclarations) { + sb.push("{\n"); + let indentLevel = ++this.indentLevel; + util.indent(sb, indentLevel); + this.visitImportDeclaration(declarations[0]); + for (let i = 1; i < numDeclarations; ++i) { + sb.push(",\n"); + util.indent(sb, indentLevel); + this.visitImportDeclaration(declarations[i]); } - } - - finish(): string { - var ret = this.sb.join(""); - this.sb = []; - return ret; - } -} \ No newline at end of file + --this.indentLevel; + sb.push("\n} from "); + } else { + sb.push("{} from "); + } + } else if (namespaceName) { + sb.push("* as "); + this.visitIdentifierExpression(namespaceName); + sb.push(" from "); + } + this.visitStringLiteralExpression(node.path); + } + + visitIndexSignature(node: IndexSignatureNode): void { + var sb = this.sb; + sb.push("[key: "); + this.visitTypeNode(node.keyType); + sb.push("]: "); + this.visitTypeNode(node.valueType); + } + + visitInterfaceDeclaration(node: InterfaceDeclaration, isDefault = false): void { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + var sb = this.sb; + if (isDefault) { + sb.push("export default "); + } else { + this.serializeExternalModifiers(node); + } + sb.push("interface "); + this.visitIdentifierExpression(node.name); + var typeParameters = node.typeParameters; + if (typeParameters != null && typeParameters.length > 0) { + sb.push("<"); + this.visitTypeParameter(typeParameters[0]); + for (let i = 1, k = typeParameters.length; i < k; ++i) { + sb.push(", "); + this.visitTypeParameter(typeParameters[i]); + } + sb.push(">"); + } + var extendsType = node.extendsType; + if (extendsType) { + sb.push(" extends "); + this.visitTypeNode(extendsType); + } + // must not have implementsTypes + sb.push(" {\n"); + var indentLevel = ++this.indentLevel; + var members = node.members; + for (let i = 0, k = members.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(members[i]); + } + --this.indentLevel; + sb.push("}"); + } + + visitMethodDeclaration(node: MethodDeclaration): void { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + this.serializeAccessModifiers(node); + if (node.is(CommonFlags.Get)) { + this.sb.push("get "); + } else if (node.is(CommonFlags.Set)) { + this.sb.push("set "); + } + this.visitFunctionCommon(node); + } + + visitNamespaceDeclaration(node: NamespaceDeclaration, isDefault = false): void { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + var sb = this.sb; + if (isDefault) { + sb.push("export default "); + } else { + this.serializeExternalModifiers(node); + } + sb.push("namespace "); + this.visitIdentifierExpression(node.name); + var members = node.members; + var numMembers = members.length; + if (numMembers) { + sb.push(" {\n"); + let indentLevel = ++this.indentLevel; + for (let i = 0, k = members.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(members[i]); + } + util.indent(sb, --this.indentLevel); + sb.push("}"); + } else { + sb.push(" {}"); + } + } + + visitReturnStatement(node: ReturnStatement): void { + var value = node.value; + if (value) { + this.sb.push("return "); + this.visitNode(value); + } else { + this.sb.push("return"); + } + } + + visitSwitchCase(node: SwitchCase): void { + var sb = this.sb; + var label = node.label; + if (label) { + sb.push("case "); + this.visitNode(label); + sb.push(":\n"); + } else { + sb.push("default:\n"); + } + var statements = node.statements; + var numStatements = statements.length; + if (numStatements) { + let indentLevel = ++this.indentLevel; + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(statements[0]); + for (let i = 1; i < numStatements; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(statements[i]); + } + --this.indentLevel; + } + } + + visitSwitchStatement(node: SwitchStatement): void { + var sb = this.sb; + sb.push("switch ("); + this.visitNode(node.condition); + sb.push(") {\n"); + var indentLevel = ++this.indentLevel; + var cases = node.cases; + for (let i = 0, k = cases.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitSwitchCase(cases[i]); + sb.push("\n"); + } + --this.indentLevel; + sb.push("}"); + } + + visitThrowStatement(node: ThrowStatement): void { + this.sb.push("throw "); + this.visitNode(node.value); + } + + visitTryStatement(node: TryStatement): void { + var sb = this.sb; + sb.push("try {\n"); + var indentLevel = ++this.indentLevel; + var statements = node.bodyStatements; + for (let i = 0, k = statements.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(statements[i]); + } + var catchVariable = node.catchVariable; + if (catchVariable) { + util.indent(sb, indentLevel - 1); + sb.push("} catch ("); + this.visitIdentifierExpression(catchVariable); + sb.push(") {\n"); + let catchStatements = node.catchStatements; + if (catchStatements) { + for (let i = 0, k = catchStatements.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(catchStatements[i]); + } + } + } + var finallyStatements = node.finallyStatements; + if (finallyStatements) { + util.indent(sb, indentLevel - 1); + sb.push("} finally {\n"); + for (let i = 0, k = finallyStatements.length; i < k; ++i) { + util.indent(sb, indentLevel); + this.visitNodeAndTerminate(finallyStatements[i]); + } + } + util.indent(sb, indentLevel - 1); + sb.push("}"); + } + + visitTypeDeclaration(node: TypeDeclaration): void { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + var sb = this.sb; + this.serializeExternalModifiers(node); + sb.push("type "); + this.visitIdentifierExpression(node.name); + var typeParameters = node.typeParameters; + if (typeParameters) { + let numTypeParameters = typeParameters.length; + if (numTypeParameters) { + sb.push("<"); + for (let i = 0; i < numTypeParameters; ++i) { + this.visitTypeParameter(typeParameters[i]); + } + sb.push(">"); + } + } + sb.push(" = "); + this.visitTypeNode(node.type); + } + + visitVariableDeclaration(node: VariableDeclaration): void { + this.visitIdentifierExpression(node.name); + var type = node.type; + var sb = this.sb; + if (node.flags & CommonFlags.DefinitelyAssigned) { + sb.push("!"); + } + if (type) { + sb.push(": "); + this.visitTypeNode(type); + } + var initializer = node.initializer; + if (initializer) { + sb.push(" = "); + this.visitNode(initializer); + } + } + + visitVariableStatement(node: VariableStatement): void { + var decorators = node.decorators; + if (decorators) { + for (let i = 0, k = decorators.length; i < k; ++i) { + this.serializeDecorator(decorators[i]); + } + } + var sb = this.sb; + var declarations = node.declarations; + var numDeclarations = declarations.length; + var firstDeclaration = declarations[0]; + this.serializeExternalModifiers(firstDeclaration); + sb.push(firstDeclaration.is(CommonFlags.Const) ? "const " : firstDeclaration.is(CommonFlags.Let) ? "let " : "var "); + this.visitVariableDeclaration(node.declarations[0]); + for (let i = 1; i < numDeclarations; ++i) { + sb.push(", "); + this.visitVariableDeclaration(node.declarations[i]); + } + } + + visitWhileStatement(node: WhileStatement): void { + var sb = this.sb; + sb.push("while ("); + this.visitNode(node.condition); + var statement = node.body; + if (statement.kind == NodeKind.Empty) { + sb.push(")"); + } else { + sb.push(") "); + this.visitNode(node.body); + } + } + + // other + + serializeDecorator(node: DecoratorNode): void { + var sb = this.sb; + sb.push("@"); + this.visitNode(node.name); + var args = node.args; + if (args) { + sb.push("("); + let numArgs = args.length; + if (numArgs) { + this.visitNode(args[0]); + for (let i = 1; i < numArgs; ++i) { + sb.push(", "); + this.visitNode(args[i]); + } + } + sb.push(")\n"); + } else { + sb.push("\n"); + } + util.indent(sb, this.indentLevel); + } + + serializeParameter(node: ParameterNode): void { + var sb = this.sb; + var kind = node.parameterKind; + var implicitFieldDeclaration = node.implicitFieldDeclaration; + if (implicitFieldDeclaration) { + this.serializeAccessModifiers(implicitFieldDeclaration); + } + if (kind == ParameterKind.Rest) { + sb.push("..."); + } + this.visitIdentifierExpression(node.name); + var type = node.type; + var initializer = node.initializer; + if (type) { + if (kind == ParameterKind.Optional && !initializer) sb.push("?"); + if (!isTypeOmitted(type)) { + sb.push(": "); + this.visitTypeNode(type); + } + } + if (initializer) { + sb.push(" = "); + this.visitNode(initializer); + } + } + + serializeExternalModifiers(node: DeclarationStatement): void { + var sb = this.sb; + if (node.is(CommonFlags.Export)) { + sb.push("export "); + } else if (node.is(CommonFlags.Import)) { + sb.push("import "); + } else if (node.is(CommonFlags.Declare)) { + sb.push("declare "); + } + } + + serializeAccessModifiers(node: DeclarationStatement): void { + var sb = this.sb; + if (node.is(CommonFlags.Public)) { + sb.push("public "); + } else if (node.is(CommonFlags.Private)) { + sb.push("private "); + } else if (node.is(CommonFlags.Protected)) { + sb.push("protected "); + } + if (node.is(CommonFlags.Static)) { + sb.push("static "); + } else if (node.is(CommonFlags.Abstract)) { + sb.push("abstract "); + } + if (node.is(CommonFlags.Readonly)) { + sb.push("readonly "); + } + } + + finish(): string { + var ret = this.sb.join(""); + this.sb = []; + return ret; + } +} diff --git a/transform/src/index.ts b/transform/src/index.ts index 6066dd7..5f74538 100644 --- a/transform/src/index.ts +++ b/transform/src/index.ts @@ -16,7 +16,7 @@ class JSONTransform extends Visitor { visitImportStatement(node: ImportStatement): void { super.visitImportStatement(node); - const source = this.parser.sources.find(src => src.internalPath == node.internalPath); + const source = this.parser.sources.find((src) => src.internalPath == node.internalPath); if (!source) return; let valid = false; @@ -45,7 +45,7 @@ class JSONTransform extends Visitor { } if (!found) return; - console.log(toString(node)) + console.log(toString(node)); this.schema = new SchemaData(); this.schema.node = node; @@ -187,21 +187,18 @@ class JSONTransform extends Visitor { found = false; - if (!this.imports.find(i => i.declarations.find(d => d.foreignName.text == "JSON"))) { + if (!this.imports.find((i) => i.declarations.find((d) => d.foreignName.text == "JSON"))) { const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); - let relativePath = path.relative( - path.dirname(node.range.source.normalizedPath), - path.resolve(__dirname, "../../assembly/index.ts") - ); + let relativePath = path.relative(path.dirname(node.range.source.normalizedPath), path.resolve(__dirname, "../../assembly/index.ts")); if (!relativePath.startsWith(".") && !relativePath.startsWith("/")) relativePath = "./" + relativePath; // if (!existsSync(relativePath)) { // throw new Error("Could not find a valid json-as library to import from! Please add import { JSON } from \"path-to-json-as\"; in " + node.range.source.normalizedPath + "!"); // } - const txt = "import { JSON } from \"" + relativePath + "\";" + const txt = 'import { JSON } from "' + relativePath + '";'; if (!this.requiredImport) { this.requiredImport = txt; if (process.env["JSON_DEBUG"]) console.log(txt + "\n"); @@ -350,38 +347,16 @@ class JSONTransform extends Visitor { } visitCallExpression(node: CallExpression, ref: Node): void { super.visitCallExpression(node, ref); - if ( - !( - node.expression.kind == NodeKind.PropertyAccess && - (node.expression as PropertyAccessExpression).property.text == "stringifyTo" - ) - && - !( - node.expression.kind == NodeKind.Identifier && - (node.expression as IdentifierExpression).text == "stringifyTo" - ) - ) return; + if (!(node.expression.kind == NodeKind.PropertyAccess && (node.expression as PropertyAccessExpression).property.text == "stringifyTo") && !(node.expression.kind == NodeKind.Identifier && (node.expression as IdentifierExpression).text == "stringifyTo")) return; const source = node.range.source; if (ref.kind == NodeKind.Call) { - const newNode = Node.createBinaryExpression( - Token.Equals, - node.args[1], - node, - node.range - ); + const newNode = Node.createBinaryExpression(Token.Equals, node.args[1], node, node.range); (ref).args[(ref).args.indexOf(node)] = newNode; } else { - const newNode = Node.createExpressionStatement( - Node.createBinaryExpression( - Token.Equals, - node.args[1], - node, - node.range - ) - ); + const newNode = Node.createExpressionStatement(Node.createBinaryExpression(Token.Equals, node.args[1], node, node.range)); const nodeIndex = source.statements.findIndex((n: Node) => { if (n == node) return true; @@ -408,18 +383,17 @@ export default class Transformer extends Transform { const transformer = new JSONTransform(); // Sort the sources so that user scripts are visited last - const sources = parser.sources - .sort((_a, _b) => { - const a = _a.internalPath; - const b = _b.internalPath; - if (a[0] == "~" && b[0] !== "~") { - return -1; - } else if (a[0] !== "~" && b[0] == "~") { - return 1; - } else { - return 0; - } - }); + const sources = parser.sources.sort((_a, _b) => { + const a = _a.internalPath; + const b = _b.internalPath; + if (a[0] == "~" && b[0] !== "~") { + return -1; + } else if (a[0] !== "~" && b[0] == "~") { + return 1; + } else { + return 0; + } + }); transformer.parser = parser; // Loop over every source @@ -430,13 +404,7 @@ export default class Transformer extends Transform { transformer.visit(source); if (transformer.requiredImport) { - const tokenizer = new Tokenizer( - new Source( - SourceKind.User, - source.normalizedPath, - transformer.requiredImport, - ), - ); + const tokenizer = new Tokenizer(new Source(SourceKind.User, source.normalizedPath, transformer.requiredImport)); parser.currentSource = tokenizer.source; source.statements.unshift(parser.parseTopLevelStatement(tokenizer)!); parser.currentSource = source; diff --git a/transform/src/util.ts b/transform/src/util.ts index a6ed0cc..4a58420 100644 --- a/transform/src/util.ts +++ b/transform/src/util.ts @@ -1,75 +1,56 @@ // Taken from https://github.com/as-pect/visitor-as/blob/master/src/simpleParser.ts -import { - Parser, - Tokenizer, - Source, - SourceKind, - Expression, - Statement, - NamespaceDeclaration, - ClassDeclaration, - DeclarationStatement, - Range, - Node, -} from "assemblyscript/dist/assemblyscript.js"; +import { Parser, Tokenizer, Source, SourceKind, Expression, Statement, NamespaceDeclaration, ClassDeclaration, DeclarationStatement, Range, Node } from "assemblyscript/dist/assemblyscript.js"; import { ASTBuilder } from "./builder.js"; export class SimpleParser { - private static get parser(): Parser { - return new Parser(); + private static get parser(): Parser { + return new Parser(); + } + + private static getTokenizer(s: string, file: string = "index.ts"): Tokenizer { + return new Tokenizer(new Source(SourceKind.User, file, s)); + } + + static parseExpression(s: string): Expression { + const res = this.parser.parseExpression(this.getTokenizer(s)); + if (res == null) { + throw new Error("Failed to parse the expression: '" + s + "'"); } + return res; + } - private static getTokenizer(s: string, file: string = "index.ts"): Tokenizer { - return new Tokenizer(new Source(SourceKind.User, file, s)); + static parseStatement(s: string, topLevel = false): Statement { + const res = this.parser.parseStatement(this.getTokenizer(s), topLevel); + if (res == null) { + throw new Error("Failed to parse the statement: '" + s + "'"); } + return res; + } - static parseExpression(s: string): Expression { - const res = this.parser.parseExpression(this.getTokenizer(s)); - if (res == null) { - throw new Error("Failed to parse the expression: '" + s + "'"); - } - return res; + static parseTopLevelStatement(s: string, namespace?: NamespaceDeclaration | null): Statement { + const res = this.parser.parseTopLevelStatement(this.getTokenizer(s), namespace); + if (res == null) { + throw new Error("Failed to parse the top level statement: '" + s + "'"); } + return res; + } - static parseStatement(s: string, topLevel = false): Statement { - const res = this.parser.parseStatement(this.getTokenizer(s), topLevel); - if (res == null) { - throw new Error("Failed to parse the statement: '" + s + "'"); - } - return res; - } - - static parseTopLevelStatement( - s: string, - namespace?: NamespaceDeclaration | null - ): Statement { - const res = this.parser.parseTopLevelStatement(this.getTokenizer(s), namespace); - if (res == null) { - throw new Error("Failed to parse the top level statement: '" + s + "'"); - } - return res; - } - - static parseClassMember(s: string, _class: ClassDeclaration): DeclarationStatement { - let res = this.parser.parseClassMember( - this.getTokenizer(s, _class.range.source.normalizedPath), - _class - ); - if (res == null) { - throw new Error("Failed to parse the class member: '" + s + "'"); - } - return res; + static parseClassMember(s: string, _class: ClassDeclaration): DeclarationStatement { + let res = this.parser.parseClassMember(this.getTokenizer(s, _class.range.source.normalizedPath), _class); + if (res == null) { + throw new Error("Failed to parse the class member: '" + s + "'"); } + return res; + } } -let isStdlibRegex = - /\~lib\/(?:array|arraybuffer|atomics|builtins|crypto|console|compat|dataview|date|diagnostics|error|function|iterator|map|math|number|object|process|reference|regexp|set|staticarray|string|symbol|table|typedarray|vector|rt\/?|bindings\/|shared\/typeinfo)|util\/|uri|polyfills|memory/; +let isStdlibRegex = /\~lib\/(?:array|arraybuffer|atomics|builtins|crypto|console|compat|dataview|date|diagnostics|error|function|iterator|map|math|number|object|process|reference|regexp|set|staticarray|string|symbol|table|typedarray|vector|rt\/?|bindings\/|shared\/typeinfo)|util\/|uri|polyfills|memory/; export function isStdlib(s: Source | { range: Range }): boolean { - let source = s instanceof Source ? s : s.range.source; - return isStdlibRegex.test(source.internalPath); + let source = s instanceof Source ? s : s.range.source; + return isStdlibRegex.test(source.internalPath); } export function toString(node: Node): string { - return ASTBuilder.build(node); -} \ No newline at end of file + return ASTBuilder.build(node); +} diff --git a/transform/src/visitor.ts b/transform/src/visitor.ts index fa8fec0..29b65a3 100644 --- a/transform/src/visitor.ts +++ b/transform/src/visitor.ts @@ -2,545 +2,530 @@ import { ArrayLiteralExpression, AssertionExpression, BinaryExpression, CallExpr import { toString } from "./util.js"; export class Visitor { - public currentSource: Source | null = null; - visit(node: Node | Node[], ref: Node | null = null): void { - if (node == null) return; - if (node instanceof Array) { - for (const n of node) { - this._visit(n, ref); - } - } else { - // @ts-ignore - this._visit(node, ref); - } - } - _visit(node: Node, ref: Node | null): void { - switch (node.kind) { - case NodeKind.Source: - this.visitSource(node as Source, ref); - break; - case NodeKind.NamedType: - this.visitNamedTypeNode(node as NamedTypeNode, ref); - break; - case NodeKind.FunctionType: - this.visitFunctionTypeNode(node as FunctionTypeNode, ref); - break; - case NodeKind.TypeName: - this.visitTypeName(node as TypeName, ref); - break; - case NodeKind.TypeParameter: - this.visitTypeParameter(node as TypeParameterNode, ref); - break; - case NodeKind.Identifier: - this.visitIdentifierExpression(node as IdentifierExpression, ref); - break; - case NodeKind.Assertion: - this.visitAssertionExpression(node as AssertionExpression, ref); - break; - case NodeKind.Binary: - this.visitBinaryExpression(node as BinaryExpression, ref); - break; - case NodeKind.Call: - this.visitCallExpression(node as CallExpression, ref); - break; - case NodeKind.Class: - this.visitClassExpression(node as ClassExpression, ref); - break; - case NodeKind.Comma: - this.visitCommaExpression(node as CommaExpression, ref); - break; - case NodeKind.ElementAccess: - this.visitElementAccessExpression(node as ElementAccessExpression, ref); - break; - case NodeKind.Function: - this.visitFunctionExpression(node as FunctionExpression, ref); - break; - case NodeKind.InstanceOf: - this.visitInstanceOfExpression(node as InstanceOfExpression, ref); - break; - case NodeKind.Literal: - this.visitLiteralExpression(node as LiteralExpression, ref); - break; - case NodeKind.New: - this.visitNewExpression(node as NewExpression, ref); - break; - case NodeKind.Parenthesized: - this.visitParenthesizedExpression(node as ParenthesizedExpression, ref); - break; - case NodeKind.PropertyAccess: - this.visitPropertyAccessExpression(node as PropertyAccessExpression, ref); - break; - case NodeKind.Ternary: - this.visitTernaryExpression(node as TernaryExpression, ref); - break; - case NodeKind.UnaryPostfix: - this.visitUnaryPostfixExpression(node as UnaryPostfixExpression, ref); - break; - case NodeKind.UnaryPrefix: - this.visitUnaryPrefixExpression(node as UnaryPrefixExpression, ref); - break; - case NodeKind.Block: - this.visitBlockStatement(node as BlockStatement, ref); - break; - case NodeKind.Break: - this.visitBreakStatement(node as BreakStatement, ref); - break; - case NodeKind.Continue: - this.visitContinueStatement(node as ContinueStatement, ref); - break; - case NodeKind.Do: - this.visitDoStatement(node as DoStatement, ref); - break; - case NodeKind.Empty: - this.visitEmptyStatement(node as EmptyStatement, ref); - break; - case NodeKind.Export: - this.visitExportStatement(node as ExportStatement, ref); - break; - case NodeKind.ExportDefault: - this.visitExportDefaultStatement(node as ExportDefaultStatement, ref); - break; - case NodeKind.ExportImport: - this.visitExportImportStatement(node as ExportImportStatement, ref); - break; - case NodeKind.Expression: - this.visitExpressionStatement(node as ExpressionStatement, ref); - break; - case NodeKind.For: - this.visitForStatement(node as ForStatement, ref); - break; - case NodeKind.If: - this.visitIfStatement(node as IfStatement, ref); - break; - case NodeKind.Import: - this.visitImportStatement(node as ImportStatement, ref); - break; - case NodeKind.Return: - this.visitReturnStatement(node as ReturnStatement, ref); - break; - case NodeKind.Switch: - this.visitSwitchStatement(node as SwitchStatement, ref); - break; - case NodeKind.Throw: - this.visitThrowStatement(node as ThrowStatement, ref); - break; - case NodeKind.Try: - this.visitTryStatement(node as TryStatement, ref); - break; - case NodeKind.Variable: - this.visitVariableStatement(node as VariableStatement, ref); - break; - case NodeKind.While: - this.visitWhileStatement(node as WhileStatement, ref); - break; - case NodeKind.ClassDeclaration: - this.visitClassDeclaration(node as ClassDeclaration, false, ref); - break; - case NodeKind.EnumDeclaration: - this.visitEnumDeclaration(node as EnumDeclaration, false, ref); - break; - case NodeKind.EnumValueDeclaration: - this.visitEnumValueDeclaration(node as EnumValueDeclaration, ref); - break; - case NodeKind.FieldDeclaration: - this.visitFieldDeclaration(node as FieldDeclaration, ref); - break; - case NodeKind.FunctionDeclaration: - this.visitFunctionDeclaration(node as FunctionDeclaration, false, ref); - break; - case NodeKind.ImportDeclaration: - this.visitImportDeclaration(node as ImportDeclaration, ref); - break; - case NodeKind.InterfaceDeclaration: - this.visitInterfaceDeclaration(node as InterfaceDeclaration, false, ref); - break; - case NodeKind.MethodDeclaration: - this.visitMethodDeclaration(node as MethodDeclaration, ref); - break; - case NodeKind.NamespaceDeclaration: - this.visitNamespaceDeclaration(node as NamespaceDeclaration, false, ref); - break; - case NodeKind.TypeDeclaration: - this.visitTypeDeclaration(node as TypeDeclaration, ref); - break; - case NodeKind.VariableDeclaration: - this.visitVariableDeclaration(node as VariableDeclaration, ref); - break; - case NodeKind.Decorator: - this.visitDecoratorNode(node as DecoratorNode, ref); - break; - case NodeKind.ExportMember: - this.visitExportMember(node as ExportMember, ref); - break; - case NodeKind.SwitchCase: - this.visitSwitchCase(node as SwitchCase, ref); - break; - case NodeKind.IndexSignature: - this.visitIndexSignature(node as IndexSignatureNode, ref); - break; - case NodeKind.Null: - this.visitNullExpression(node as NullExpression, ref); - break; - case NodeKind.True: { - this.visitTrueExpression(node as TrueExpression, ref); - break; - } - case NodeKind.False: { - this.visitFalseExpression(node as FalseExpression, ref); - break; - } - case NodeKind.Compiled: { - this.visitCompiledExpression(node as CompiledExpression, ref); - break; - } - case NodeKind.Constructor: { - this.visitConstructorExpression(node as ConstructorExpression, ref); - break; - } - case NodeKind.Comment: { - this.visitComment(node as CommentNode, ref); - break; - } - case NodeKind.ForOf: { - this.visitForOfStatement(node as ForOfStatement, ref); - break; - } - case NodeKind.Module: { - this.visitModuleDeclaration(node as ModuleDeclaration, ref); - break; - } - case NodeKind.Omitted: { - this.visitOmittedExpression(node as OmittedExpression, ref); - break; - } - case NodeKind.Parameter: { - this.visitParameter(node as ParameterNode, ref); - break; - } - case NodeKind.Super: { - this.visitSuperExpression(node as SuperExpression, ref); - break; - } - case NodeKind.This: { - this.visitThisExpression(node as ThisExpression, ref); - break; - } - case NodeKind.Void: { - this.visitVoidStatement(node as VoidStatement, ref); - break; - } - default: - throw new Error("Could not visit invalid type!"); - } - } - visitSource(node: Source, ref: Node | null = null): void { - this.currentSource = node; - this.visit(node.statements, node); - this.currentSource = null; - } - visitTypeNode(node: TypeNode, ref: Node | null = null): void { } - visitTypeName(node: TypeName, ref: Node | null = null): void { - this.visit(node.identifier, node); - this.visit(node.next, node); - } - visitNamedTypeNode(node: NamedTypeNode, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.typeArguments, node); - } - visitFunctionTypeNode(node: FunctionTypeNode, ref: Node | null = null): void { - this.visit(node.parameters, node); - this.visit(node.returnType, node); - this.visit(node.explicitThisType, node); - } - visitTypeParameter(node: TypeParameterNode, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.extendsType, node); - this.visit(node.defaultType, node); - } - visitIdentifierExpression(node: IdentifierExpression, ref: Node | null = null): void { } - visitArrayLiteralExpression(node: ArrayLiteralExpression, ref: Node | null = null): void { - this.visit(node.elementExpressions, node); - } - visitObjectLiteralExpression(node: ObjectLiteralExpression, ref: Node | null = null): void { - this.visit(node.names, node); - this.visit(node.values, node); - } - visitAssertionExpression(node: AssertionExpression, ref: Node | null = null): void { - this.visit(node.toType, node); - this.visit(node.expression, node); - } - visitBinaryExpression(node: BinaryExpression, ref: Node | null = null): void { - this.visit(node.left, node); - this.visit(node.right, node); - } - visitCallExpression(node: CallExpression, ref: Node | null = null): void { - this.visit(node.expression, node); - this.visit(node.typeArguments, node); - this.visit(node.args, node); - } - visitClassExpression(node: ClassExpression, ref: Node | null = null): void { - this.visit(node.declaration, node); - } - visitCommaExpression(node: CommaExpression, ref: Node | null = null): void { - this.visit(node.expressions, node); - } - visitElementAccessExpression(node: ElementAccessExpression, ref: Node | null = null): void { - this.visit(node.elementExpression, node); - this.visit(node.expression, node); - } - visitFunctionExpression(node: FunctionExpression, ref: Node | null = null): void { - this.visit(node.declaration, node); - } - visitLiteralExpression(node: LiteralExpression, ref: Node | null = null): void { - switch (node.literalKind) { - case LiteralKind.Float: - this.visitFloatLiteralExpression(node as FloatLiteralExpression); - break; - case LiteralKind.Integer: - this.visitIntegerLiteralExpression(node as IntegerLiteralExpression); - break; - case LiteralKind.String: - this.visitStringLiteralExpression(node as StringLiteralExpression); - break; - case LiteralKind.Template: - this.visitTemplateLiteralExpression(node as TemplateLiteralExpression); - break; - case LiteralKind.RegExp: - this.visitRegexpLiteralExpression(node as RegexpLiteralExpression); - break; - case LiteralKind.Array: - this.visitArrayLiteralExpression(node as ArrayLiteralExpression); - break; - case LiteralKind.Object: - this.visitObjectLiteralExpression(node as ObjectLiteralExpression); - break; - default: - throw new Error( - "Invalid LiteralKind at visitLiteralExpression(): " + node.literalKind, - ); - } - } - visitFloatLiteralExpression(node: FloatLiteralExpression, ref: Node | null = null): void { } - visitInstanceOfExpression(node: InstanceOfExpression, ref: Node | null = null): void { - this.visit(node.expression, node); - this.visit(node.isType, node); - } - visitIntegerLiteralExpression(node: IntegerLiteralExpression, ref: Node | null = null): void { } - visitStringLiteralExpression(node: StringLiteralExpression, ref: Node | null = null): void { } - visitTemplateLiteralExpression(node: TemplateLiteralExpression, ref: Node | null = null): void { } - visitRegexpLiteralExpression(node: RegexpLiteralExpression, ref: Node | null = null): void { } - visitNewExpression(node: NewExpression, ref: Node | null = null): void { - this.visit(node.typeName, node); - this.visit(node.typeArguments, node); - this.visit(node.args, node); - } - visitParenthesizedExpression(node: ParenthesizedExpression, ref: Node | null = null): void { - this.visit(node.expression, node); - } - visitPropertyAccessExpression(node: PropertyAccessExpression, ref: Node | null = null): void { - this.visit(node.property, node); - this.visit(node.expression, node); - } - visitTernaryExpression(node: TernaryExpression, ref: Node | null = null): void { - this.visit(node.condition, node); - this.visit(node.ifThen, node); - this.visit(node.ifElse, node); - } - visitUnaryExpression(node: UnaryExpression, ref: Node | null = null): void { - this.visit(node.operand, node); - } - visitUnaryPostfixExpression(node: UnaryPostfixExpression, ref: Node | null = null): void { - this.visit(node.operand, node); - } - visitUnaryPrefixExpression(node: UnaryPrefixExpression, ref: Node | null = null): void { - this.visit(node.operand, node); - } - visitSuperExpression(node: SuperExpression, ref: Node | null = null): void { } - visitFalseExpression(node: FalseExpression, ref: Node | null = null): void { } - visitTrueExpression(node: TrueExpression, ref: Node | null = null): void { } - visitThisExpression(node: ThisExpression, ref: Node | null = null): void { } - visitNullExpression(node: NullExpression, ref: Node | null = null): void { } - visitConstructorExpression(node: ConstructorExpression, ref: Node | null = null): void { } - visitNodeAndTerminate(statement: Statement, ref: Node | null = null): void { } - visitBlockStatement(node: BlockStatement, ref: Node | null = null): void { - this.visit(node.statements, node); - } - visitBreakStatement(node: BreakStatement, ref: Node | null = null): void { - this.visit(node.label, node); - } - visitContinueStatement(node: ContinueStatement, ref: Node | null = null): void { - this.visit(node.label, node); - } - visitClassDeclaration(node: ClassDeclaration, isDefault: boolean = false, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.decorators, node); - if ( - node.isGeneric ? node.typeParameters != null : node.typeParameters == null - ) { - this.visit(node.typeParameters, node); - this.visit(node.extendsType, node); - this.visit(node.implementsTypes, node); - this.visit(node.members, node); - } else { - throw new Error( - "Expected to type parameters to match class declaration, but found type mismatch instead!", - ); - } - } - visitDoStatement(node: DoStatement, ref: Node | null = null): void { - this.visit(node.condition, node); - this.visit(node.body, node); - } - visitEmptyStatement(node: EmptyStatement, ref: Node | null = null): void { } - visitEnumDeclaration(node: EnumDeclaration, isDefault: boolean = false, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.decorators, node); - this.visit(node.values, node); - } - visitEnumValueDeclaration(node: EnumValueDeclaration, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.initializer, node); - } - visitExportImportStatement(node: ExportImportStatement, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.externalName, node); - } - visitExportMember(node: ExportMember, ref: Node | null = null): void { - this.visit(node.localName, node); - this.visit(node.exportedName, node); - } - visitExportStatement(node: ExportStatement, ref: Node | null = null): void { - this.visit(node.path, node); - this.visit(node.members, node); - } - visitExportDefaultStatement(node: ExportDefaultStatement, ref: Node | null = null): void { - this.visit(node.declaration, node); - } - visitExpressionStatement(node: ExpressionStatement, ref: Node | null = null): void { - this.visit(node.expression, ref); - } - visitFieldDeclaration(node: FieldDeclaration, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.type, node); - this.visit(node.initializer, node); - this.visit(node.decorators, node); - } - visitForStatement(node: ForStatement, ref: Node | null = null): void { - this.visit(node.initializer, node); - this.visit(node.condition, node); - this.visit(node.incrementor, node); - this.visit(node.body, node); - } - visitFunctionDeclaration( - node: FunctionDeclaration, - isDefault: boolean = false, - ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.decorators, node); - this.visit(node.typeParameters, node); - this.visit(node.signature, node); - this.visit(node.body, node); - } - visitIfStatement(node: IfStatement, ref: Node | null = null): void { - this.visit(node.condition, node); - this.visit(node.ifTrue, node); - this.visit(node.ifFalse, node); - } - visitImportDeclaration(node: ImportDeclaration, ref: Node | null = null): void { - this.visit(node.foreignName, node); - this.visit(node.name, node); - this.visit(node.decorators, node); - } - visitImportStatement(node: ImportStatement, ref: Node | null = null): void { - this.visit(node.namespaceName, node); - this.visit(node.declarations, node); - } - visitIndexSignature(node: IndexSignatureNode, ref: Node | null = null): void { - this.visit(node.keyType, node); - this.visit(node.valueType, node); - } - visitInterfaceDeclaration( - node: InterfaceDeclaration, - isDefault: boolean = false, - ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.typeParameters, node); - this.visit(node.implementsTypes, node); - this.visit(node.extendsType, node); - this.visit(node.members, node); - } - visitMethodDeclaration(node: MethodDeclaration, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.typeParameters, node); - this.visit(node.signature, node); - this.visit(node.decorators, node); - this.visit(node.body, node); - } - visitNamespaceDeclaration( - node: NamespaceDeclaration, - isDefault: boolean = false, - ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.decorators, node); - this.visit(node.members, node); - } - visitReturnStatement(node: ReturnStatement, ref: Node | null = null): void { - this.visit(node.value, node); - } - visitSwitchCase(node: SwitchCase, ref: Node | null = null): void { - this.visit(node.label, node); - this.visit(node.statements, node); - } - visitSwitchStatement(node: SwitchStatement, ref: Node | null = null): void { - this.visit(node.condition, node); - this.visit(node.cases, node); - } - visitThrowStatement(node: ThrowStatement, ref: Node | null = null): void { - this.visit(node.value, node); - } - visitTryStatement(node: TryStatement, ref: Node | null = null): void { - this.visit(node.bodyStatements, node); - this.visit(node.catchVariable, node); - this.visit(node.catchStatements, node); - this.visit(node.finallyStatements, node); - } - visitTypeDeclaration(node: TypeDeclaration, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.decorators, node); - this.visit(node.type, node); - this.visit(node.typeParameters, node); - } - visitVariableDeclaration(node: VariableDeclaration, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.type, node); - this.visit(node.initializer, node); - } - visitVariableStatement(node: VariableStatement, ref: Node | null = null): void { - this.visit(node.decorators, node); - this.visit(node.declarations, node); - } - visitWhileStatement(node: WhileStatement, ref: Node | null = null): void { - this.visit(node.condition, node); - this.visit(node.body, node); - } - visitVoidStatement(node: VoidStatement, ref: Node | null = null): void { } - visitComment(node: CommentNode, ref: Node | null = null): void { } - visitDecoratorNode(node: DecoratorNode, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.args, node); - } - visitParameter(node: ParameterNode, ref: Node | null = null): void { - this.visit(node.name, node); - this.visit(node.implicitFieldDeclaration, node); - this.visit(node.initializer, node); - this.visit(node.type, node); - } - visitCompiledExpression(node: CompiledExpression, ref: Node | null = null): void { } - visitForOfStatement(node: ForOfStatement, ref: Node | null = null): void { - this.visit(node.body, node); - this.visit(node.variable, node); - this.visit(node.iterable, node); - } - visitModuleDeclaration(node: ModuleDeclaration, ref: Node | null = null): void { } - visitOmittedExpression(node: OmittedExpression, ref: Node | null = null): void { } -} \ No newline at end of file + public currentSource: Source | null = null; + visit(node: Node | Node[], ref: Node | null = null): void { + if (node == null) return; + if (node instanceof Array) { + for (const n of node) { + this._visit(n, ref); + } + } else { + // @ts-ignore + this._visit(node, ref); + } + } + _visit(node: Node, ref: Node | null): void { + switch (node.kind) { + case NodeKind.Source: + this.visitSource(node as Source, ref); + break; + case NodeKind.NamedType: + this.visitNamedTypeNode(node as NamedTypeNode, ref); + break; + case NodeKind.FunctionType: + this.visitFunctionTypeNode(node as FunctionTypeNode, ref); + break; + case NodeKind.TypeName: + this.visitTypeName(node as TypeName, ref); + break; + case NodeKind.TypeParameter: + this.visitTypeParameter(node as TypeParameterNode, ref); + break; + case NodeKind.Identifier: + this.visitIdentifierExpression(node as IdentifierExpression, ref); + break; + case NodeKind.Assertion: + this.visitAssertionExpression(node as AssertionExpression, ref); + break; + case NodeKind.Binary: + this.visitBinaryExpression(node as BinaryExpression, ref); + break; + case NodeKind.Call: + this.visitCallExpression(node as CallExpression, ref); + break; + case NodeKind.Class: + this.visitClassExpression(node as ClassExpression, ref); + break; + case NodeKind.Comma: + this.visitCommaExpression(node as CommaExpression, ref); + break; + case NodeKind.ElementAccess: + this.visitElementAccessExpression(node as ElementAccessExpression, ref); + break; + case NodeKind.Function: + this.visitFunctionExpression(node as FunctionExpression, ref); + break; + case NodeKind.InstanceOf: + this.visitInstanceOfExpression(node as InstanceOfExpression, ref); + break; + case NodeKind.Literal: + this.visitLiteralExpression(node as LiteralExpression, ref); + break; + case NodeKind.New: + this.visitNewExpression(node as NewExpression, ref); + break; + case NodeKind.Parenthesized: + this.visitParenthesizedExpression(node as ParenthesizedExpression, ref); + break; + case NodeKind.PropertyAccess: + this.visitPropertyAccessExpression(node as PropertyAccessExpression, ref); + break; + case NodeKind.Ternary: + this.visitTernaryExpression(node as TernaryExpression, ref); + break; + case NodeKind.UnaryPostfix: + this.visitUnaryPostfixExpression(node as UnaryPostfixExpression, ref); + break; + case NodeKind.UnaryPrefix: + this.visitUnaryPrefixExpression(node as UnaryPrefixExpression, ref); + break; + case NodeKind.Block: + this.visitBlockStatement(node as BlockStatement, ref); + break; + case NodeKind.Break: + this.visitBreakStatement(node as BreakStatement, ref); + break; + case NodeKind.Continue: + this.visitContinueStatement(node as ContinueStatement, ref); + break; + case NodeKind.Do: + this.visitDoStatement(node as DoStatement, ref); + break; + case NodeKind.Empty: + this.visitEmptyStatement(node as EmptyStatement, ref); + break; + case NodeKind.Export: + this.visitExportStatement(node as ExportStatement, ref); + break; + case NodeKind.ExportDefault: + this.visitExportDefaultStatement(node as ExportDefaultStatement, ref); + break; + case NodeKind.ExportImport: + this.visitExportImportStatement(node as ExportImportStatement, ref); + break; + case NodeKind.Expression: + this.visitExpressionStatement(node as ExpressionStatement, ref); + break; + case NodeKind.For: + this.visitForStatement(node as ForStatement, ref); + break; + case NodeKind.If: + this.visitIfStatement(node as IfStatement, ref); + break; + case NodeKind.Import: + this.visitImportStatement(node as ImportStatement, ref); + break; + case NodeKind.Return: + this.visitReturnStatement(node as ReturnStatement, ref); + break; + case NodeKind.Switch: + this.visitSwitchStatement(node as SwitchStatement, ref); + break; + case NodeKind.Throw: + this.visitThrowStatement(node as ThrowStatement, ref); + break; + case NodeKind.Try: + this.visitTryStatement(node as TryStatement, ref); + break; + case NodeKind.Variable: + this.visitVariableStatement(node as VariableStatement, ref); + break; + case NodeKind.While: + this.visitWhileStatement(node as WhileStatement, ref); + break; + case NodeKind.ClassDeclaration: + this.visitClassDeclaration(node as ClassDeclaration, false, ref); + break; + case NodeKind.EnumDeclaration: + this.visitEnumDeclaration(node as EnumDeclaration, false, ref); + break; + case NodeKind.EnumValueDeclaration: + this.visitEnumValueDeclaration(node as EnumValueDeclaration, ref); + break; + case NodeKind.FieldDeclaration: + this.visitFieldDeclaration(node as FieldDeclaration, ref); + break; + case NodeKind.FunctionDeclaration: + this.visitFunctionDeclaration(node as FunctionDeclaration, false, ref); + break; + case NodeKind.ImportDeclaration: + this.visitImportDeclaration(node as ImportDeclaration, ref); + break; + case NodeKind.InterfaceDeclaration: + this.visitInterfaceDeclaration(node as InterfaceDeclaration, false, ref); + break; + case NodeKind.MethodDeclaration: + this.visitMethodDeclaration(node as MethodDeclaration, ref); + break; + case NodeKind.NamespaceDeclaration: + this.visitNamespaceDeclaration(node as NamespaceDeclaration, false, ref); + break; + case NodeKind.TypeDeclaration: + this.visitTypeDeclaration(node as TypeDeclaration, ref); + break; + case NodeKind.VariableDeclaration: + this.visitVariableDeclaration(node as VariableDeclaration, ref); + break; + case NodeKind.Decorator: + this.visitDecoratorNode(node as DecoratorNode, ref); + break; + case NodeKind.ExportMember: + this.visitExportMember(node as ExportMember, ref); + break; + case NodeKind.SwitchCase: + this.visitSwitchCase(node as SwitchCase, ref); + break; + case NodeKind.IndexSignature: + this.visitIndexSignature(node as IndexSignatureNode, ref); + break; + case NodeKind.Null: + this.visitNullExpression(node as NullExpression, ref); + break; + case NodeKind.True: { + this.visitTrueExpression(node as TrueExpression, ref); + break; + } + case NodeKind.False: { + this.visitFalseExpression(node as FalseExpression, ref); + break; + } + case NodeKind.Compiled: { + this.visitCompiledExpression(node as CompiledExpression, ref); + break; + } + case NodeKind.Constructor: { + this.visitConstructorExpression(node as ConstructorExpression, ref); + break; + } + case NodeKind.Comment: { + this.visitComment(node as CommentNode, ref); + break; + } + case NodeKind.ForOf: { + this.visitForOfStatement(node as ForOfStatement, ref); + break; + } + case NodeKind.Module: { + this.visitModuleDeclaration(node as ModuleDeclaration, ref); + break; + } + case NodeKind.Omitted: { + this.visitOmittedExpression(node as OmittedExpression, ref); + break; + } + case NodeKind.Parameter: { + this.visitParameter(node as ParameterNode, ref); + break; + } + case NodeKind.Super: { + this.visitSuperExpression(node as SuperExpression, ref); + break; + } + case NodeKind.This: { + this.visitThisExpression(node as ThisExpression, ref); + break; + } + case NodeKind.Void: { + this.visitVoidStatement(node as VoidStatement, ref); + break; + } + default: + throw new Error("Could not visit invalid type!"); + } + } + visitSource(node: Source, ref: Node | null = null): void { + this.currentSource = node; + this.visit(node.statements, node); + this.currentSource = null; + } + visitTypeNode(node: TypeNode, ref: Node | null = null): void {} + visitTypeName(node: TypeName, ref: Node | null = null): void { + this.visit(node.identifier, node); + this.visit(node.next, node); + } + visitNamedTypeNode(node: NamedTypeNode, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.typeArguments, node); + } + visitFunctionTypeNode(node: FunctionTypeNode, ref: Node | null = null): void { + this.visit(node.parameters, node); + this.visit(node.returnType, node); + this.visit(node.explicitThisType, node); + } + visitTypeParameter(node: TypeParameterNode, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.extendsType, node); + this.visit(node.defaultType, node); + } + visitIdentifierExpression(node: IdentifierExpression, ref: Node | null = null): void {} + visitArrayLiteralExpression(node: ArrayLiteralExpression, ref: Node | null = null): void { + this.visit(node.elementExpressions, node); + } + visitObjectLiteralExpression(node: ObjectLiteralExpression, ref: Node | null = null): void { + this.visit(node.names, node); + this.visit(node.values, node); + } + visitAssertionExpression(node: AssertionExpression, ref: Node | null = null): void { + this.visit(node.toType, node); + this.visit(node.expression, node); + } + visitBinaryExpression(node: BinaryExpression, ref: Node | null = null): void { + this.visit(node.left, node); + this.visit(node.right, node); + } + visitCallExpression(node: CallExpression, ref: Node | null = null): void { + this.visit(node.expression, node); + this.visit(node.typeArguments, node); + this.visit(node.args, node); + } + visitClassExpression(node: ClassExpression, ref: Node | null = null): void { + this.visit(node.declaration, node); + } + visitCommaExpression(node: CommaExpression, ref: Node | null = null): void { + this.visit(node.expressions, node); + } + visitElementAccessExpression(node: ElementAccessExpression, ref: Node | null = null): void { + this.visit(node.elementExpression, node); + this.visit(node.expression, node); + } + visitFunctionExpression(node: FunctionExpression, ref: Node | null = null): void { + this.visit(node.declaration, node); + } + visitLiteralExpression(node: LiteralExpression, ref: Node | null = null): void { + switch (node.literalKind) { + case LiteralKind.Float: + this.visitFloatLiteralExpression(node as FloatLiteralExpression); + break; + case LiteralKind.Integer: + this.visitIntegerLiteralExpression(node as IntegerLiteralExpression); + break; + case LiteralKind.String: + this.visitStringLiteralExpression(node as StringLiteralExpression); + break; + case LiteralKind.Template: + this.visitTemplateLiteralExpression(node as TemplateLiteralExpression); + break; + case LiteralKind.RegExp: + this.visitRegexpLiteralExpression(node as RegexpLiteralExpression); + break; + case LiteralKind.Array: + this.visitArrayLiteralExpression(node as ArrayLiteralExpression); + break; + case LiteralKind.Object: + this.visitObjectLiteralExpression(node as ObjectLiteralExpression); + break; + default: + throw new Error("Invalid LiteralKind at visitLiteralExpression(): " + node.literalKind); + } + } + visitFloatLiteralExpression(node: FloatLiteralExpression, ref: Node | null = null): void {} + visitInstanceOfExpression(node: InstanceOfExpression, ref: Node | null = null): void { + this.visit(node.expression, node); + this.visit(node.isType, node); + } + visitIntegerLiteralExpression(node: IntegerLiteralExpression, ref: Node | null = null): void {} + visitStringLiteralExpression(node: StringLiteralExpression, ref: Node | null = null): void {} + visitTemplateLiteralExpression(node: TemplateLiteralExpression, ref: Node | null = null): void {} + visitRegexpLiteralExpression(node: RegexpLiteralExpression, ref: Node | null = null): void {} + visitNewExpression(node: NewExpression, ref: Node | null = null): void { + this.visit(node.typeName, node); + this.visit(node.typeArguments, node); + this.visit(node.args, node); + } + visitParenthesizedExpression(node: ParenthesizedExpression, ref: Node | null = null): void { + this.visit(node.expression, node); + } + visitPropertyAccessExpression(node: PropertyAccessExpression, ref: Node | null = null): void { + this.visit(node.property, node); + this.visit(node.expression, node); + } + visitTernaryExpression(node: TernaryExpression, ref: Node | null = null): void { + this.visit(node.condition, node); + this.visit(node.ifThen, node); + this.visit(node.ifElse, node); + } + visitUnaryExpression(node: UnaryExpression, ref: Node | null = null): void { + this.visit(node.operand, node); + } + visitUnaryPostfixExpression(node: UnaryPostfixExpression, ref: Node | null = null): void { + this.visit(node.operand, node); + } + visitUnaryPrefixExpression(node: UnaryPrefixExpression, ref: Node | null = null): void { + this.visit(node.operand, node); + } + visitSuperExpression(node: SuperExpression, ref: Node | null = null): void {} + visitFalseExpression(node: FalseExpression, ref: Node | null = null): void {} + visitTrueExpression(node: TrueExpression, ref: Node | null = null): void {} + visitThisExpression(node: ThisExpression, ref: Node | null = null): void {} + visitNullExpression(node: NullExpression, ref: Node | null = null): void {} + visitConstructorExpression(node: ConstructorExpression, ref: Node | null = null): void {} + visitNodeAndTerminate(statement: Statement, ref: Node | null = null): void {} + visitBlockStatement(node: BlockStatement, ref: Node | null = null): void { + this.visit(node.statements, node); + } + visitBreakStatement(node: BreakStatement, ref: Node | null = null): void { + this.visit(node.label, node); + } + visitContinueStatement(node: ContinueStatement, ref: Node | null = null): void { + this.visit(node.label, node); + } + visitClassDeclaration(node: ClassDeclaration, isDefault: boolean = false, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.decorators, node); + if (node.isGeneric ? node.typeParameters != null : node.typeParameters == null) { + this.visit(node.typeParameters, node); + this.visit(node.extendsType, node); + this.visit(node.implementsTypes, node); + this.visit(node.members, node); + } else { + throw new Error("Expected to type parameters to match class declaration, but found type mismatch instead!"); + } + } + visitDoStatement(node: DoStatement, ref: Node | null = null): void { + this.visit(node.condition, node); + this.visit(node.body, node); + } + visitEmptyStatement(node: EmptyStatement, ref: Node | null = null): void {} + visitEnumDeclaration(node: EnumDeclaration, isDefault: boolean = false, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.decorators, node); + this.visit(node.values, node); + } + visitEnumValueDeclaration(node: EnumValueDeclaration, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.initializer, node); + } + visitExportImportStatement(node: ExportImportStatement, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.externalName, node); + } + visitExportMember(node: ExportMember, ref: Node | null = null): void { + this.visit(node.localName, node); + this.visit(node.exportedName, node); + } + visitExportStatement(node: ExportStatement, ref: Node | null = null): void { + this.visit(node.path, node); + this.visit(node.members, node); + } + visitExportDefaultStatement(node: ExportDefaultStatement, ref: Node | null = null): void { + this.visit(node.declaration, node); + } + visitExpressionStatement(node: ExpressionStatement, ref: Node | null = null): void { + this.visit(node.expression, ref); + } + visitFieldDeclaration(node: FieldDeclaration, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.type, node); + this.visit(node.initializer, node); + this.visit(node.decorators, node); + } + visitForStatement(node: ForStatement, ref: Node | null = null): void { + this.visit(node.initializer, node); + this.visit(node.condition, node); + this.visit(node.incrementor, node); + this.visit(node.body, node); + } + visitFunctionDeclaration(node: FunctionDeclaration, isDefault: boolean = false, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.decorators, node); + this.visit(node.typeParameters, node); + this.visit(node.signature, node); + this.visit(node.body, node); + } + visitIfStatement(node: IfStatement, ref: Node | null = null): void { + this.visit(node.condition, node); + this.visit(node.ifTrue, node); + this.visit(node.ifFalse, node); + } + visitImportDeclaration(node: ImportDeclaration, ref: Node | null = null): void { + this.visit(node.foreignName, node); + this.visit(node.name, node); + this.visit(node.decorators, node); + } + visitImportStatement(node: ImportStatement, ref: Node | null = null): void { + this.visit(node.namespaceName, node); + this.visit(node.declarations, node); + } + visitIndexSignature(node: IndexSignatureNode, ref: Node | null = null): void { + this.visit(node.keyType, node); + this.visit(node.valueType, node); + } + visitInterfaceDeclaration(node: InterfaceDeclaration, isDefault: boolean = false, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.typeParameters, node); + this.visit(node.implementsTypes, node); + this.visit(node.extendsType, node); + this.visit(node.members, node); + } + visitMethodDeclaration(node: MethodDeclaration, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.typeParameters, node); + this.visit(node.signature, node); + this.visit(node.decorators, node); + this.visit(node.body, node); + } + visitNamespaceDeclaration(node: NamespaceDeclaration, isDefault: boolean = false, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.decorators, node); + this.visit(node.members, node); + } + visitReturnStatement(node: ReturnStatement, ref: Node | null = null): void { + this.visit(node.value, node); + } + visitSwitchCase(node: SwitchCase, ref: Node | null = null): void { + this.visit(node.label, node); + this.visit(node.statements, node); + } + visitSwitchStatement(node: SwitchStatement, ref: Node | null = null): void { + this.visit(node.condition, node); + this.visit(node.cases, node); + } + visitThrowStatement(node: ThrowStatement, ref: Node | null = null): void { + this.visit(node.value, node); + } + visitTryStatement(node: TryStatement, ref: Node | null = null): void { + this.visit(node.bodyStatements, node); + this.visit(node.catchVariable, node); + this.visit(node.catchStatements, node); + this.visit(node.finallyStatements, node); + } + visitTypeDeclaration(node: TypeDeclaration, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.decorators, node); + this.visit(node.type, node); + this.visit(node.typeParameters, node); + } + visitVariableDeclaration(node: VariableDeclaration, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.type, node); + this.visit(node.initializer, node); + } + visitVariableStatement(node: VariableStatement, ref: Node | null = null): void { + this.visit(node.decorators, node); + this.visit(node.declarations, node); + } + visitWhileStatement(node: WhileStatement, ref: Node | null = null): void { + this.visit(node.condition, node); + this.visit(node.body, node); + } + visitVoidStatement(node: VoidStatement, ref: Node | null = null): void {} + visitComment(node: CommentNode, ref: Node | null = null): void {} + visitDecoratorNode(node: DecoratorNode, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.args, node); + } + visitParameter(node: ParameterNode, ref: Node | null = null): void { + this.visit(node.name, node); + this.visit(node.implicitFieldDeclaration, node); + this.visit(node.initializer, node); + this.visit(node.type, node); + } + visitCompiledExpression(node: CompiledExpression, ref: Node | null = null): void {} + visitForOfStatement(node: ForOfStatement, ref: Node | null = null): void { + this.visit(node.body, node); + this.visit(node.variable, node); + this.visit(node.iterable, node); + } + visitModuleDeclaration(node: ModuleDeclaration, ref: Node | null = null): void {} + visitOmittedExpression(node: OmittedExpression, ref: Node | null = null): void {} +}