From 1fad3d26c78c417a339ee9b4b053fec149f00b32 Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Sat, 10 Nov 2018 14:40:58 +0100 Subject: [PATCH] Add initial Date bindings Doesn't do much, yet, because we can't get the timezone with a plain binding, but it's at least something. --- std/assembly/bindings/Date.ts | 10 + std/assembly/date.ts | 37 +++ std/assembly/index.d.ts | 21 ++ std/portable/index.d.ts | 21 ++ tests/compiler.js | 3 +- tests/compiler/std/date.optimized.wat | 208 ++++++++++++++++ tests/compiler/std/date.ts | 14 ++ tests/compiler/std/date.untouched.wat | 327 ++++++++++++++++++++++++++ 8 files changed, 640 insertions(+), 1 deletion(-) create mode 100644 std/assembly/bindings/Date.ts create mode 100644 std/assembly/date.ts create mode 100644 tests/compiler/std/date.optimized.wat create mode 100644 tests/compiler/std/date.ts create mode 100644 tests/compiler/std/date.untouched.wat diff --git a/std/assembly/bindings/Date.ts b/std/assembly/bindings/Date.ts new file mode 100644 index 00000000..80fcc5f9 --- /dev/null +++ b/std/assembly/bindings/Date.ts @@ -0,0 +1,10 @@ +export declare function UTC( + year: i32, + month: i32, + day: i32, + hour: i32, + minute: i32, + second: i32, + millisecond: i32 +): f64; +export declare function now(): f64; diff --git a/std/assembly/date.ts b/std/assembly/date.ts new file mode 100644 index 00000000..23655350 --- /dev/null +++ b/std/assembly/date.ts @@ -0,0 +1,37 @@ +import { + UTC as Date_UTC, + now as Date_now +} from "./bindings/Date"; + +export class Date { + + @inline static UTC( + year: i32, + month: i32 = 0, + day: i32 = 1, + hour: i32 = 0, + minute: i32 = 0, + second: i32 = 0, + millisecond: i32 = 0 + ): i64 { + return Date_UTC(year, month, day, hour, minute, second, millisecond); + } + + @inline static now(): i64 { + return Date_now(); + } + + private value: i64; + + constructor(value: i64) { + this.value = value; + } + + getTime(): i64 { + return this.value; + } + + setTime(value: i64): void { + this.value = value; + } +} diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts index c7339487..1cc8f0e5 100644 --- a/std/assembly/index.d.ts +++ b/std/assembly/index.d.ts @@ -657,6 +657,27 @@ declare const Math: IMath; /** Alias of {@link NativeMathf} or {@link JSMath} respectively. Defaults to `NativeMathf`. */ declare const Mathf: IMath; +declare class Date { + /** Returns the UTC timestamp in milliseconds of the specified date. */ + static UTC( + year: i32, + month: i32, + day: i32, + hour: i32, + minute: i32, + second: i32, + millisecond: i32 + ): i64; + /** Returns the current UTC timestamp in milliseconds. */ + static now(): i64; + /** Constructs a new date object from an UTC timestamp in milliseconds. */ + constructor(value: i64); + /** Returns the UTC timestamp of this date in milliseconds. */ + getTime(): i64; + /** Sets the UTC timestamp of this date in milliseconds. */ + setTime(value: i64): void; +} + /** Environmental tracing function for debugging purposes. */ declare function trace(msg: string, n?: i32, a0?: f64, a1?: f64, a2?: f64, a3?: f64, a4?: f64): void; diff --git a/std/portable/index.d.ts b/std/portable/index.d.ts index c941785b..82c0a0b0 100644 --- a/std/portable/index.d.ts +++ b/std/portable/index.d.ts @@ -424,6 +424,27 @@ declare const Math: IMath; declare const Mathf: IMath; declare const JSMath: IMath; +declare class Date { + /** Returns the UTC timestamp in milliseconds of the specified date. */ + static UTC( + year: i32, + month: i32, + day: i32, + hour: i32, + minute: i32, + second: i32, + millisecond: i32 + ): number; + /** Returns the current UTC timestamp in milliseconds. */ + static now(): number; + /** Constructs a new date object from an UTC timestamp in milliseconds. */ + constructor(value: number); + /** Returns the UTC timestamp of this date in milliseconds. */ + getTime(): number; + /** Sets the UTC timestamp of this date in milliseconds. */ + setTime(value: number): void; +} + declare namespace console { /** @deprecated */ function log(message: string): void; diff --git a/tests/compiler.js b/tests/compiler.js index 8846efd7..c5642072 100644 --- a/tests/compiler.js +++ b/tests/compiler.js @@ -192,7 +192,8 @@ tests.forEach(filename => { math: { mod: function(a, b) { return a % b; } }, - Math: Math, + Math, + Date, // tests/declare declare: { diff --git a/tests/compiler/std/date.optimized.wat b/tests/compiler/std/date.optimized.wat new file mode 100644 index 00000000..b8df80fb --- /dev/null +++ b/tests/compiler/std/date.optimized.wat @@ -0,0 +1,208 @@ +(module + (type $iiiiiiiF (func (param i32 i32 i32 i32 i32 i32 i32) (result f64))) + (type $iiiiv (func (param i32 i32 i32 i32))) + (type $F (func (result f64))) + (type $ii (func (param i32) (result i32))) + (type $v (func)) + (import "Date" "UTC" (func $~lib/bindings/Date/UTC (param i32 i32 i32 i32 i32 i32 i32) (result f64))) + (import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32))) + (import "Date" "now" (func $~lib/bindings/Date/now (result f64))) + (memory $0 1) + (data (i32.const 8) "\0b\00\00\00s\00t\00d\00/\00d\00a\00t\00e\00.\00t\00s") + (table $0 1 anyfunc) + (elem (i32.const 0) $null) + (global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0)) + (global $~lib/allocator/arena/offset (mut i32) (i32.const 0)) + (global $std/date/creationTime (mut i64) (i64.const 0)) + (global $std/date/date (mut i32) (i32.const 0)) + (export "memory" (memory $0)) + (export "table" (table $0)) + (start $start) + (func $~lib/allocator/arena/__memory_allocate (; 3 ;) (type $ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + get_local $0 + i32.const 1073741824 + i32.gt_u + if + unreachable + end + get_global $~lib/allocator/arena/offset + tee_local $1 + get_local $0 + i32.const 1 + get_local $0 + i32.const 1 + i32.gt_u + select + i32.add + i32.const 7 + i32.add + i32.const -8 + i32.and + tee_local $2 + current_memory + tee_local $3 + i32.const 16 + i32.shl + i32.gt_u + if + get_local $3 + get_local $2 + get_local $1 + i32.sub + i32.const 65535 + i32.add + i32.const -65536 + i32.and + i32.const 16 + i32.shr_u + tee_local $0 + get_local $3 + get_local $0 + i32.gt_s + select + grow_memory + i32.const 0 + i32.lt_s + if + get_local $0 + grow_memory + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + get_local $2 + set_global $~lib/allocator/arena/offset + get_local $1 + ) + (func $start (; 4 ;) (type $v) + (local $0 i32) + (local $1 i64) + i32.const 40 + set_global $~lib/allocator/arena/startOffset + get_global $~lib/allocator/arena/startOffset + set_global $~lib/allocator/arena/offset + i32.const 1970 + i32.const 0 + i32.const 1 + i32.const 0 + i32.const 0 + i32.const 0 + i32.const 0 + call $~lib/bindings/Date/UTC + i64.trunc_s/f64 + i64.const 0 + i64.ne + if + i32.const 0 + i32.const 8 + i32.const 3 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 1970 + i32.const 0 + i32.const 1 + i32.const 0 + i32.const 0 + i32.const 0 + i32.const 0 + call $~lib/bindings/Date/UTC + i64.trunc_s/f64 + i64.const 0 + i64.ne + if + i32.const 0 + i32.const 8 + i32.const 4 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 2018 + i32.const 10 + i32.const 10 + i32.const 11 + i32.const 0 + i32.const 0 + i32.const 1 + call $~lib/bindings/Date/UTC + i64.trunc_s/f64 + set_global $std/date/creationTime + get_global $std/date/creationTime + i64.const 1541847600001 + i64.ne + if + i32.const 0 + i32.const 8 + i32.const 7 + i32.const 0 + call $~lib/env/abort + unreachable + end + call $~lib/bindings/Date/now + i64.trunc_s/f64 + get_global $std/date/creationTime + i64.le_s + if + i32.const 0 + i32.const 8 + i32.const 9 + i32.const 0 + call $~lib/env/abort + unreachable + end + get_global $std/date/creationTime + set_local $1 + i32.const 8 + call $~lib/allocator/arena/__memory_allocate + tee_local $0 + i64.const 0 + i64.store + get_local $0 + get_local $1 + i64.store + get_local $0 + set_global $std/date/date + get_global $std/date/date + i64.load + get_global $std/date/creationTime + i64.ne + if + i32.const 0 + i32.const 8 + i32.const 12 + i32.const 0 + call $~lib/env/abort + unreachable + end + get_global $std/date/date + get_global $std/date/creationTime + i64.const 1 + i64.add + i64.store + get_global $std/date/date + i64.load + get_global $std/date/creationTime + i64.const 1 + i64.add + i64.ne + if + i32.const 0 + i32.const 8 + i32.const 14 + i32.const 0 + call $~lib/env/abort + unreachable + end + ) + (func $null (; 5 ;) (type $v) + nop + ) +) diff --git a/tests/compiler/std/date.ts b/tests/compiler/std/date.ts new file mode 100644 index 00000000..c118d4d4 --- /dev/null +++ b/tests/compiler/std/date.ts @@ -0,0 +1,14 @@ +import "allocator/arena"; + +assert(Date.UTC(1970, 0, 1) == 0); +assert(Date.UTC(1970, 0, 1, 0, 0, 0, 0) == 0); + +var creationTime = Date.UTC(2018, 10, 10, 11, 0, 0, 1); +assert(creationTime == 1541847600001); + +assert(Date.now() > creationTime); + +var date = new Date(creationTime); +assert(date.getTime() == creationTime); +date.setTime(creationTime + 1); +assert(date.getTime() == creationTime + 1); diff --git a/tests/compiler/std/date.untouched.wat b/tests/compiler/std/date.untouched.wat new file mode 100644 index 00000000..18c36586 --- /dev/null +++ b/tests/compiler/std/date.untouched.wat @@ -0,0 +1,327 @@ +(module + (type $iiiiiiiF (func (param i32 i32 i32 i32 i32 i32 i32) (result f64))) + (type $iiiiv (func (param i32 i32 i32 i32))) + (type $F (func (result f64))) + (type $iIi (func (param i32 i64) (result i32))) + (type $ii (func (param i32) (result i32))) + (type $iI (func (param i32) (result i64))) + (type $iIv (func (param i32 i64))) + (type $v (func)) + (import "Date" "UTC" (func $~lib/bindings/Date/UTC (param i32 i32 i32 i32 i32 i32 i32) (result f64))) + (import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32))) + (import "Date" "now" (func $~lib/bindings/Date/now (result f64))) + (memory $0 1) + (data (i32.const 8) "\0b\00\00\00s\00t\00d\00/\00d\00a\00t\00e\00.\00t\00s\00") + (table $0 1 anyfunc) + (elem (i32.const 0) $null) + (global $~lib/internal/allocator/AL_BITS i32 (i32.const 3)) + (global $~lib/internal/allocator/AL_SIZE i32 (i32.const 8)) + (global $~lib/internal/allocator/AL_MASK i32 (i32.const 7)) + (global $~lib/internal/allocator/MAX_SIZE_32 i32 (i32.const 1073741824)) + (global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0)) + (global $~lib/allocator/arena/offset (mut i32) (i32.const 0)) + (global $std/date/creationTime (mut i64) (i64.const 0)) + (global $std/date/date (mut i32) (i32.const 0)) + (global $HEAP_BASE i32 (i32.const 36)) + (export "memory" (memory $0)) + (export "table" (table $0)) + (start $start) + (func $~lib/allocator/arena/__memory_allocate (; 3 ;) (type $ii) (param $0 i32) (result i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + get_local $0 + get_global $~lib/internal/allocator/MAX_SIZE_32 + i32.gt_u + if + unreachable + end + get_global $~lib/allocator/arena/offset + set_local $1 + get_local $1 + get_local $0 + tee_local $2 + i32.const 1 + tee_local $3 + get_local $2 + get_local $3 + i32.gt_u + select + i32.add + get_global $~lib/internal/allocator/AL_MASK + i32.add + get_global $~lib/internal/allocator/AL_MASK + i32.const -1 + i32.xor + i32.and + set_local $4 + current_memory + set_local $5 + get_local $4 + get_local $5 + i32.const 16 + i32.shl + i32.gt_u + if + get_local $4 + get_local $1 + i32.sub + i32.const 65535 + i32.add + i32.const 65535 + i32.const -1 + i32.xor + i32.and + i32.const 16 + i32.shr_u + set_local $2 + get_local $5 + tee_local $3 + get_local $2 + tee_local $6 + get_local $3 + get_local $6 + i32.gt_s + select + set_local $3 + get_local $3 + grow_memory + i32.const 0 + i32.lt_s + if + get_local $2 + grow_memory + i32.const 0 + i32.lt_s + if + unreachable + end + end + end + get_local $4 + set_global $~lib/allocator/arena/offset + get_local $1 + ) + (func $~lib/memory/memory.allocate (; 4 ;) (type $ii) (param $0 i32) (result i32) + get_local $0 + call $~lib/allocator/arena/__memory_allocate + return + ) + (func $~lib/date/Date#constructor (; 5 ;) (type $iIi) (param $0 i32) (param $1 i64) (result i32) + (local $2 i32) + get_local $0 + if (result i32) + get_local $0 + else + block (result i32) + i32.const 8 + call $~lib/memory/memory.allocate + set_local $2 + get_local $2 + i64.const 0 + i64.store + get_local $2 + end + tee_local $0 + end + tee_local $0 + get_local $1 + i64.store + get_local $0 + ) + (func $~lib/date/Date#getTime (; 6 ;) (type $iI) (param $0 i32) (result i64) + get_local $0 + i64.load + ) + (func $~lib/date/Date#setTime (; 7 ;) (type $iIv) (param $0 i32) (param $1 i64) + get_local $0 + get_local $1 + i64.store + ) + (func $start (; 8 ;) (type $v) + (local $0 i32) + (local $1 i32) + (local $2 i32) + (local $3 i32) + (local $4 i32) + (local $5 i32) + (local $6 i32) + get_global $HEAP_BASE + get_global $~lib/internal/allocator/AL_MASK + i32.add + get_global $~lib/internal/allocator/AL_MASK + i32.const -1 + i32.xor + i32.and + set_global $~lib/allocator/arena/startOffset + get_global $~lib/allocator/arena/startOffset + set_global $~lib/allocator/arena/offset + block $~lib/date/Date.UTC|inlined.0 (result i64) + i32.const 1970 + set_local $0 + i32.const 0 + set_local $1 + i32.const 1 + set_local $2 + i32.const 0 + set_local $3 + i32.const 0 + set_local $4 + i32.const 0 + set_local $5 + i32.const 0 + set_local $6 + get_local $0 + get_local $1 + get_local $2 + get_local $3 + get_local $4 + get_local $5 + get_local $6 + call $~lib/bindings/Date/UTC + i64.trunc_s/f64 + end + i64.const 0 + i64.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 3 + i32.const 0 + call $~lib/env/abort + unreachable + end + block $~lib/date/Date.UTC|inlined.1 (result i64) + i32.const 1970 + set_local $6 + i32.const 0 + set_local $5 + i32.const 1 + set_local $4 + i32.const 0 + set_local $3 + i32.const 0 + set_local $2 + i32.const 0 + set_local $1 + i32.const 0 + set_local $0 + get_local $6 + get_local $5 + get_local $4 + get_local $3 + get_local $2 + get_local $1 + get_local $0 + call $~lib/bindings/Date/UTC + i64.trunc_s/f64 + end + i64.const 0 + i64.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 4 + i32.const 0 + call $~lib/env/abort + unreachable + end + block $~lib/date/Date.UTC|inlined.2 (result i64) + i32.const 2018 + set_local $0 + i32.const 10 + set_local $1 + i32.const 10 + set_local $2 + i32.const 11 + set_local $3 + i32.const 0 + set_local $4 + i32.const 0 + set_local $5 + i32.const 1 + set_local $6 + get_local $0 + get_local $1 + get_local $2 + get_local $3 + get_local $4 + get_local $5 + get_local $6 + call $~lib/bindings/Date/UTC + i64.trunc_s/f64 + end + set_global $std/date/creationTime + get_global $std/date/creationTime + i64.const 1541847600001 + i64.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 7 + i32.const 0 + call $~lib/env/abort + unreachable + end + block $~lib/date/Date.now|inlined.0 (result i64) + call $~lib/bindings/Date/now + i64.trunc_s/f64 + end + get_global $std/date/creationTime + i64.gt_s + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 9 + i32.const 0 + call $~lib/env/abort + unreachable + end + i32.const 0 + get_global $std/date/creationTime + call $~lib/date/Date#constructor + set_global $std/date/date + get_global $std/date/date + call $~lib/date/Date#getTime + get_global $std/date/creationTime + i64.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 12 + i32.const 0 + call $~lib/env/abort + unreachable + end + get_global $std/date/date + get_global $std/date/creationTime + i64.const 1 + i64.add + call $~lib/date/Date#setTime + get_global $std/date/date + call $~lib/date/Date#getTime + get_global $std/date/creationTime + i64.const 1 + i64.add + i64.eq + i32.eqz + if + i32.const 0 + i32.const 8 + i32.const 14 + i32.const 0 + call $~lib/env/abort + unreachable + end + ) + (func $null (; 9 ;) (type $v) + ) +)