From f2280797d5d2dd1993d08b90495079f103e7bdb1 Mon Sep 17 00:00:00 2001 From: jinser Date: Thu, 5 Dec 2024 11:49:54 +0800 Subject: [PATCH] refactor: moon fmt and moon info (#79) * refactor: run `moon fmt --block-style` * refactor: run `moon info` generate mbti for all packages --- benchmark/benchmark.mbt | 7 ++ benchmark/internal/ffi/ffi_js.mbt | 3 + benchmark/internal/ffi/ffi_native.mbt | 3 + benchmark/internal/ffi/ffi_wasm.mbt | 3 + benchmark/types.mbt | 3 + crypto/chacha.mbt | 20 ++++-- crypto/md5.mbt | 18 ++++-- crypto/md5_test.mbt | 1 + crypto/sha1.mbt | 1 + crypto/sha1_test.mbt | 1 + crypto/sha224.mbt | 2 + crypto/sha256.mbt | 15 +++-- crypto/sha256_test.mbt | 2 + crypto/sm3.mbt | 21 ++++-- crypto/sm3_test.mbt | 1 + crypto/utils.mbt | 27 ++++---- fs/fs.mbt | 25 ++++---- fs/internal/ffi/fs_js.mbt | 22 +++++++ fs/internal/ffi/fs_native.mbt | 22 +++++++ fs/internal/ffi/fs_wasm.mbt | 25 ++++++++ internal/ffi/byte_array_wasm.mbt | 11 ++++ internal/ffi/dir_wasm.mbt | 6 ++ internal/ffi/string_wasm.mbt | 12 +++- json5/internal_types.mbt | 12 ++++ json5/json5.mbti | 6 -- json5/lex_main.mbt | 1 + json5/lex_misc.mbt | 8 +++ json5/lex_number.mbt | 11 ++++ json5/lex_prop.mbt | 2 + json5/lex_string.mbt | 2 + json5/parse.mbt | 5 ++ json5/parse_test.mbt | 1 + json5/types.mbt | 6 ++ json5/unicode_gen.mbt | 3 + json5/util.mbt | 3 + num/num.mbt | 1 + stack/stack.mbt | 51 ++++++++------- stack/stack.mbti | 1 - stack/types.mbt | 1 + sys/internal/ffi/sys_js.mbt | 5 ++ sys/internal/ffi/sys_native.mbt | 3 + sys/internal/ffi/sys_wasm.mbt | 6 ++ sys/sys.mbt | 3 + time/duration.mbt | 37 ++++++----- time/errors.mbt | 6 ++ time/period.mbt | 45 +++++++------ time/plain_date.mbt | 84 +++++++++++++++--------- time/plain_date_time.mbt | 86 +++++++++++++------------ time/plain_time.mbt | 70 +++++++++++++------- time/time.mbti | 12 ---- time/util.mbt | 21 ++++-- time/weekday.mbt | 3 + time/zone.mbt | 12 ++-- time/zone_offset.mbt | 25 +++++--- time/zoned_date_time.mbt | 92 ++++++++++++++------------- uuid/ops.mbt | 1 + uuid/uuid.mbt | 15 +++-- uuid/uuid.mbti | 2 - uuid/variant.mbt | 12 ++-- 59 files changed, 613 insertions(+), 292 deletions(-) diff --git a/benchmark/benchmark.mbt b/benchmark/benchmark.mbt index 799bd4e..dcd173a 100644 --- a/benchmark/benchmark.mbt +++ b/benchmark/benchmark.mbt @@ -12,10 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub fn Task::new(name : String, f : () -> Unit, count~ : Int = 10) -> Task { { name, f, count } } +///| pub fn run(self : Task) -> TaskResult { let now = @ffi.instant_now() for i = 1; i <= self.count; i = i + 1 { @@ -34,6 +36,7 @@ pub fn run(self : Task) -> TaskResult { { task: self, average: time / self.count.to_double(), max, min } } +///| pub fn to_string(self : TaskResult) -> String { $|Benchmark Task [\{self.task.name}] Count = \{self.task.count} $|---------------------------------------- @@ -43,18 +46,22 @@ pub fn to_string(self : TaskResult) -> String { $|---------------------------------------- } +///| pub fn output(self : TaskResult, logger : Logger) -> Unit { logger.write_string(self.to_string()) } +///| pub fn Criterion::new() -> Criterion { { tasks: [] } } +///| pub fn add(self : Criterion, task : Task) -> Unit { self.tasks.push(task) } +///| pub fn run(self : Criterion) -> Map[String, TaskResult] { let map = {} for task in self.tasks { diff --git a/benchmark/internal/ffi/ffi_js.mbt b/benchmark/internal/ffi/ffi_js.mbt index c92f4ff..7d66055 100644 --- a/benchmark/internal/ffi/ffi_js.mbt +++ b/benchmark/internal/ffi/ffi_js.mbt @@ -12,11 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| type Date +///| pub extern "js" fn instant_now() -> Date = #| () => new Date() +///| pub extern "js" fn instant_elapsed_as_secs_f64(x : Date) -> Double = #|function cost(x){ #| const now = new Date(); diff --git a/benchmark/internal/ffi/ffi_native.mbt b/benchmark/internal/ffi/ffi_native.mbt index 1f09feb..90ee155 100644 --- a/benchmark/internal/ffi/ffi_native.mbt +++ b/benchmark/internal/ffi/ffi_native.mbt @@ -12,13 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| type Instant +///| pub fn instant_now() -> Instant { // no implement now panic() } +///| pub fn instant_elapsed_as_secs_f64(_x : Instant) -> Double { // no implement now panic() diff --git a/benchmark/internal/ffi/ffi_wasm.mbt b/benchmark/internal/ffi/ffi_wasm.mbt index 6367771..69841f9 100644 --- a/benchmark/internal/ffi/ffi_wasm.mbt +++ b/benchmark/internal/ffi/ffi_wasm.mbt @@ -12,8 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| type Instant +///| pub fn instant_now() -> Instant = "__moonbit_time_unstable" "instant_now" +///| pub fn instant_elapsed_as_secs_f64(x : Instant) -> Double = "__moonbit_time_unstable" "instant_elapsed_as_secs_f64" diff --git a/benchmark/types.mbt b/benchmark/types.mbt index 3853af5..da1326d 100644 --- a/benchmark/types.mbt +++ b/benchmark/types.mbt @@ -12,12 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| struct Task { name : String f : () -> Unit count : Int } +///| pub(readonly) struct TaskResult { task : Task average : Double @@ -25,6 +27,7 @@ pub(readonly) struct TaskResult { min : Double } +///| struct Criterion { tasks : Array[Task] } diff --git a/crypto/chacha.mbt b/crypto/chacha.mbt index 5b726e9..bea950b 100644 --- a/crypto/chacha.mbt +++ b/crypto/chacha.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn flipWord(word : UInt) -> UInt { let b0 = (word & 0xff) << 24 let b1 = (word & 0xff00) << 8 @@ -26,6 +27,7 @@ test "flipWord" { inspect!(flipped, content="2018915346") } +///| fn quarterRound( state : FixedArray[UInt], w : Int, @@ -75,6 +77,7 @@ test "quarterRound" { ) } +///| fn chachaBlockRound(state : FixedArray[UInt]) -> FixedArray[UInt] { let state1 = quarterRound(state, 0, 4, 8, 12) let state2 = quarterRound(state1, 1, 5, 9, 13) @@ -112,6 +115,7 @@ test "chachaBlockRound" { ) } +///| fn chachaBlockLoop(state : FixedArray[UInt], n : UInt) -> FixedArray[UInt] { match n { 0 => state.copy() @@ -158,10 +162,12 @@ test "chachaBlockLoop" { ) } +///| fn flipState(state : FixedArray[UInt]) -> FixedArray[UInt] { state.map(flipWord) } +///| fn zipWith( op : (UInt, UInt) -> UInt, state1 : FixedArray[UInt], @@ -189,7 +195,7 @@ test "zipWith" { inspect!(result, content="[6, 8, 10, 12]") } -/// - chacha8: round = 4 +///| - chacha8: round = 4 /// - chacha12: round = 6 /// - chacha20: round = 10 fn chachaBlock( @@ -240,6 +246,7 @@ test "chachaBlock" { ) } +///| fn stateToBytes(state : FixedArray[UInt]) -> Bytes { fn from_array(arr : Array[UInt]) -> Bytes { let rv = Bytes::new(arr.length()) @@ -285,7 +292,7 @@ test "stateToBytes" { ) } -/// Encrypts a block of data using the ChaCha8 algorithm. +///| Encrypts a block of data using the ChaCha8 algorithm. /// - [key] must be 8 32-bit unsigned integers. /// - [counter] is the counter value. /// - [block] is the block of data to be encrypted. @@ -303,7 +310,7 @@ pub fn chacha8( chacha(key, counter, block, 4, nonce) } -/// Encrypts a block of data using the ChaCha12 algorithm. +///| Encrypts a block of data using the ChaCha12 algorithm. /// - [key] must be 8 32-bit unsigned integers. /// - [counter] is the counter value. /// - [block] is the block of data to be encrypted. @@ -321,7 +328,7 @@ pub fn chacha12( chacha(key, counter, block, 6, nonce) } -/// Encrypts a block of data using the ChaCha20 algorithm. +///| Encrypts a block of data using the ChaCha20 algorithm. /// - [key] must be 8 32-bit unsigned integers. /// - [counter] is the counter value. /// - [block] is the block of data to be encrypted. @@ -339,6 +346,7 @@ pub fn chacha20( chacha(key, counter, block, 10, nonce) } +///| fn chacha( key : FixedArray[UInt], counter : UInt, @@ -403,6 +411,7 @@ fn chacha( res } +///| fn quarterRound1(t : (UInt, UInt, UInt, UInt)) -> (UInt, UInt, UInt, UInt) { let aprime = t.0 + t.1 let dprime = t.3 ^ aprime @@ -410,6 +419,7 @@ fn quarterRound1(t : (UInt, UInt, UInt, UInt)) -> (UInt, UInt, UInt, UInt) { (aprime, t.1, t.2, dout) } +///| fn quarterRound2(t : (UInt, UInt, UInt, UInt)) -> (UInt, UInt, UInt, UInt) { let cprime = t.2 + t.3 let bprime = t.1 ^ cprime @@ -417,6 +427,7 @@ fn quarterRound2(t : (UInt, UInt, UInt, UInt)) -> (UInt, UInt, UInt, UInt) { (t.0, bout, cprime, t.3) } +///| fn quarterRound3(t : (UInt, UInt, UInt, UInt)) -> (UInt, UInt, UInt, UInt) { let aprime = t.0 + t.1 let dprime = t.3 ^ aprime @@ -424,6 +435,7 @@ fn quarterRound3(t : (UInt, UInt, UInt, UInt)) -> (UInt, UInt, UInt, UInt) { (aprime, t.1, t.2, dout) } +///| fn quarterRound4(t : (UInt, UInt, UInt, UInt)) -> (UInt, UInt, UInt, UInt) { let cprime = t.2 + t.3 let bprime = t.1 ^ cprime diff --git a/crypto/md5.mbt b/crypto/md5.mbt index 37f7bc2..442baf0 100644 --- a/crypto/md5.mbt +++ b/crypto/md5.mbt @@ -16,25 +16,27 @@ // [RFC1321] https://www.ietf.org/rfc/rfc1321.txt // [Ron Rivest] https://people.csail.mit.edu/rivest/Md5.c // [md5-0.7.0] https://docs.rs/md5/0.7.0/src/md5/lib.rs.html +///| struct MD5Context { state : FixedArray[UInt] // state 'a' 'b' 'c' 'd' count : FixedArray[UInt] buffer : Bytes } +///| let padding : Bytes = Bytes::make(64, b'\x00') -/// update the state of given context from new `data` +///| update the state of given context from new `data` pub fn MD5Context::update(self : MD5Context, data : Bytes) -> Unit { md5_update(self, data) } -/// an alias of `MD5Context::compute()` +///| an alias of `MD5Context::compute()` pub fn MD5Context::finalize(self : MD5Context) -> Bytes { self.md5_compute() } -/// Instantiate a MD5 context +///| Instantiate a MD5 context pub fn MD5Context::new() -> MD5Context { padding[0] = b'\x80' { @@ -44,7 +46,7 @@ pub fn MD5Context::new() -> MD5Context { } } -/// compute MD5 digest from given context +///| compute MD5 digest from given context fn MD5Context::md5_compute(self : MD5Context) -> Bytes { let input = FixedArray::make(16, 0U) let idx = ((self.count[0] >> 3) & 0x3f).reinterpret_as_int() @@ -89,22 +91,27 @@ fn MD5Context::md5_compute(self : MD5Context) -> Bytes { // G(X,Y,Z) = XZ v Y not(Z) // H(X,Y,Z) = X xor Y xor Z // I(X,Y,Z) = Y xor (X v not(Z)) +///| fn MD5Context::f(x : UInt, y : UInt, z : UInt) -> UInt { (x & y) | (x.lnot() & z) } +///| fn MD5Context::g(x : UInt, y : UInt, z : UInt) -> UInt { ((x ^ y) & z) ^ y } +///| fn MD5Context::h(x : UInt, y : UInt, z : UInt) -> UInt { x ^ y ^ z } +///| fn MD5Context::i(x : UInt, y : UInt, z : UInt) -> UInt { y ^ (x | z.lnot()) } +///| fn md5_update(ctx : MD5Context, data : Bytes) -> Unit { let input = FixedArray::make(16, 0U) let mut idx = ((ctx.count[0] >> 3) & 0x3f).reinterpret_as_int() @@ -130,6 +137,7 @@ fn md5_update(ctx : MD5Context, data : Bytes) -> Unit { } } +///| fn md5_transform(state : FixedArray[UInt], input : FixedArray[UInt]) -> Unit { let mut a = state[0] let mut b = state[1] @@ -217,7 +225,7 @@ fn md5_transform(state : FixedArray[UInt], input : FixedArray[UInt]) -> Unit { state[3] += d } -/// Compute the MD5 digest of some `data` based on [RFC1321](https://www.ietf.org/rfc/rfc1321.txt). +///| Compute the MD5 digest of some `data` based on [RFC1321](https://www.ietf.org/rfc/rfc1321.txt). /// - Note that MD5 is considered _cryptographically broken_. /// Unless mandated, more secure alternatives should be preferred. pub fn md5(data : Bytes) -> Bytes { diff --git a/crypto/md5_test.mbt b/crypto/md5_test.mbt index 4549764..ff80823 100644 --- a/crypto/md5_test.mbt +++ b/crypto/md5_test.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn md5test(s : String) -> String { bytes_to_hex_string(@crypto.md5(s.to_bytes())) } diff --git a/crypto/sha1.mbt b/crypto/sha1.mbt index e132732..898c2a8 100644 --- a/crypto/sha1.mbt +++ b/crypto/sha1.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub fn sha1(input : Bytes) -> Bytes { // Padding let old_length = input.length() diff --git a/crypto/sha1_test.mbt b/crypto/sha1_test.mbt index 2926a6e..54e250e 100644 --- a/crypto/sha1_test.mbt +++ b/crypto/sha1_test.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| let bytes_to_hex_string = @crypto.bytes_to_hex_string test "sha1" { diff --git a/crypto/sha224.mbt b/crypto/sha224.mbt index 90193bf..773338a 100644 --- a/crypto/sha224.mbt +++ b/crypto/sha224.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub fn sha224(data : Bytes) -> Bytes { let ctx = Sha256Context::new( reg=[ @@ -23,6 +24,7 @@ pub fn sha224(data : Bytes) -> Bytes { arr_u32_to_u8be(ctx.sha256_compute().iter().take(7), 224) } +///| pub fn sha224_from_iter(data : Iter[Byte]) -> Bytes { let ctx = Sha256Context::new( reg=[ diff --git a/crypto/sha256.mbt b/crypto/sha256.mbt index 4e32249..a660768 100644 --- a/crypto/sha256.mbt +++ b/crypto/sha256.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| struct Sha256Context { reg : FixedArray[UInt] // register A B C D E F G H. i.e. digest mut len : UInt64 @@ -19,7 +20,7 @@ struct Sha256Context { mut buf_index : Int } -/// Instantiate a Sha256 context +///| Instantiate a Sha256 context /// `reg` is the initial hash value. Defaults to Sha256's. pub fn Sha256Context::new( reg~ : FixedArray[UInt] = [ @@ -30,6 +31,7 @@ pub fn Sha256Context::new( { reg, len: 0, buf: Bytes::new(64), buf_index: 0 } } +///| let sha256_t : FixedArray[UInt] = [ // pre calculated 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, @@ -43,6 +45,7 @@ let sha256_t : FixedArray[UInt] = [ // pre calculated 0xc67178f2, ] +///| fn pad(self : Sha256Context) -> Bytes { let mut cnt = self.buf_index self.len += 8UL * cnt.to_uint64() @@ -68,6 +71,7 @@ fn pad(self : Sha256Context) -> Bytes { return self.buf } +///| fn transform( self : Sha256Context, data : Bytes, @@ -123,6 +127,7 @@ fn transform( self.reg } +///| pub fn update_from_iter(self : Sha256Context, data : Iter[Byte]) -> Unit { data.each( fn(b) { @@ -138,7 +143,7 @@ pub fn update_from_iter(self : Sha256Context, data : Iter[Byte]) -> Unit { ) } -/// update the state of given context from new `data` +///| update the state of given context from new `data` pub fn update(self : Sha256Context, data : Bytes) -> Unit { let mut offset = 0 while offset < data.length() { @@ -159,6 +164,7 @@ pub fn update(self : Sha256Context, data : Bytes) -> Unit { } } +///| fn sha256_compute( self : Sha256Context, data~ : Iter[Byte] = Iter::empty() @@ -173,18 +179,19 @@ fn sha256_compute( } } -/// Compute the Sha256 digest from given Sha256Context +///| Compute the Sha256 digest from given Sha256Context pub fn finalize(self : Sha256Context) -> Bytes { arr_u32_to_u8be(self.sha256_compute().iter(), 256) } -/// Compute the Sha256 digest in `Bytes` of some `data`. Note that Sha256 is big-endian. +///| Compute the Sha256 digest in `Bytes` of some `data`. Note that Sha256 is big-endian. pub fn sha256(data : Bytes) -> Bytes { let ctx = Sha256Context::new() let _ = ctx.update(data) arr_u32_to_u8be(ctx.sha256_compute().iter(), 256) } +///| pub fn sha256_from_iter(data : Iter[Byte]) -> Bytes { let ctx = Sha256Context::new() let _ = ctx.update_from_iter(data) diff --git a/crypto/sha256_test.mbt b/crypto/sha256_test.mbt index 4ce5fe8..9f7011f 100644 --- a/crypto/sha256_test.mbt +++ b/crypto/sha256_test.mbt @@ -12,10 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn sha256test(s : String) -> String { @crypto.bytes_to_hex_string(@crypto.sha256(s.to_bytes())) } +///| fn sha224test(s : String) -> String { @crypto.bytes_to_hex_string(@crypto.sha224(s.to_bytes())) } diff --git a/crypto/sm3.mbt b/crypto/sm3.mbt index 8c1ae40..1ab96ac 100644 --- a/crypto/sm3.mbt +++ b/crypto/sm3.mbt @@ -16,6 +16,7 @@ // - [GM/T 0004-2012] https://www.oscca.gov.cn/sca/xxgk/2010-12/17/1002389/files/302a3ada057c4a73830536d03e683110.pdf // SM3 is as secure as SHA256, providing similar performance. https://doi.org/10.3390/electronics8091033 +///| struct SM3Context { reg : FixedArray[UInt] // register A B C D E F G H. i.e. digest mut len : UInt64 @@ -23,7 +24,7 @@ struct SM3Context { mut buf_index : Int } -/// Instantiate a SM3 context +///| Instantiate a SM3 context pub fn SM3Context::new() -> SM3Context { { reg: [ @@ -36,6 +37,7 @@ pub fn SM3Context::new() -> SM3Context { } } +///| let t : FixedArray[UInt] = [ // pre calculated 0x79cc4519, 0xf3988a32, 0xe7311465, 0xce6228cb, 0x9cc45197, 0x3988a32f, 0x7311465e, 0xe6228cbc, 0xcc451979, 0x988a32f3, 0x311465e7, 0x6228cbce, 0xc451979c, 0x88a32f39, @@ -52,34 +54,41 @@ let t : FixedArray[UInt] = [ // pre calculated // auxiliary functions // FF_j = | X xor Y xor Z where 0 <= j <= 15 // | (X and Y) or (X and Z) or (Y and Z) where 16 <= j <=63 +///| fn SM3Context::ff_0(x : UInt, y : UInt, z : UInt) -> UInt { x ^ y ^ z } +///| fn SM3Context::ff_1(x : UInt, y : UInt, z : UInt) -> UInt { (x & y) | (x & z) | (y & z) } // GG_j = | X xor Y xor Z where 0 <= j <= 15 // | (X and Y) or (~X and Z) where 16 <= j <= 63 +///| fn SM3Context::gg_0(x : UInt, y : UInt, z : UInt) -> UInt { x ^ y ^ z } +///| fn SM3Context::gg_1(x : UInt, y : UInt, z : UInt) -> UInt { ((y ^ z) & x) ^ z // equivalent of (x & y) | (x.lnot() & z), but faster } // P_0 = X xor (X <<< 9) xor (X <<< 17) // P_1 = X xor (X <<< 15) xor (X <<< 23) +///| fn SM3Context::p_0(x : UInt) -> UInt { x ^ rotate_left_u(x, 9) ^ rotate_left_u(x, 17) } +///| fn SM3Context::p_1(x : UInt) -> UInt { x ^ rotate_left_u(x, 15) ^ rotate_left_u(x, 23) } +///| fn pad(self : SM3Context) -> Bytes { let mut cnt = self.buf_index self.len += 8UL * cnt.to_uint64() @@ -105,6 +114,7 @@ fn pad(self : SM3Context) -> Bytes { return self.buf } +///| fn transform( self : SM3Context, data : Bytes, @@ -184,6 +194,7 @@ fn transform( return t_arr } +///| pub fn update_from_iter(self : SM3Context, data : Iter[Byte]) -> Unit { data.each( fn(b) { @@ -199,7 +210,7 @@ pub fn update_from_iter(self : SM3Context, data : Iter[Byte]) -> Unit { ) } -/// update the state of given context from new `data` +///| update the state of given context from new `data` pub fn update(self : SM3Context, data : Bytes) -> Unit { let mut offset = 0 while offset < data.length() { @@ -220,6 +231,7 @@ pub fn update(self : SM3Context, data : Bytes) -> Unit { } } +///| fn sm3_compute( self : SM3Context, data~ : Iter[Byte] = Iter::empty() @@ -234,18 +246,19 @@ fn sm3_compute( } } -/// Compute the SM3 digest from given SM3Context +///| Compute the SM3 digest from given SM3Context pub fn finalize(self : SM3Context) -> Bytes { arr_u32_to_u8be(self.sm3_compute().iter(), 256) } -/// Compute the SM3 digest in `Bytes` of some `data`. Note that SM3 is big-endian. +///| Compute the SM3 digest in `Bytes` of some `data`. Note that SM3 is big-endian. pub fn sm3(data : Bytes) -> Bytes { let ctx = SM3Context::new() let _ = ctx.update(data) arr_u32_to_u8be(ctx.sm3_compute().iter(), 256) } +///| pub fn sm3_from_iter(data : Iter[Byte]) -> Bytes { let ctx = SM3Context::new() let _ = ctx.update_from_iter(data) diff --git a/crypto/sm3_test.mbt b/crypto/sm3_test.mbt index 0214401..91d6a58 100644 --- a/crypto/sm3_test.mbt +++ b/crypto/sm3_test.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn sm3test(s : String) -> String { @crypto.bytes_to_hex_string(@crypto.sm3(s.to_bytes())) } diff --git a/crypto/utils.mbt b/crypto/utils.mbt index 3431f0c..fb74756 100644 --- a/crypto/utils.mbt +++ b/crypto/utils.mbt @@ -12,13 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Converts a byte array to a hex string, without any prefix like "0x". - +///| Converts a byte array to a hex string, without any prefix like "0x". let hex_digits : FixedArray[String] = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", ] -/// print a sequence of byte in hex representation +///| print a sequence of byte in hex representation pub fn bytes_to_hex_string(input : Bytes) -> String { let mut ret = "" for i = input.length() - 1; i >= 0; i = i - 1 { @@ -32,6 +31,7 @@ pub fn bytes_to_hex_string(input : Bytes) -> String { ret } +///| fn uint_to_hex_string(input : UInt) -> String { let ret = FixedArray::make(8, "0") let mut mut_input = input @@ -42,16 +42,17 @@ fn uint_to_hex_string(input : UInt) -> String { ret.fold(String::op_add, init="") } -/// print a sequence of uint in hex representation +///| print a sequence of uint in hex representation pub fn uints_to_hex_string(input : Iter[UInt]) -> String { input.map(uint_to_hex_string).fold(String::op_add, init="") } +///| fn uint32(x : Byte) -> UInt { x.to_int().reinterpret_as_uint() } -/// convert 4 bytes a byte sequence to a UInt in little endian +///| convert 4 bytes a byte sequence to a UInt in little endian /// - `x` : A byte sequence consisting of 4 or more bytes /// - `i` : An offset. e.g. i = 4 will convert `x[4~7]` to a UInt. fn u8_to_u32le(x : Bytes, i~ : Int = 0) -> UInt { @@ -71,16 +72,15 @@ fn u8_to_u32le(x : Bytes, i~ : Int = 0) -> UInt { // ) // } -/// convert 4 bytes of a byte array to a UInt in big endian -/// - `x` : A byte sequence consisting of 4 or more bytes -/// - `i` : An offset. e.g. i = 4 will convert `x[4~7]` to a UInt. - // fn arr_u8_to_u32be(x : Array[Byte], ~i : Int = 0) -> UInt { // uint32(x[i]).lsl(24) | uint32(x[i + 1]).lsl(16) | uint32(x[i + 2]).lsl(8) | uint32( // x[i + 3], // ) // } +///| convert 4 bytes of a byte array to a UInt in big endian +/// - `x` : A byte sequence consisting of 4 or more bytes +/// - `i` : An offset. e.g. i = 4 will convert `x[4~7]` to a UInt. fn bytes_u8_to_u32be(x : Bytes, i~ : Int = 0) -> UInt { (uint32(x[i]) << 24) | (uint32(x[i + 1]) << 16) | @@ -88,8 +88,7 @@ fn bytes_u8_to_u32be(x : Bytes, i~ : Int = 0) -> UInt { uint32(x[i + 3]) } -/// convert an array of UInt to Bytes in big endian - +///| convert an array of UInt to Bytes in big endian fn arr_u32_to_u8be(x : Iter[UInt], bits : Int) -> Bytes { let temp : Bytes = Bytes::new(bits / 8) x.eachi( @@ -103,17 +102,17 @@ fn arr_u32_to_u8be(x : Iter[UInt], bits : Int) -> Bytes { temp } -/// rotate a Int `x` left by `n` bit(s) - +///| rotate a Int `x` left by `n` bit(s) fn rotate_left(x : Int, n : Int) -> Int { (x << n) | (x.reinterpret_as_uint() >> (32 - n)).reinterpret_as_int() } -/// rotate a UInt `x` left by `n` bit(s) +///| rotate a UInt `x` left by `n` bit(s) fn rotate_left_u(x : UInt, n : Int) -> UInt { (x << n) | (x >> (32 - n)) } +///| fn rotate_right_u(x : UInt, n : Int) -> UInt { (x >> n) | (x << (32 - n)) } diff --git a/fs/fs.mbt b/fs/fs.mbt index 39d0ec8..ed5e503 100644 --- a/fs/fs.mbt +++ b/fs/fs.mbt @@ -12,21 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub(all) type! IOError { NotFound(String) } +///| pub impl Show for IOError with output(self, logger) { logger.write_string(self.to_string()) } +///| fn IOError::to_string(self : IOError) -> String { match self { IOError::NotFound(path) => "`\{path}` does not exist" } } -/// Writes a string to a file. +///| Writes a string to a file. /// /// # Parameters /// - `path`: A `String` representing the file path. @@ -35,7 +38,7 @@ pub fn write_string_to_file(path~ : String, content~ : String) -> Unit { @ffi.write_string_to_file(path, content) } -/// Writes an array of bytes to a file at the specified path. +///| Writes an array of bytes to a file at the specified path. /// /// # Parameters /// @@ -45,7 +48,7 @@ pub fn write_bytes_to_file(path~ : String, content~ : Bytes) -> Unit { @ffi.write_bytes_to_file(path, content) } -/// Checks if a path exists. +///| Checks if a path exists. /// /// # Parameters /// - `path`: A `String` representing the file path. @@ -56,7 +59,7 @@ pub fn path_exists(path~ : String) -> Bool { @ffi.path_exists(path) } -/// Reads the entire contents of a file into a string. +///| Reads the entire contents of a file into a string. /// /// # Parameters /// - `path`: A `String` representing the file path. @@ -68,7 +71,7 @@ pub fn read_file_to_string(path~ : String) -> String! { @ffi.read_file_to_string(path) } -/// Reads the content of a file specified by the given path and returns its +///| Reads the content of a file specified by the given path and returns its /// content as an array of bytes. If the file does not exist, an error is raised. /// /// # Parameters @@ -83,7 +86,7 @@ pub fn read_file_to_bytes(path~ : String) -> Bytes! { @ffi.read_file_to_bytes(path) } -/// Reads the contents of a directory and returns an array of filenames. +///| Reads the contents of a directory and returns an array of filenames. /// /// # Parameters /// @@ -97,7 +100,7 @@ pub fn read_dir(path~ : String) -> Array[String]! { @ffi.read_dir(path) } -/// Creates a directory at the specified path. +///| Creates a directory at the specified path. /// Note: nested directories are not supported for native backend /// /// # Parameters @@ -107,7 +110,7 @@ pub fn create_dir(path~ : String) -> Unit { @ffi.create_dir(path) } -/// Checks if the given path is a directory. +///| Checks if the given path is a directory. /// /// # Parameters /// @@ -121,7 +124,7 @@ pub fn is_dir(path~ : String) -> Bool! { @ffi.is_dir(path) } -/// Check if the given path points to a file. +///| Check if the given path points to a file. /// /// # Parameters /// @@ -135,7 +138,7 @@ pub fn is_file(path~ : String) -> Bool! { @ffi.is_file(path) } -/// Removes a directory at the specified path. +///| Removes a directory at the specified path. /// /// # Parameters /// @@ -145,7 +148,7 @@ pub fn remove_dir(path~ : String) -> Unit! { @ffi.remove_dir(path) } -/// Removes a file at the specified path. +///| Removes a file at the specified path. /// /// # Parameters /// diff --git a/fs/internal/ffi/fs_js.mbt b/fs/internal/ffi/fs_js.mbt index 1da54a4..c5bf31b 100644 --- a/fs/internal/ffi/fs_js.mbt +++ b/fs/internal/ffi/fs_js.mbt @@ -12,10 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub fn read_file_to_string(path : String) -> String { read_file_to_string_internal(path) } +///| extern "js" fn read_file_to_string_internal(path : String) -> String = #| function(path) { #| fs = require('fs'); @@ -23,10 +25,12 @@ extern "js" fn read_file_to_string_internal(path : String) -> String = #| return content; #| } +///| pub fn read_file_to_bytes(path : String) -> Bytes { Bytes::from_iter(read_file_to_bytes_internal(path).iter()) } +///| extern "js" fn read_file_to_bytes_internal(path : String) -> FixedArray[Byte] = #| function(path) { #| fs = require('fs'); @@ -34,20 +38,24 @@ extern "js" fn read_file_to_bytes_internal(path : String) -> FixedArray[Byte] = #| return content; #| } +///| pub fn write_string_to_file(path : String, content : String) -> Unit { write_string_to_file_internal(path, content) } +///| extern "js" fn write_string_to_file_internal(path : String, content : String) = #| function(path, content) { #| fs = require('fs'); #| fs.writeFileSync(path, content, 'utf8'); #| } +///| pub fn write_bytes_to_file(path : String, content : Bytes) -> Unit { write_bytes_to_file_internal(path, FixedArray::from_iter(content.iter())) } +///| extern "js" fn write_bytes_to_file_internal( path : String, content : FixedArray[Byte] @@ -57,70 +65,84 @@ extern "js" fn write_bytes_to_file_internal( #| fs.writeFileSync(path, Buffer.from(content)); #| } +///| pub fn path_exists(path : String) -> Bool { path_exists_internal(path) } +///| extern "js" fn path_exists_internal(path : String) -> Bool = #| function(path) { #| fs = require('fs'); #| return fs.existsSync(path); #| } +///| pub fn read_dir(path : String) -> Array[String] { Array::from_fixed_array(read_dir_internal(path)) } +///| extern "js" fn read_dir_internal(path : String) -> FixedArray[String] = #| function(path) { #| fs = require('fs'); #| return fs.readdirSync(path); #| } +///| pub fn create_dir(path : String) -> Unit { create_dir_internal(path) } +///| extern "js" fn create_dir_internal(path : String) -> Unit = #| function(path) { #| fs = require('fs'); #| fs.mkdirSync(path, { recursive: true }); #| } +///| pub fn is_dir(path : String) -> Bool { is_dir_internal(path) } +///| extern "js" fn is_dir_internal(path : String) -> Bool = #| function(path) { #| fs = require('fs'); #| return fs.statSync(path).isDirectory(); #| } +///| pub fn is_file(path : String) -> Bool { is_file_internal(path) } +///| extern "js" fn is_file_internal(path : String) -> Bool = #| function(path) { #| fs = require('fs'); #| return fs.statSync(path).isFile(); #| } +///| pub fn remove_dir(path : String) -> Unit { remove_dir_internal(path) } +///| extern "js" fn remove_dir_internal(path : String) -> Unit = #| function(path) { #| fs = require('fs'); #| fs.rmSync(path, { recursive: true }); #| } +///| pub fn remove_file(path : String) -> Unit { remove_file_internal(path) } +///| extern "js" fn remove_file_internal(path : String) -> Unit = #| function(path) { #| fs = require('fs'); diff --git a/fs/internal/ffi/fs_native.mbt b/fs/internal/ffi/fs_native.mbt index f9a253d..914764b 100644 --- a/fs/internal/ffi/fs_native.mbt +++ b/fs/internal/ffi/fs_native.mbt @@ -12,80 +12,101 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub fn read_file_to_string(path : String) -> String { let path_bytes = mbt_string_to_utf8_bytes(path) let res = read_file_to_bytes_ffi(path_bytes) utf8_bytes_to_mbt_string(res) } +///| pub fn read_file_to_bytes(path : String) -> Bytes { let path_bytes = mbt_string_to_utf8_bytes(path) read_file_to_bytes_ffi(path_bytes) } +///| extern "C" fn read_file_to_bytes_ffi(path : Bytes) -> Bytes = "read_file_to_bytes" +///| pub fn write_string_to_file(path : String, content : String) -> Unit { let path_bytes = mbt_string_to_utf8_bytes(path) let content_bytes = mbt_string_to_utf8_bytes(content) write_bytes_to_file_ffi(path_bytes, content_bytes) } +///| pub fn write_bytes_to_file(path : String, content : Bytes) -> Unit { let path = mbt_string_to_utf8_bytes(path) write_bytes_to_file_ffi(path, content) } +///| extern "C" fn write_bytes_to_file_ffi(path : Bytes, content : Bytes) = "write_bytes_to_file" +///| pub fn path_exists(path : String) -> Bool { path_exists_ffi(mbt_string_to_utf8_bytes(path)) == 0 } +///| extern "C" fn path_exists_ffi(path : Bytes) -> Int = "path_exists" +///| pub fn read_dir(path : String) -> Array[String] { let path_bytes = mbt_string_to_utf8_bytes(path) let res = read_dir_ffi(path_bytes).map(utf8_bytes_to_mbt_string) Array::from_fixed_array(res) } +///| extern "C" fn read_dir_ffi(path : Bytes) -> FixedArray[Bytes] = "read_dir" +///| pub fn create_dir(path : String) -> Unit { let path_bytes = mbt_string_to_utf8_bytes(path) create_dir_ffi(path_bytes) } +///| extern "C" fn create_dir_ffi(path : Bytes) = "create_dir" +///| pub fn is_dir(path : String) -> Bool { let path_bytes = mbt_string_to_utf8_bytes(path) is_dir_ffi(path_bytes) == 0 } +///| extern "C" fn is_dir_ffi(path : Bytes) -> Int = "is_dir" +///| pub fn is_file(path : String) -> Bool { let path_bytes = mbt_string_to_utf8_bytes(path) is_file_ffi(path_bytes) == 0 } +///| extern "C" fn is_file_ffi(path : Bytes) -> Int = "is_file" +///| pub fn remove_dir(path : String) -> Unit { remove_dir_ffi(mbt_string_to_utf8_bytes(path)) } +///| extern "C" fn remove_dir_ffi(path : Bytes) = "remove_dir" +///| pub fn remove_file(path : String) -> Unit { let path_bytes = mbt_string_to_utf8_bytes(path) remove_file_ffi(path_bytes) } +///| extern "C" fn remove_file_ffi(path : Bytes) = "remove_file" +///| fn mbt_string_to_utf8_bytes(str : String) -> Bytes { let res : Array[Byte] = [] let len = str.length() @@ -121,6 +142,7 @@ fn mbt_string_to_utf8_bytes(str : String) -> Bytes { Bytes::from_array(res) } +///| fn utf8_bytes_to_mbt_string(bytes : Bytes) -> String { let res : Array[Char] = [] let len = bytes.length() diff --git a/fs/internal/ffi/fs_wasm.mbt b/fs/internal/ffi/fs_wasm.mbt index 4acb26e..8321982 100644 --- a/fs/internal/ffi/fs_wasm.mbt +++ b/fs/internal/ffi/fs_wasm.mbt @@ -12,90 +12,115 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| typealias XExternString = @ffi.XExternString +///| typealias XExternByteArray = @ffi.XExternByteArray +///| typealias XExternStringArray = @ffi.XExternStringArray +///| pub fn read_file_to_string(path : String) -> String { let path = @ffi.string_to_extern(path) let content = read_file_to_string_ffi(path) @ffi.string_from_extern(content) } +///| fn read_file_to_string_ffi(path : XExternString) -> XExternString = "__moonbit_fs_unstable" "read_file_to_string" +///| pub fn read_file_to_bytes(path : String) -> Bytes { let path = @ffi.string_to_extern(path) let content = read_file_to_bytes_ffi(path) @ffi.byte_array_from_extern(content) } +///| fn read_file_to_bytes_ffi(path : XExternString) -> XExternByteArray = "__moonbit_fs_unstable" "read_file_to_bytes" +///| pub fn write_string_to_file(path : String, content : String) -> Unit { let path = @ffi.string_to_extern(path) let content = @ffi.string_to_extern(content) write_string_to_file_ffi(path, content) } +///| fn write_string_to_file_ffi(path : XExternString, content : XExternString) = "__moonbit_fs_unstable" "write_string_to_file" +///| pub fn write_bytes_to_file(path : String, content : Bytes) -> Unit { let path = @ffi.string_to_extern(path) let content = @ffi.byte_array_to_extern(content) write_bytes_to_file_ffi(path, content) } +///| fn write_bytes_to_file_ffi(path : XExternString, content : XExternByteArray) = "__moonbit_fs_unstable" "write_bytes_to_file" +///| pub fn path_exists(path : String) -> Bool { let path = @ffi.string_to_extern(path) path_exists_ffi(path) } +///| fn path_exists_ffi(path : XExternString) -> Bool = "__moonbit_fs_unstable" "path_exists" +///| pub fn read_dir(path : String) -> Array[String] { let path = @ffi.string_to_extern(path) let dirs = read_dir_ffi(path) @ffi.string_array_from_extern(dirs) } +///| fn read_dir_ffi(path : XExternString) -> XExternStringArray = "__moonbit_fs_unstable" "read_dir" +///| pub fn create_dir(path : String) -> Unit { let path = @ffi.string_to_extern(path) create_dir_ffi(path) } +///| fn create_dir_ffi(path : XExternString) = "__moonbit_fs_unstable" "create_dir" +///| pub fn is_dir(path : String) -> Bool { let path = @ffi.string_to_extern(path) is_dir_ffi(path) } +///| fn is_dir_ffi(path : XExternString) -> Bool = "__moonbit_fs_unstable" "is_dir" +///| pub fn is_file(path : String) -> Bool { let path = @ffi.string_to_extern(path) is_file_ffi(path) } +///| fn is_file_ffi(path : XExternString) -> Bool = "__moonbit_fs_unstable" "is_file" +///| pub fn remove_dir(path : String) -> Unit { let path = @ffi.string_to_extern(path) remove_dir_ffi(path) } +///| fn remove_dir_ffi(path : XExternString) = "__moonbit_fs_unstable" "remove_dir" +///| pub fn remove_file(path : String) -> Unit { let path = @ffi.string_to_extern(path) remove_file_ffi(path) } +///| fn remove_file_ffi(path : XExternString) = "__moonbit_fs_unstable" "remove_file" diff --git a/internal/ffi/byte_array_wasm.mbt b/internal/ffi/byte_array_wasm.mbt index fa93fcb..28e2b2e 100644 --- a/internal/ffi/byte_array_wasm.mbt +++ b/internal/ffi/byte_array_wasm.mbt @@ -12,26 +12,36 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub(all) type XByteArrayCreateHandle +///| pub(all) type XByteArrayReadHandle +///| pub(all) type XExternByteArray +///| fn begin_read_byte_array(s : XExternByteArray) -> XByteArrayReadHandle = "__moonbit_fs_unstable" "begin_read_byte_array" +///| fn byte_array_read_byte(handle : XByteArrayReadHandle) -> Int = "__moonbit_fs_unstable" "byte_array_read_byte" +///| fn finish_read_byte_array(handle : XByteArrayReadHandle) = "__moonbit_fs_unstable" "finish_read_byte_array" +///| fn begin_create_byte_array() -> XByteArrayCreateHandle = "__moonbit_fs_unstable" "begin_create_byte_array" +///| fn byte_array_append_byte(handle : XByteArrayCreateHandle, ch : Int) = "__moonbit_fs_unstable" "byte_array_append_byte" +///| fn finish_create_byte_array( handle : XByteArrayCreateHandle ) -> XExternByteArray = "__moonbit_fs_unstable" "finish_create_byte_array" +///| pub fn byte_array_to_extern(s : Bytes) -> XExternByteArray { let handle = begin_create_byte_array() for i = 0; i < s.length(); i = i + 1 { @@ -40,6 +50,7 @@ pub fn byte_array_to_extern(s : Bytes) -> XExternByteArray { finish_create_byte_array(handle) } +///| pub fn byte_array_from_extern(e : XExternByteArray) -> Bytes { let buf = Array::new() let handle = begin_read_byte_array(e) diff --git a/internal/ffi/dir_wasm.mbt b/internal/ffi/dir_wasm.mbt index db434b7..5273652 100644 --- a/internal/ffi/dir_wasm.mbt +++ b/internal/ffi/dir_wasm.mbt @@ -12,16 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub(all) type XStringArrayReadHandle +///| pub(all) type XExternStringArray +///| fn begin_read_string_array(sa : XExternStringArray) -> XStringArrayReadHandle = "__moonbit_fs_unstable" "begin_read_string_array" +///| fn string_array_read_string(handle : XStringArrayReadHandle) -> XExternString = "__moonbit_fs_unstable" "string_array_read_string" +///| fn finish_read_string_array(handle : XStringArrayReadHandle) = "__moonbit_fs_unstable" "finish_read_string_array" +///| pub fn string_array_from_extern(e : XExternStringArray) -> Array[String] { let buf = Array::new() let handle = begin_read_string_array(e) diff --git a/internal/ffi/string_wasm.mbt b/internal/ffi/string_wasm.mbt index 54d2daa..2d15a70 100644 --- a/internal/ffi/string_wasm.mbt +++ b/internal/ffi/string_wasm.mbt @@ -12,18 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub(all) type XStringCreateHandle +///| pub(all) type XStringReadHandle +///| pub(all) type XExternString +///| fn begin_create_string() -> XStringCreateHandle = "__moonbit_fs_unstable" "begin_create_string" +///| fn string_append_char(handle : XStringCreateHandle, ch : Char) = "__moonbit_fs_unstable" "string_append_char" +///| fn finish_create_string(handle : XStringCreateHandle) -> XExternString = "__moonbit_fs_unstable" "finish_create_string" +///| pub fn string_to_extern(s : String) -> XExternString { let handle = begin_create_string() for i = 0; i < s.length(); i = i + 1 { @@ -32,14 +39,17 @@ pub fn string_to_extern(s : String) -> XExternString { finish_create_string(handle) } +///| fn begin_read_string(s : XExternString) -> XStringReadHandle = "__moonbit_fs_unstable" "begin_read_string" -/// Read one char from the string, returns -1 if the end of the string is reached. +///| Read one char from the string, returns -1 if the end of the string is reached. /// The number returned is the unicode codepoint of the character. fn string_read_char(handle : XStringReadHandle) -> Int = "__moonbit_fs_unstable" "string_read_char" +///| fn finish_read_string(handle : XStringReadHandle) = "__moonbit_fs_unstable" "finish_read_string" +///| pub fn string_from_extern(e : XExternString) -> String { let buf = StringBuilder::new() let handle = begin_read_string(e) diff --git a/json5/internal_types.mbt b/json5/internal_types.mbt index 6fda482..90cc467 100644 --- a/json5/internal_types.mbt +++ b/json5/internal_types.mbt @@ -12,22 +12,27 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| priv struct ParseContext { mut offset : Int input : String end_offset : Int } +///| fn ParseContext::make(input : String) -> ParseContext { { offset: 0, input, end_offset: input.length() } } +///| priv type CharClass Array[(Char, Char)] +///| fn CharClass::of(array : Array[(Char, Char)]) -> CharClass { CharClass(array) } +///| fn CharClass::contains(self : CharClass, c : Char) -> Bool { for left = 0, right = self._.length(); left < right; { let middle = (left + right) / 2 @@ -44,6 +49,7 @@ fn CharClass::contains(self : CharClass, c : Char) -> Bool { } } +///| priv enum Token { Null True @@ -58,18 +64,22 @@ priv enum Token { Colon } derive(Eq, Show) +///| priv struct StringBuilder { mut buffer : String } +///| fn StringBuilder::make() -> StringBuilder { { buffer: "" } } +///| fn add_string(self : StringBuilder, s : String) -> Unit { self.buffer = self.buffer + s } +///| fn add_substring( self : StringBuilder, s : String, @@ -79,10 +89,12 @@ fn add_substring( self.buffer = self.buffer + s.substring(start~, end~) } +///| fn add_char(self : StringBuilder, c : Char) -> Unit { self.buffer = self.buffer + c.to_string() } +///| fn to_string(self : StringBuilder) -> String { self.buffer } diff --git a/json5/json5.mbti b/json5/json5.mbti index 397aebc..a33a00b 100644 --- a/json5/json5.mbti +++ b/json5/json5.mbti @@ -16,18 +16,12 @@ pub(all) enum ParseErrorData { InvalidNumber(Position, String) InvalidIdentEscape(Position) } -impl ParseErrorData { - op_equal(Self, Self) -> Bool -} impl Eq for ParseErrorData pub(all) struct Position { line : Int column : Int } -impl Position { - op_equal(Self, Self) -> Bool -} impl Eq for Position impl Show for Position diff --git a/json5/lex_main.mbt b/json5/lex_main.mbt index 4bf221d..3569143 100644 --- a/json5/lex_main.mbt +++ b/json5/lex_main.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn lex_value( ctx : ParseContext, allow_rbracket~ : Bool = false diff --git a/json5/lex_misc.mbt b/json5/lex_misc.mbt index 5497eb8..4611eb2 100644 --- a/json5/lex_misc.mbt +++ b/json5/lex_misc.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn read_char(ctx : ParseContext) -> Char? { if ctx.offset < ctx.end_offset { let c = ctx.input[ctx.offset] @@ -33,6 +34,7 @@ fn read_char(ctx : ParseContext) -> Char? { } } +///| fn lex_skip_whitespace(ctx : ParseContext) -> Unit!ParseError { for { match read_char(ctx) { @@ -53,6 +55,7 @@ fn lex_skip_whitespace(ctx : ParseContext) -> Unit!ParseError { } } +///| fn lex_after_array_value(ctx : ParseContext) -> Token!ParseError { lex_skip_whitespace!(ctx) match read_char(ctx) { @@ -63,6 +66,7 @@ fn lex_after_array_value(ctx : ParseContext) -> Token!ParseError { } } +///| fn lex_after_property_name(ctx : ParseContext) -> Token!ParseError { lex_skip_whitespace!(ctx) match read_char(ctx) { @@ -72,6 +76,7 @@ fn lex_after_property_name(ctx : ParseContext) -> Token!ParseError { } } +///| fn lex_after_object_value(ctx : ParseContext) -> Token!ParseError { lex_skip_whitespace!(ctx) match read_char(ctx) { @@ -82,6 +87,7 @@ fn lex_after_object_value(ctx : ParseContext) -> Token!ParseError { } } +///| fn lex_assert_char(ctx : ParseContext, c : Char) -> Unit!ParseError { match read_char(ctx) { Some(c2) => if c == c2 { () } else { invalid_char!(ctx, shift=-1) } @@ -89,6 +95,7 @@ fn lex_assert_char(ctx : ParseContext, c : Char) -> Unit!ParseError { } } +///| fn lex_infinity(ctx : ParseContext) -> Unit!ParseError { lex_assert_char!(ctx, 'n') lex_assert_char!(ctx, 'f') @@ -99,6 +106,7 @@ fn lex_infinity(ctx : ParseContext) -> Unit!ParseError { lex_assert_char!(ctx, 'y') } +///| fn lex_comment(ctx : ParseContext) -> Unit!ParseError { match read_char(ctx) { Some('/') => diff --git a/json5/lex_number.mbt b/json5/lex_number.mbt index cb60981..749a35a 100644 --- a/json5/lex_number.mbt +++ b/json5/lex_number.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn lex_decimal_integer(ctx : ParseContext, start~ : Int) -> Double!ParseError { for { match read_char(ctx) { @@ -29,6 +30,7 @@ fn lex_decimal_integer(ctx : ParseContext, start~ : Int) -> Double!ParseError { } } +///| fn lex_decimal_point_leading( ctx : ParseContext, start~ : Int @@ -45,6 +47,7 @@ fn lex_decimal_point_leading( } } +///| fn lex_decimal_point(ctx : ParseContext, start~ : Int) -> Double!ParseError { match read_char(ctx) { Some('e' | 'E') => return lex_decimal_exponent!(ctx, start~) @@ -59,6 +62,7 @@ fn lex_decimal_point(ctx : ParseContext, start~ : Int) -> Double!ParseError { } } +///| fn lex_decimal_fraction(ctx : ParseContext, start~ : Int) -> Double!ParseError { for { match read_char(ctx) { @@ -75,6 +79,7 @@ fn lex_decimal_fraction(ctx : ParseContext, start~ : Int) -> Double!ParseError { } } +///| fn lex_decimal_exponent(ctx : ParseContext, start~ : Int) -> Double!ParseError { match read_char(ctx) { Some('+') | Some('-') => return lex_decimal_exponent_sign!(ctx, start~) @@ -89,6 +94,7 @@ fn lex_decimal_exponent(ctx : ParseContext, start~ : Int) -> Double!ParseError { } } +///| fn lex_decimal_exponent_sign( ctx : ParseContext, start~ : Int @@ -105,6 +111,7 @@ fn lex_decimal_exponent_sign( } } +///| fn lex_decimal_exponent_integer( ctx : ParseContext, start~ : Int @@ -123,6 +130,7 @@ fn lex_decimal_exponent_integer( } } +///| fn lex_zero(ctx : ParseContext, neg~ : Bool, start~ : Int) -> Double!ParseError { match read_char(ctx) { Some('.') => return lex_decimal_point!(ctx, start~) @@ -140,6 +148,7 @@ fn lex_zero(ctx : ParseContext, neg~ : Bool, start~ : Int) -> Double!ParseError } } +///| fn lex_hexadecimal(ctx : ParseContext, neg~ : Bool) -> Double!ParseError { match read_char(ctx) { Some(c) => { @@ -156,6 +165,7 @@ fn lex_hexadecimal(ctx : ParseContext, neg~ : Bool) -> Double!ParseError { } } +///| fn lex_hexadecimal_integer(ctx : ParseContext, n : Int) -> Double { for n = n.to_double() { match read_char(ctx) { @@ -173,6 +183,7 @@ fn lex_hexadecimal_integer(ctx : ParseContext, n : Int) -> Double { } } +///| fn lex_number_end( ctx : ParseContext, start : Int, diff --git a/json5/lex_prop.mbt b/json5/lex_prop.mbt index faf9bba..ac77984 100644 --- a/json5/lex_prop.mbt +++ b/json5/lex_prop.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn lex_property_name(ctx : ParseContext) -> Token!ParseError { lex_skip_whitespace!(ctx) match read_char(ctx) { @@ -56,6 +57,7 @@ fn lex_property_name(ctx : ParseContext) -> Token!ParseError { } } +///| fn lex_ident( ctx : ParseContext, start : Int, diff --git a/json5/lex_string.mbt b/json5/lex_string.mbt index f6bfe49..2f46652 100644 --- a/json5/lex_string.mbt +++ b/json5/lex_string.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn lex_string(ctx : ParseContext, quote : Char) -> String!ParseError { let buf = StringBuilder::make() let mut start = ctx.offset @@ -78,6 +79,7 @@ fn lex_string(ctx : ParseContext, quote : Char) -> String!ParseError { buf.to_string() } +///| fn lex_hex_digits(ctx : ParseContext, n : Int) -> Int!ParseError { let mut r = 0 for i = 0; i < n; i = i + 1 { diff --git a/json5/parse.mbt b/json5/parse.mbt index aa3bd5f..3a8b9d1 100644 --- a/json5/parse.mbt +++ b/json5/parse.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub fn parse(input : String) -> @json.JsonValue!ParseError { let ctx = ParseContext::make(input) let val = parse_value!(ctx) @@ -23,11 +24,13 @@ pub fn parse(input : String) -> @json.JsonValue!ParseError { } } +///| fn parse_value(ctx : ParseContext) -> @json.JsonValue!ParseError { let tok = lex_value!(ctx) parse_value2!(ctx, tok) } +///| fn parse_value2(ctx : ParseContext, tok : Token) -> @json.JsonValue!ParseError { match tok { Null => Null @@ -41,6 +44,7 @@ fn parse_value2(ctx : ParseContext, tok : Token) -> @json.JsonValue!ParseError { } } +///| fn parse_object(ctx : ParseContext) -> @json.JsonValue!ParseError { let map = Map::new() for { @@ -69,6 +73,7 @@ fn parse_object(ctx : ParseContext) -> @json.JsonValue!ParseError { Object(map) } +///| fn parse_array(ctx : ParseContext) -> @json.JsonValue!ParseError { let vec = [] for { diff --git a/json5/parse_test.mbt b/json5/parse_test.mbt index fb3d5f0..ff82690 100644 --- a/json5/parse_test.mbt +++ b/json5/parse_test.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn test_parse(input : String, loc~ : SourceLoc = _) -> @json.JsonValue!Error { let v = @json5.parse?(input) match v { diff --git a/json5/types.mbt b/json5/types.mbt index e9d28b1..e378a7a 100644 --- a/json5/types.mbt +++ b/json5/types.mbt @@ -12,11 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub(all) struct Position { line : Int // 1-based column : Int // 0-based } derive(Eq, Show) +///| pub(all) enum ParseErrorData { InvalidChar(Position, Char) InvalidEof @@ -24,12 +26,15 @@ pub(all) enum ParseErrorData { InvalidIdentEscape(Position) } derive(Eq) +///| pub(all) type! ParseError ParseErrorData +///| fn parse_error[X](data : ParseErrorData) -> X!ParseError { raise ParseError(data) } +///| pub fn ParseError::to_string(self : ParseError) -> String { match self { ParseError(InvalidChar({ line, column }, c)) => @@ -42,6 +47,7 @@ pub fn ParseError::to_string(self : ParseError) -> String { } } +///| pub fn ParseError::output(self : ParseError, logger : Logger) -> Unit { logger.write_string(ParseError::to_string(self)) } diff --git a/json5/unicode_gen.mbt b/json5/unicode_gen.mbt index a08eb8a..bfab9e1 100644 --- a/json5/unicode_gen.mbt +++ b/json5/unicode_gen.mbt @@ -13,6 +13,7 @@ // limitations under the License. // This is a generated file. Do not edit. +///| let non_ascii_whitespace : CharClass = CharClass::of( [ ('\u00A0', '\u00A0'), @@ -26,6 +27,7 @@ let non_ascii_whitespace : CharClass = CharClass::of( ], ) +///| let non_ascii_id_start : CharClass = CharClass::of( [ ('\u00AA', '\u00AA'), @@ -617,6 +619,7 @@ let non_ascii_id_start : CharClass = CharClass::of( ], ) +///| let non_ascii_id_continue : CharClass = CharClass::of( [ ('\u00AA', '\u00AA'), diff --git a/json5/util.mbt b/json5/util.mbt index bb021f8..b4397a0 100644 --- a/json5/util.mbt +++ b/json5/util.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn offset_to_position(input : String, offset : Int) -> Position { let mut line = 1 let mut column = 0 @@ -27,6 +28,7 @@ fn offset_to_position(input : String, offset : Int) -> Position { return Position::{ line, column } } +///| fn invalid_char[X](ctx : ParseContext, shift~ : Int = 0) -> X!ParseError { let offset = ctx.offset + shift parse_error!( @@ -34,6 +36,7 @@ fn invalid_char[X](ctx : ParseContext, shift~ : Int = 0) -> X!ParseError { ) } +///| fn hex_digit_to_int(c : Char) -> Int { if c >= 'A' { (c.to_int() & (32).lnot()) - 'A'.to_int() + 10 diff --git a/num/num.mbt b/num/num.mbt index 1a1282a..614bec5 100644 --- a/num/num.mbt +++ b/num/num.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub(readonly) trait Num { from_int(Int) -> Self op_add(Self, Self) -> Self diff --git a/stack/stack.mbt b/stack/stack.mbt index 6b76afe..fe2e0e4 100644 --- a/stack/stack.mbt +++ b/stack/stack.mbt @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Create an empty stack. +///| Create an empty stack. /// /// # Example /// @@ -29,7 +29,7 @@ test "new" { inspect!(s, content="Stack::[]") } -/// Create a stack based on all elements in list. +///| Create a stack based on all elements in list. /// /// # Example /// @@ -47,7 +47,7 @@ test "from_list" { inspect!(s.len, content="3") } -/// Create a stack based on all elements in array. +///| Create a stack based on all elements in array. /// /// # Example /// @@ -65,7 +65,7 @@ test "from_array" { inspect!(s.len, content="3") } -/// Create a stack based on all elements in array. +///| Create a stack based on all elements in array. /// /// # Example /// @@ -83,6 +83,7 @@ test "of" { inspect!(s.len, content="3") } +///| pub fn to_string[T : Show](self : Stack[T]) -> String { let mut res = "Stack::[" self.elements.eachi( @@ -96,6 +97,7 @@ pub fn to_string[T : Show](self : Stack[T]) -> String { res + "]" } +///| pub fn output[T : Show](self : Stack[T], logger : Logger) -> Unit { logger.write_string(self.to_string()) } @@ -106,7 +108,7 @@ test "to_string" { inspect!(Stack::of([1, 2, 3, 4, 5]), content="Stack::[1, 2, 3, 4, 5]") } -/// Create a stack based on another stack. +///| Create a stack based on another stack. /// /// # Example /// @@ -125,7 +127,7 @@ test "from_stack" { inspect!(s1.elements == s.elements, content="true") } -/// Clear all elements in Stack +///| Clear all elements in Stack /// /// # Example /// @@ -145,7 +147,7 @@ test "clear" { inspect!(s, content="Stack::[]") } -/// Same as the `clear()`, but returns an cleared stack +///| Same as the `clear()`, but returns an cleared stack /// /// # Example /// @@ -163,7 +165,7 @@ test "return_with_clear" { inspect!(s, content="Stack::[]") } -/// Push an element into the stack. +///| Push an element into the stack. /// /// # Example /// @@ -184,7 +186,7 @@ test "push" { inspect!(s.len, content="1") } -/// Push a list into the stack. +///| Push a list into the stack. /// /// # Example /// @@ -204,7 +206,7 @@ test "push_list" { inspect!(s.len, content="3") } -/// Push other stack into the current stack. +///| Push other stack into the current stack. /// /// # Example /// @@ -226,7 +228,7 @@ test "push_stack" { inspect!(s.len == s1.len, content="true") } -/// Push an array into the stack. +///| Push an array into the stack. /// /// # Example /// @@ -246,7 +248,7 @@ test "push_array" { inspect!(s.len, content="3") } -/// Pop an element from the top of the stack. +///| Pop an element from the top of the stack. /// If there are elements in the stack, return `Some (the top element of the stack)`, otherwise return `None`. /// /// # Example @@ -280,7 +282,7 @@ test "pop" { inspect!(s1.len, content="0") } -/// Pop an element from the top of the stack. +///| Pop an element from the top of the stack. /// If there are elements in the stack, return the top element of the stack, otherwise abort. /// /// # Example @@ -311,7 +313,7 @@ test "unsafe_pop" { inspect!(s.len, content="2") } -/// Drop the element at the top of the stack. +///| Drop the element at the top of the stack. /// Like pop, but does not return elements and does nothing if the Stack is empty. /// /// # Example @@ -338,7 +340,7 @@ test "drop" { inspect!(s.len, content="2") } -/// Drop the element at the top of the stack. +///| Drop the element at the top of the stack. /// Like drop, but when the drop is successful, it returns `Ok(())`, and when it fails, it returns `Err(())` /// /// # Example @@ -367,7 +369,7 @@ test "drop_result" { inspect!(s.len, content="2") } -/// Only the top element of the stack is returned and will not be pop or drop. +///| Only the top element of the stack is returned and will not be pop or drop. /// If there are elements in the stack, return `Some (the top element of the stack)`, otherwise return `None`. /// /// # Example @@ -391,7 +393,7 @@ test "peek" { inspect!(s.len, content="3") } -/// Only the top element of the stack is returned and will not be pop or drop. +///| Only the top element of the stack is returned and will not be pop or drop. /// If there are elements in the stack, return the top element of the stack, otherwise abort. /// /// # Example @@ -418,7 +420,7 @@ test "peek_exn" { inspect!(s.len, content="3") } -/// If stack is empty, return true, otherwise return false. +///| If stack is empty, return true, otherwise return false. /// /// # Example /// @@ -436,12 +438,12 @@ test "is_empty" { inspect!(empty.is_empty(), content="true") } -/// Returns the number of elements of the Stack +///| Returns the number of elements of the Stack pub fn length[T](self : Stack[T]) -> Int { self.len } -/// Iterates over the elements of the stack from top to bottom. +///| Iterates over the elements of the stack from top to bottom. /// /// # Example /// ``` @@ -470,7 +472,7 @@ test "iter" { inspect!(sub, content="-3") } -/// Folds over the elements of the stack from top to bottom. +///| Folds over the elements of the stack from top to bottom. /// /// # Example /// ``` @@ -488,7 +490,7 @@ test "fold" { inspect!(sum, content="6") } -/// Convert stack to list. +///| Convert stack to list. /// /// # Example /// @@ -503,7 +505,7 @@ test "to_list" { inspect!(Stack::of([3, 2, 1]).to_list(), content="@list.of([3, 2, 1])") } -/// Convert stack to array. +///| Convert stack to array. /// /// # Example /// @@ -518,7 +520,7 @@ test "to_array" { inspect!(Stack::of([3, 2, 1]).to_array(), content="[3, 2, 1]") } -/// Compare two stacks. +///| Compare two stacks. /// /// NOTE: Since the current standard library @immut/list.T lacks the equal or op_equal function, /// this function internally implements the equal function of @immut/list.T. @@ -536,6 +538,7 @@ pub fn equal[T : Eq](self : Stack[T], other : Stack[T]) -> Bool { } } +///| pub fn op_equal[T : Eq](self : Stack[T], other : Stack[T]) -> Bool { self.equal(other) } diff --git a/stack/stack.mbti b/stack/stack.mbti index 7f26907..00c592a 100644 --- a/stack/stack.mbti +++ b/stack/stack.mbti @@ -8,7 +8,6 @@ alias @moonbitlang/core/immut/list as @list type Stack impl Stack { clear[T](Self[T]) -> Unit - default[T : Default]() -> Self[T] drop[T](Self[T]) -> Unit drop_result[T](Self[T]) -> Result[Unit, Unit] each[T](Self[T], (T) -> Unit) -> Unit diff --git a/stack/types.mbt b/stack/types.mbt index 122ea1c..e8af28e 100644 --- a/stack/types.mbt +++ b/stack/types.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| struct Stack[T] { mut elements : @immut/list.T[T] mut len : Int diff --git a/sys/internal/ffi/sys_js.mbt b/sys/internal/ffi/sys_js.mbt index ed1952e..2263d31 100644 --- a/sys/internal/ffi/sys_js.mbt +++ b/sys/internal/ffi/sys_js.mbt @@ -12,15 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub fn get_cli_args() -> Array[String] { get_cli_args_internal() } +///| extern "js" fn get_cli_args_internal() -> Array[String] = #| function() { #| return process.argv; #| } +///| pub fn get_env_vars() -> Map[String, String] { let tmp = get_env_vars_internal() let res = {} @@ -30,6 +33,7 @@ pub fn get_env_vars() -> Map[String, String] { res } +///| extern "js" fn get_env_vars_internal() -> Array[String] = #| function() { #| const env = process.env; @@ -41,6 +45,7 @@ extern "js" fn get_env_vars_internal() -> Array[String] = #| return result; #| } +///| pub extern "js" fn exit(code : Int) -> Unit = #| function(code) { #| process.exit(code); diff --git a/sys/internal/ffi/sys_native.mbt b/sys/internal/ffi/sys_native.mbt index 25b462a..68f2432 100644 --- a/sys/internal/ffi/sys_native.mbt +++ b/sys/internal/ffi/sys_native.mbt @@ -12,14 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub fn get_cli_args() -> Array[String] { // not implement yet panic() } +///| pub fn get_env_vars() -> Map[String, String] { // not implement yet panic() } +///| pub extern "native" fn exit(code : Int) -> Unit = "exit" diff --git a/sys/internal/ffi/sys_wasm.mbt b/sys/internal/ffi/sys_wasm.mbt index e52a34b..f541daa 100644 --- a/sys/internal/ffi/sys_wasm.mbt +++ b/sys/internal/ffi/sys_wasm.mbt @@ -12,15 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| typealias XExternStringArray = @ffi.XExternStringArray +///| pub fn get_cli_args() -> Array[String] { let args = get_cli_args_ffi() @ffi.string_array_from_extern(args) } +///| fn get_cli_args_ffi() -> XExternStringArray = "__moonbit_fs_unstable" "args_get" +///| pub fn get_env_vars() -> Map[String, String] { let env = get_env_vars_ffi() let tmp = @ffi.string_array_from_extern(env) @@ -31,6 +35,8 @@ pub fn get_env_vars() -> Map[String, String] { res } +///| fn get_env_vars_ffi() -> XExternStringArray = "__moonbit_fs_unstable" "env_get_vars" +///| pub fn exit(code : Int) = "__moonbit_sys_unstable" "exit" diff --git a/sys/sys.mbt b/sys/sys.mbt index 593723e..bc06e00 100644 --- a/sys/sys.mbt +++ b/sys/sys.mbt @@ -12,14 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub fn get_cli_args() -> Array[String] { @ffi.get_cli_args() } +///| pub fn get_env_vars() -> Map[String, String] { @ffi.get_env_vars() } +///| pub fn exit(code : Int) -> Unit { @ffi.exit(code) } diff --git a/time/duration.mbt b/time/duration.mbt index 0378a82..d269199 100644 --- a/time/duration.mbt +++ b/time/duration.mbt @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// An amount of time with nanosecond precision. +///| An amount of time with nanosecond precision. struct Duration { secs : Int64 nanos : Int } derive(Eq, Compare) -/// Creates a Duration from hours, minutes, seconds and nanoseconds. +///| Creates a Duration from hours, minutes, seconds and nanoseconds. pub fn Duration::of( hours~ : Int64 = 0L, minutes~ : Int64 = 0L, @@ -36,6 +36,7 @@ pub fn Duration::of( { secs, nanos } } +///| fn create(secs : Int64, nanos : Int) -> Duration!Error { if nanos < min_nanosecond || nanos > max_nanosecond { fail!(invalid_duration_err) @@ -43,12 +44,12 @@ fn create(secs : Int64, nanos : Int) -> Duration!Error { { secs, nanos } } -/// Returns a zero length duration. +///| Returns a zero length duration. pub fn Duration::zero() -> Duration { { secs: 0L, nanos: 0 } } -/// Parses a ISO 8601 format string like `PT[n]H[n]M[n].[n]S`. +///| Parses a ISO 8601 format string like `PT[n]H[n]M[n].[n]S`. pub fn Duration::from_string(str : String) -> Duration!Error { // TODO: better parsing impl if str.substring(end=2) != "PT" { @@ -97,7 +98,7 @@ pub fn Duration::from_string(str : String) -> Duration!Error { Duration::of!(hours~, minutes~, seconds~, nanoseconds~) } -/// Returns a string representation of this duration using ISO 8601 representation. +///| Returns a string representation of this duration using ISO 8601 representation. pub fn to_string(self : Duration) -> String { if self.is_zero() { return "PT0S" @@ -137,31 +138,32 @@ pub fn to_string(self : Duration) -> String { buf.to_string() } +///| pub impl Show for Duration with output(self : Duration, logger : Logger) -> Unit { logger.write_string(self.to_string()) } -/// Returns the number of seconds in this duration. +///| Returns the number of seconds in this duration. pub fn seconds(self : Duration) -> Int64 { self.secs } -/// Returns the number of nanoseconds in this duration. +///| Returns the number of nanoseconds in this duration. pub fn nanoseconds(self : Duration) -> Int { self.nanos } -/// Checks if this duration is zero length. +///| Checks if this duration is zero length. pub fn is_zero(self : Duration) -> Bool { self.secs == 0L && self.nanos == 0 } -/// Checks if this duration is negative. +///| Checks if this duration is negative. pub fn is_neg(self : Duration) -> Bool { self.secs < 0L } -/// Adds specified hours to this duration, and returns a new duration. +///| Adds specified hours to this duration, and returns a new duration. pub fn add_hours(self : Duration, hours : Int64) -> Duration!Error { if hours == 0L { return self @@ -173,7 +175,7 @@ pub fn add_hours(self : Duration, hours : Int64) -> Duration!Error { { ..self, secs, } } -/// Adds specified minutes to this duration, and returns a new duration. +///| Adds specified minutes to this duration, and returns a new duration. pub fn add_minutes(self : Duration, minutes : Int64) -> Duration!Error { if minutes == 0L { return self @@ -185,7 +187,7 @@ pub fn add_minutes(self : Duration, minutes : Int64) -> Duration!Error { { ..self, secs, } } -/// Adds specified seconds to this duration, and returns a new duration. +///| Adds specified seconds to this duration, and returns a new duration. pub fn add_seconds(self : Duration, seconds : Int64) -> Duration!Error { if seconds == 0L { return self @@ -194,7 +196,7 @@ pub fn add_seconds(self : Duration, seconds : Int64) -> Duration!Error { { ..self, secs, } } -/// Adds specified nanoseconds to this duration, and returns a new duration. +///| Adds specified nanoseconds to this duration, and returns a new duration. pub fn add_nanoseconds(self : Duration, nanoseconds : Int64) -> Duration!Error { if nanoseconds == 0L { return self @@ -207,7 +209,7 @@ pub fn add_nanoseconds(self : Duration, nanoseconds : Int64) -> Duration!Error { Duration::of!(seconds~, nanoseconds~) } -/// Adds other duration to this duration, and returns a new duration. +///| Adds other duration to this duration, and returns a new duration. pub fn add_duration(self : Duration, other : Duration) -> Duration!Error { if other.is_zero() { return self @@ -223,11 +225,12 @@ pub fn add_duration(self : Duration, other : Duration) -> Duration!Error { create!(secs, nanos.to_int()) } +///| pub fn op_add(self : Duration, other : Duration) -> Duration!Error { self.add_duration!(other) } -/// Returns a new duration with the specified amount of seconds. +///| Returns a new duration with the specified amount of seconds. pub fn with_seconds(self : Duration, seconds : Int64) -> Duration { if seconds == self.secs { return self @@ -235,7 +238,7 @@ pub fn with_seconds(self : Duration, seconds : Int64) -> Duration { { secs: seconds, nanos: self.nanos } } -/// Returns a new duration with the specified nanosecond of second. +///| Returns a new duration with the specified nanosecond of second. pub fn with_nanoseconds(self : Duration, nanoseconds : Int) -> Duration!Error { if nanoseconds == self.nanos { return self @@ -243,7 +246,7 @@ pub fn with_nanoseconds(self : Duration, nanoseconds : Int) -> Duration!Error { create!(self.secs, nanoseconds) } -/// Converts this duration to the total length in nanoseconds. +///| Converts this duration to the total length in nanoseconds. pub fn to_nanoseconds(self : Duration) -> Int64 { self.secs * nanoseconds_per_second + self.nanos.to_int64() } diff --git a/time/errors.mbt b/time/errors.mbt index 6e21f20..bfe6719 100644 --- a/time/errors.mbt +++ b/time/errors.mbt @@ -12,14 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| let invalid_time_err = "Invalid time" +///| let invalid_date_err = "Invalid date" +///| let invalid_date_time_err = "Invalid date time" +///| let invalid_period_err = "Invalid period" +///| let invalid_duration_err = "Invalid duration" +///| let invalid_offset_err = "Invalid offset" diff --git a/time/period.mbt b/time/period.mbt index 209e0d8..e91fe25 100644 --- a/time/period.mbt +++ b/time/period.mbt @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// An amount of time representing by years, months and days in the ISO-8601 calendar system. +///| An amount of time representing by years, months and days in the ISO-8601 calendar system. struct Period { years : Int months : Int days : Int } derive(Eq, Compare) -/// Creates a Period from years, months, and days. +///| Creates a Period from years, months, and days. pub fn Period::of( years~ : Int = 0, months~ : Int = 0, @@ -28,12 +28,12 @@ pub fn Period::of( { years, months, days } } -/// Returns a zero length period. +///| Returns a zero length period. pub fn Period::zero() -> Period { { years: 0, months: 0, days: 0 } } -/// Parses a ISO 8601 format string like `P[n]Y[n]M[n]D`. +///| Parses a ISO 8601 format string like `P[n]Y[n]M[n]D`. pub fn Period::from_string(str : String) -> Period!Error { // TODO: better parsing impl if str[0] != 'P' { @@ -66,7 +66,7 @@ pub fn Period::from_string(str : String) -> Period!Error { Period::of(years~, months~, days~) } -/// Returns a string representation of this period using ISO 8601 representation. +///| Returns a string representation of this period using ISO 8601 representation. pub fn to_string(self : Period) -> String { if self.is_zero() { return "P0D" @@ -88,26 +88,27 @@ pub fn to_string(self : Period) -> String { buf.to_string() } +///| pub impl Show for Period with output(self : Period, logger : Logger) { logger.write_string(self.to_string()) } -/// Returns the number of years in this duration. +///| Returns the number of years in this duration. pub fn years(self : Period) -> Int { self.years } -/// Returns the number of months in this duration. +///| Returns the number of months in this duration. pub fn months(self : Period) -> Int { self.months } -/// Returns the number of days in this duration. +///| Returns the number of days in this duration. pub fn days(self : Period) -> Int { self.days } -/// Adds specified years to this period, and returns a new period. +///| Adds specified years to this period, and returns a new period. pub fn add_years(self : Period, years : Int) -> Period!Error { if years == 0 { return self @@ -116,7 +117,7 @@ pub fn add_years(self : Period, years : Int) -> Period!Error { Period::of(years=new_years, months=self.months, days=self.days) } -/// Adds specified weeks to this period, and returns a new period. +///| Adds specified weeks to this period, and returns a new period. pub fn add_weeks(self : Period, weeks : Int) -> Period!Error { if weeks == 0 { return self @@ -125,7 +126,7 @@ pub fn add_weeks(self : Period, weeks : Int) -> Period!Error { Period::of(years=self.years, months=self.months, days=new_days) } -/// Adds specified months to this period, and returns a new period. +///| Adds specified months to this period, and returns a new period. pub fn add_months(self : Period, months : Int) -> Period!Error { if months == 0 { return self @@ -134,7 +135,7 @@ pub fn add_months(self : Period, months : Int) -> Period!Error { Period::of(years=self.years, months=new_months, days=self.days) } -/// Adds specified days to this period, and returns a new period. +///| Adds specified days to this period, and returns a new period. pub fn add_days(self : Period, days : Int) -> Period!Error { if days == 0 { return self @@ -143,7 +144,7 @@ pub fn add_days(self : Period, days : Int) -> Period!Error { Period::of(years=self.years, months=self.months, days=new_days) } -/// Adds other period to this period, and returns a new period. +///| Adds other period to this period, and returns a new period. pub fn add_period(self : Period, other : Period) -> Period!Error { if other.is_zero() { return self @@ -154,15 +155,17 @@ pub fn add_period(self : Period, other : Period) -> Period!Error { .add_days!(other.days()) } +///| pub fn op_add(self : Period, other : Period) -> Period!Error { self.add_period!(other) } +///| pub fn op_sub(self : Period, other : Period) -> Period!Error { self.add_period!(other.negated!()) } -/// Returns a new period with all elements in this period multiplied by the specified value. +///| Returns a new period with all elements in this period multiplied by the specified value. pub fn multiply(self : Period, n : Int) -> Period!Error { if n == 0 { return Period::zero() @@ -176,12 +179,12 @@ pub fn multiply(self : Period, n : Int) -> Period!Error { Period::of(years~, months~, days~) } -/// Returns a new period with all elements in this period negated. +///| Returns a new period with all elements in this period negated. pub fn negated(self : Period) -> Period!Error { self.multiply!(-1) } -/// Returns a new period with the specified amount of years. +///| Returns a new period with the specified amount of years. pub fn with_years(self : Period, years : Int) -> Period { if years == self.years { self @@ -190,7 +193,7 @@ pub fn with_years(self : Period, years : Int) -> Period { } } -/// Returns a new period with the specified amount of months. +///| Returns a new period with the specified amount of months. pub fn with_months(self : Period, months : Int) -> Period { if months == self.months { self @@ -199,7 +202,7 @@ pub fn with_months(self : Period, months : Int) -> Period { } } -/// Returns a new period with the specified amount of days. +///| Returns a new period with the specified amount of days. pub fn with_days(self : Period, days : Int) -> Period { if days == self.days { self @@ -208,17 +211,17 @@ pub fn with_days(self : Period, days : Int) -> Period { } } -/// Checks if this period is zero length. +///| Checks if this period is zero length. pub fn is_zero(self : Period) -> Bool { self.years == 0 && self.months == 0 && self.days == 0 } -/// Checks if this period is negative. +///| Checks if this period is negative. pub fn is_neg(self : Period) -> Bool { self.years < 0 || self.months < 0 || self.days < 0 } -/// Returns the total number of months in this period. +///| Returns the total number of months in this period. pub fn to_total_months(self : Period) -> Int64 { self.years.to_int64() * 12L + self.months.to_int64() } diff --git a/time/plain_date.mbt b/time/plain_date.mbt index b82d243..0010c72 100644 --- a/time/plain_date.mbt +++ b/time/plain_date.mbt @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// A date without a time zone in the ISO 8601 calendar system. +///| A date without a time zone in the ISO 8601 calendar system. struct PlainDate { year : Int month : Int day : Int } -/// Creates a PlainDate from the year, month and day. +///| Creates a PlainDate from the year, month and day. pub fn PlainDate::of(year : Int, month : Int, day : Int) -> PlainDate!Error { if not(validate_ymd(year, month, day)) { fail!(invalid_date_err) @@ -27,7 +27,7 @@ pub fn PlainDate::of(year : Int, month : Int, day : Int) -> PlainDate!Error { PlainDate::{ year, month, day } } -/// Creates a PlainDate from year and ordinal day. +///| Creates a PlainDate from year and ordinal day. pub fn PlainDate::from_year_ord(year : Int, ordinal : Int) -> PlainDate!Error { let valid = validate_year(year) && validate_ordinal(year, ordinal) if not(valid) { @@ -42,7 +42,7 @@ pub fn PlainDate::from_year_ord(year : Int, ordinal : Int) -> PlainDate!Error { PlainDate::{ year, month, day } } -/// Creates a date from the days count since unix epoch. +///| Creates a date from the days count since unix epoch. pub fn PlainDate::from_unix_day(unix_day : Int64) -> PlainDate!Error { let (year, ord) = fixed_days_to_year_ord( unix_day + days_zero_year_to_unix_epoch, @@ -50,13 +50,13 @@ pub fn PlainDate::from_unix_day(unix_day : Int64) -> PlainDate!Error { PlainDate::from_year_ord!(year, ord) } -/// Returns the days count since unix epoch of this date. +///| Returns the days count since unix epoch of this date. pub fn to_unix_day(self : PlainDate) -> Int64 { let days = date_to_fixed_days(self.year, self.month, self.day) days - days_zero_year_to_unix_epoch } -/// Creates a PlainDate from a string, like "2008-08-08". +///| Creates a PlainDate from a string, like "2008-08-08". pub fn PlainDate::from_string(str : String) -> PlainDate!Error { // TODO: better parsing implementation. let mut s = str @@ -85,7 +85,7 @@ pub fn PlainDate::from_string(str : String) -> PlainDate!Error { PlainDate::of!(year, month, day) } -/// Returns a string representing the date. +///| Returns a string representing the date. pub fn to_string(self : PlainDate) -> String { let buf = StringBuilder::new(size_hint=11) if self.year < 0 { @@ -99,14 +99,17 @@ pub fn to_string(self : PlainDate) -> String { buf.to_string() } +///| pub impl Show for PlainDate with output(self : PlainDate, logger : Logger) { logger.write_string(self.to_string()) } +///| pub fn op_equal(self : PlainDate, other : PlainDate) -> Bool { self.compare(other) == 0 } +///| pub fn compare(self : PlainDate, other : PlainDate) -> Int { if self.year > other.year { 1 @@ -125,7 +128,7 @@ pub fn compare(self : PlainDate, other : PlainDate) -> Int { } } -/// Returns the era of this date. +///| Returns the era of this date. pub fn era(self : PlainDate) -> String { if self.year >= 1 { "CE" @@ -134,7 +137,7 @@ pub fn era(self : PlainDate) -> String { } } -/// Returns the year of the era of this date. +///| Returns the year of the era of this date. pub fn era_year(self : PlainDate) -> Int { if self.year <= 0 { self.year.abs() + 1 @@ -143,22 +146,22 @@ pub fn era_year(self : PlainDate) -> Int { } } -/// Returns the number of years relative to a calendar-specific epoch. +///| Returns the number of years relative to a calendar-specific epoch. pub fn year(self : PlainDate) -> Int { self.year } -/// Returns the ordinal number of month in the current year. +///| Returns the ordinal number of month in the current year. pub fn month(self : PlainDate) -> Int { self.month } -/// Returns the day of the month. +///| Returns the day of the month. pub fn day(self : PlainDate) -> Int { self.day } -/// Returns the weekday. +///| Returns the weekday. pub fn weekday(self : PlainDate) -> Weekday { // Zeller's congruence // https://en.wikipedia.org/wiki/Zeller%27s_congruence @@ -176,40 +179,40 @@ pub fn weekday(self : PlainDate) -> Weekday { Weekday::new(week_day).unwrap() } -/// Returns the ordinal day of the year. +///| Returns the ordinal day of the year. pub fn ordinal(self : PlainDate) -> Int { let days = date_to_fixed_days(self.year, self.month, self.day) let (_, ordinal) = fixed_days_to_year_ord(days) ordinal } -/// Returns the number of days in the week. +///| Returns the number of days in the week. pub fn PlainDate::days_in_week(_self : PlainDate) -> Int { 7 } -/// Returns the number of days in the month. +///| Returns the number of days in the month. pub fn days_in_month(self : PlainDate) -> Int { let { year, month, .. } = self calc_days_in_month(year, month) } -/// Returns the number of days in the year. +///| Returns the number of days in the year. pub fn days_in_year(self : PlainDate) -> Int { calc_days_in_year(self.year) } -/// Returns the number of months in the year. +///| Returns the number of months in the year. pub fn PlainDate::months_in_year(_self : PlainDate) -> Int { 12 } -/// Checks if the date is in a leap year. +///| Checks if the date is in a leap year. pub fn in_leap_year(self : PlainDate) -> Bool { check_leap_year(self.year) } -/// Returns a new date with the specified year. +///| Returns a new date with the specified year. pub fn with_year(self : PlainDate, year : Int) -> PlainDate!Error { if self.year == year { return self @@ -222,7 +225,7 @@ pub fn with_year(self : PlainDate, year : Int) -> PlainDate!Error { } } -/// Returns a new date with the specified month. +///| Returns a new date with the specified month. pub fn with_month(self : PlainDate, month : Int) -> PlainDate!Error { if self.month == month { return self @@ -235,7 +238,7 @@ pub fn with_month(self : PlainDate, month : Int) -> PlainDate!Error { } } -/// Returns a new date with the specified day of month. +///| Returns a new date with the specified day of month. pub fn with_day(self : PlainDate, day : Int) -> PlainDate!Error { if self.day == day { return self @@ -248,7 +251,7 @@ pub fn with_day(self : PlainDate, day : Int) -> PlainDate!Error { } } -/// Returns a new date with the specified ordinal day of year. +///| Returns a new date with the specified ordinal day of year. pub fn with_ordinal(self : PlainDate, ordinal : Int) -> PlainDate!Error { if self.ordinal() == ordinal { return self @@ -256,7 +259,7 @@ pub fn with_ordinal(self : PlainDate, ordinal : Int) -> PlainDate!Error { PlainDate::from_year_ord!(self.year, ordinal) } -/// Adds specified years to this date, and returns a new date. +///| Adds specified years to this date, and returns a new date. pub fn add_years(self : PlainDate, years : Int64) -> PlainDate!Error { if years == 0L { return self @@ -270,7 +273,7 @@ pub fn add_years(self : PlainDate, years : Int64) -> PlainDate!Error { } } -/// Adds specified months to this date, and returns a new date. +///| Adds specified months to this date, and returns a new date. pub fn add_months(self : PlainDate, months : Int64) -> PlainDate!Error { if months == 0L { return self @@ -290,7 +293,7 @@ pub fn add_months(self : PlainDate, months : Int64) -> PlainDate!Error { } } -/// Adds specified weeks to this date, and returns a new date. +///| Adds specified weeks to this date, and returns a new date. pub fn add_weeks(self : PlainDate, weeks : Int64) -> PlainDate!Error { if weeks == 0L { return self @@ -299,7 +302,7 @@ pub fn add_weeks(self : PlainDate, weeks : Int64) -> PlainDate!Error { self.add_days!(days_to_add) } -/// Adds specified days to this date, and returns a new date. +///| Adds specified days to this date, and returns a new date. pub fn add_days(self : PlainDate, days : Int64) -> PlainDate!Error { if days == 0L { return self @@ -310,7 +313,7 @@ pub fn add_days(self : PlainDate, days : Int64) -> PlainDate!Error { PlainDate::from_year_ord!(year, ordinal) } -/// Adds a period to this date, and returns a new date. +///| Adds a period to this date, and returns a new date. pub fn add_period(self : PlainDate, period : Period) -> PlainDate!Error { let mut d = self d = d @@ -319,7 +322,7 @@ pub fn add_period(self : PlainDate, period : Period) -> PlainDate!Error { d } -/// Returns the period between this date and another date. +///| Returns the period between this date and another date. pub fn until(self : PlainDate, end : PlainDate) -> Period!Error { let start_months = self.year.to_int64() * 12L + self.month.to_int64() - 1L let end_months = end.year.to_int64() * 12L + end.month.to_int64() - 1L @@ -343,27 +346,38 @@ pub fn until(self : PlainDate, end : PlainDate) -> Period!Error { // * internal helper functions * // ***************************** +///| let min_year = -9999 +///| let max_year = 9999 +///| let min_month = 1 +///| let max_month = 12 +///| let min_day = 1 +///| let max_day = 31 +///| let min_ordinal = 1 +///| let max_ordinal = 366 +///| let days_per_400_years : Int64 = 400L * 365L + 97L +///| let days_zero_year_to_unix_epoch : Int64 = 5L * days_per_400_years - (30L * 365L + 7L) +///| fn create_from_valid(year : Int, month : Int, day : Int) -> PlainDate { let mut d = day let max_day = calc_days_in_month(year, month) @@ -373,10 +387,12 @@ fn create_from_valid(year : Int, month : Int, day : Int) -> PlainDate { PlainDate::{ year, month, day: d } } +///| fn check_leap_year(year : Int) -> Bool { (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 } +///| fn calc_days_in_month(year : Int, month : Int) -> Int { let leap = check_leap_year(year) match month { @@ -386,6 +402,7 @@ fn calc_days_in_month(year : Int, month : Int) -> Int { } } +///| fn calc_days_in_year(year : Int) -> Int { if check_leap_year(year) { 366 @@ -394,6 +411,7 @@ fn calc_days_in_year(year : Int) -> Int { } } +///| fn date_to_fixed_days(year : Int, month : Int, day : Int) -> Int64 { let mut days = 0L // year days @@ -415,6 +433,7 @@ fn date_to_fixed_days(year : Int, month : Int, day : Int) -> Int64 { days } +///| fn fixed_days_to_year_ord(days : Int64) -> (Int, Int) { let mut d0 = days // adjust to positive days for calculation @@ -432,6 +451,7 @@ fn fixed_days_to_year_ord(days : Int64) -> (Int, Int) { (year, ord) } +///| let year_deltas = [ 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, @@ -456,6 +476,7 @@ let year_deltas = [ 97, // 400+1 ] +///| fn cycle_to_year_ord(cycle : Int) -> (Int, Int) { let mut year = cycle / 365 let mut ordinal0 = cycle % 365 @@ -469,22 +490,27 @@ fn cycle_to_year_ord(cycle : Int) -> (Int, Int) { (year, ordinal0 + 1) } +///| fn validate_ymd(year : Int, month : Int, day : Int) -> Bool { validate_year(year) && validate_month(month) && validate_day(year, month, day) } +///| fn validate_year(year : Int) -> Bool { year >= min_year && year <= max_year } +///| fn validate_month(month : Int) -> Bool { month >= min_month && month <= max_month } +///| fn validate_day(year : Int, month : Int, day : Int) -> Bool { day >= min_day && day <= max_day && day <= calc_days_in_month(year, month) } +///| fn validate_ordinal(year : Int, ordinal : Int) -> Bool { ordinal >= min_ordinal && ordinal <= max_ordinal && diff --git a/time/plain_date_time.mbt b/time/plain_date_time.mbt index 7d89ac1..a6bdd60 100644 --- a/time/plain_date_time.mbt +++ b/time/plain_date_time.mbt @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// A datetime without a time zone in the ISO 8601 calendar system. +///| A datetime without a time zone in the ISO 8601 calendar system. struct PlainDateTime { date : PlainDate time : PlainTime } derive(Eq, Compare) -/// Creates a PlainDateTime from the year, month, day, hour, minute, second and nanosecond. +///| Creates a PlainDateTime from the year, month, day, hour, minute, second and nanosecond. pub fn PlainDateTime::of( year : Int, month : Int, @@ -34,7 +34,7 @@ pub fn PlainDateTime::of( } } -/// Creates a PlainDateTime from the elapsed seconds since the unix epoch. +///| Creates a PlainDateTime from the elapsed seconds since the unix epoch. pub fn PlainDateTime::from_unix_second( second : Int64, nanosecond : Int, @@ -53,13 +53,13 @@ pub fn PlainDateTime::from_unix_second( { date, time } } -/// Converts this datetime to the elapsed seconds since the unix epoch. +///| Converts this datetime to the elapsed seconds since the unix epoch. pub fn to_unix_second(self : PlainDateTime) -> Int64 { self.date.to_unix_day() * seconds_per_day + self.time.second_of_day().to_int64() } -/// Creates a PlainTime from a string, like '2008-08-08T20:00:00'. +///| Creates a PlainTime from a string, like '2008-08-08T20:00:00'. pub fn PlainDateTime::from_string(str : String) -> PlainDateTime!Error { // TODO: better parsing implementation let split = split(str, 'T') @@ -71,7 +71,7 @@ pub fn PlainDateTime::from_string(str : String) -> PlainDateTime!Error { { date, time } } -/// Returns a string representing the datetime. +///| Returns a string representing the datetime. pub fn to_string(self : PlainDateTime) -> String { let buf = StringBuilder::new(size_hint=18) buf.write_string(self.date.to_string()) @@ -80,6 +80,7 @@ pub fn to_string(self : PlainDateTime) -> String { buf.to_string() } +///| pub impl Show for PlainDateTime with output( self : PlainDateTime, logger : Logger @@ -87,112 +88,112 @@ pub impl Show for PlainDateTime with output( logger.write_string(self.to_string()) } -/// Returns the era of this datetime. +///| Returns the era of this datetime. pub fn era(self : PlainDateTime) -> String { self.date.era() } -/// Returns the year of era of this datetime. +///| Returns the year of era of this datetime. pub fn era_year(self : PlainDateTime) -> Int { self.date.era_year() } -/// Returns the year of this datetime. +///| Returns the year of this datetime. pub fn year(self : PlainDateTime) -> Int { self.date.year() } -/// Returns the month of this datetime. +///| Returns the month of this datetime. pub fn month(self : PlainDateTime) -> Int { self.date.month() } -/// Returns the day of month of this datetime. +///| Returns the day of month of this datetime. pub fn day(self : PlainDateTime) -> Int { self.date.day() } -/// Returns the weekday of this datetime. +///| Returns the weekday of this datetime. pub fn weekday(self : PlainDateTime) -> Weekday { self.date.weekday() } -/// Returns the ordinal day of year of this datetime. +///| Returns the ordinal day of year of this datetime. pub fn ordinal(self : PlainDateTime) -> Int { self.date.ordinal() } -/// Returns the number of days in a week of this datetime. +///| Returns the number of days in a week of this datetime. pub fn days_in_week(self : PlainDateTime) -> Int { self.date.days_in_week() } -/// Returns the number of days in a month of this datetime. +///| Returns the number of days in a month of this datetime. pub fn days_in_month(self : PlainDateTime) -> Int { self.date.days_in_month() } -/// Returns the number of days in a year of this datetime. +///| Returns the number of days in a year of this datetime. pub fn days_in_year(self : PlainDateTime) -> Int { self.date.days_in_year() } -/// Returns the number of months in a year of this datetime. +///| Returns the number of months in a year of this datetime. pub fn months_in_year(self : PlainDateTime) -> Int { self.date.months_in_year() } -/// Checks if this datetime is in a leap year. +///| Checks if this datetime is in a leap year. pub fn in_leap_year(self : PlainDateTime) -> Bool { self.date.in_leap_year() } -/// Returns the hour of this datetime. +///| Returns the hour of this datetime. pub fn hour(self : PlainDateTime) -> Int { self.time.hour() } -/// Returns the minute of this datetime. +///| Returns the minute of this datetime. pub fn minute(self : PlainDateTime) -> Int { self.time.minute() } -/// Returns the second of this datetime. +///| Returns the second of this datetime. pub fn second(self : PlainDateTime) -> Int { self.time.second() } -/// Returns the nanosecond of this datetime. +///| Returns the nanosecond of this datetime. pub fn nanosecond(self : PlainDateTime) -> Int { self.time.nanosecond() } -/// Adds specified years to this datetime, and returns a new datetime. +///| Adds specified years to this datetime, and returns a new datetime. pub fn add_years(self : PlainDateTime, years : Int64) -> PlainDateTime!Error { { ..self, date: self.date.add_years!(years) } } -/// Adds specified months to this datetime, and returns a new datetime. +///| Adds specified months to this datetime, and returns a new datetime. pub fn add_months(self : PlainDateTime, months : Int64) -> PlainDateTime!Error { { ..self, date: self.date.add_months!(months) } } -/// Adds specified weeks to this datetime, and returns a new datetime. +///| Adds specified weeks to this datetime, and returns a new datetime. pub fn add_weeks(self : PlainDateTime, weeks : Int64) -> PlainDateTime!Error { { ..self, date: self.date.add_weeks!(weeks) } } -/// Adds specified days to this datetime, and returns a new datetime. +///| Adds specified days to this datetime, and returns a new datetime. pub fn add_days(self : PlainDateTime, days : Int64) -> PlainDateTime!Error { { ..self, date: self.date.add_days!(days) } } -/// Adds a period of date to this datetime, and returns a new datetime. +///| Adds a period of date to this datetime, and returns a new datetime. pub fn add_period(self : PlainDateTime, period : Period) -> PlainDateTime!Error { { ..self, date: self.date.add_period!(period) } } -/// Adds specified hours to this datetime, and returns a new datetime. +///| Adds specified hours to this datetime, and returns a new datetime. pub fn add_hours(self : PlainDateTime, hours : Int64) -> PlainDateTime!Error { if hours == 0L { return self @@ -200,7 +201,7 @@ pub fn add_hours(self : PlainDateTime, hours : Int64) -> PlainDateTime!Error { self.overflowing_add!(h=hours) } -/// Adds specified minutes to this datetime, and returns a new datetime. +///| Adds specified minutes to this datetime, and returns a new datetime. pub fn add_minutes( self : PlainDateTime, minutes : Int64 @@ -211,7 +212,7 @@ pub fn add_minutes( self.overflowing_add!(m=minutes) } -/// Adds specified seconds to this datetime, and returns a new datetime. +///| Adds specified seconds to this datetime, and returns a new datetime. pub fn add_seconds( self : PlainDateTime, seconds : Int64 @@ -222,7 +223,7 @@ pub fn add_seconds( self.overflowing_add!(s=seconds) } -/// Adds specified nanoseconds to this datetime, and returns a new datetime. +///| Adds specified nanoseconds to this datetime, and returns a new datetime. pub fn add_nanoseconds( self : PlainDateTime, nanoseconds : Int64 @@ -233,7 +234,7 @@ pub fn add_nanoseconds( self.overflowing_add!(ns=nanoseconds) } -/// Adds a duration of time to this datetime, and returns a new datetime. +///| Adds a duration of time to this datetime, and returns a new datetime. pub fn add_duration( self : PlainDateTime, duration : Duration @@ -244,42 +245,42 @@ pub fn add_duration( self.overflowing_add!(s=duration.secs, ns=duration.nanos.to_int64()) } -/// Returns a new datetime with the specified year. +///| Returns a new datetime with the specified year. pub fn with_year(self : PlainDateTime, year : Int) -> PlainDateTime!Error { { ..self, date: self.date.with_year!(year) } } -/// Returns a new datetime with the specified month. +///| Returns a new datetime with the specified month. pub fn with_month(self : PlainDateTime, month : Int) -> PlainDateTime!Error { { ..self, date: self.date.with_month!(month) } } -/// Returns a new datetime with the specified day of month. +///| Returns a new datetime with the specified day of month. pub fn with_day(self : PlainDateTime, day : Int) -> PlainDateTime!Error { { ..self, date: self.date.with_day!(day) } } -/// Returns a new datetime with the specified ordinal day of year. +///| Returns a new datetime with the specified ordinal day of year. pub fn with_ordinal(self : PlainDateTime, ordinal : Int) -> PlainDateTime!Error { { ..self, date: self.date.with_ordinal!(ordinal) } } -/// Returns a new datetime with the specified hour. +///| Returns a new datetime with the specified hour. pub fn with_hour(self : PlainDateTime, hour : Int) -> PlainDateTime!Error { { ..self, time: self.time.with_hour!(hour) } } -/// Returns a new datetime with the specified minute. +///| Returns a new datetime with the specified minute. pub fn with_minute(self : PlainDateTime, minute : Int) -> PlainDateTime!Error { { ..self, time: self.time.with_minute!(minute) } } -/// Returns a new datetime with the specified second. +///| Returns a new datetime with the specified second. pub fn with_second(self : PlainDateTime, second : Int) -> PlainDateTime!Error { { ..self, time: self.time.with_second!(second) } } -/// Returns a new datetime with the specified nanosecond. +///| Returns a new datetime with the specified nanosecond. pub fn with_nanosecond( self : PlainDateTime, nanosecond : Int @@ -287,12 +288,12 @@ pub fn with_nanosecond( { ..self, time: self.time.with_nanosecond!(nanosecond) } } -/// Returns the date part of this datetime. +///| Returns the date part of this datetime. pub fn to_plain_date(self : PlainDateTime) -> PlainDate { self.date } -/// Returns the time part of this datetime. +///| Returns the time part of this datetime. pub fn to_plain_time(self : PlainDateTime) -> PlainTime { self.time } @@ -301,6 +302,7 @@ pub fn to_plain_time(self : PlainDateTime) -> PlainTime { // * internal helper functions * // ***************************** +///| fn overflowing_add( self : PlainDateTime, h~ : Int64 = 0L, diff --git a/time/plain_time.mbt b/time/plain_time.mbt index be46c99..d17bf37 100644 --- a/time/plain_time.mbt +++ b/time/plain_time.mbt @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// A time without a time zone +///| A time without a time zone struct PlainTime { hour : Int minute : Int @@ -20,7 +20,7 @@ struct PlainTime { nanosecond : Int } derive(Eq, Compare) -/// Creates a PlainTime from the hour, minute, second and nanosecond. +///| Creates a PlainTime from the hour, minute, second and nanosecond. pub fn PlainTime::of( hour : Int, minute : Int, @@ -34,7 +34,7 @@ pub fn PlainTime::of( } } -/// Creates a PlainTime from a string, like '10:20:30.45678'. +///| Creates a PlainTime from a string, like '10:20:30.45678'. pub fn PlainTime::from_string(str : String) -> PlainTime!Error { // TODO: better parsing implementation if str.length() < 5 || str.length() > 18 || str[2] != ':' { @@ -59,7 +59,7 @@ pub fn PlainTime::from_string(str : String) -> PlainTime!Error { PlainTime::of!(hour, minute, second, nanosecond) } -/// Returns a string representing the time. +///| Returns a string representing the time. pub fn PlainTime::to_string(self : PlainTime) -> String { let buf = StringBuilder::new(size_hint=8) buf.write_string(add_prefix_zero(self.hour.to_string(), 2)) @@ -77,31 +77,32 @@ pub fn PlainTime::to_string(self : PlainTime) -> String { buf.to_string() } +///| pub impl Show for PlainTime with output(self : PlainTime, logger : Logger) -> Unit { logger.write_string(self.to_string()) } -/// Returns the hour of this time. +///| Returns the hour of this time. pub fn hour(self : PlainTime) -> Int { self.hour } -/// Returns the minute of this time. +///| Returns the minute of this time. pub fn minute(self : PlainTime) -> Int { self.minute } -/// Returns the second of this time. +///| Returns the second of this time. pub fn second(self : PlainTime) -> Int { self.second } -/// Returns the nanosecond of this time. +///| Returns the nanosecond of this time. pub fn nanosecond(self : PlainTime) -> Int { self.nanosecond } -/// Returns the total seconds of this time. +///| Returns the total seconds of this time. pub fn second_of_day(self : PlainTime) -> Int { let sec = self.hour * seconds_per_hour.to_int() + self.minute * seconds_per_minute.to_int() + @@ -109,13 +110,13 @@ pub fn second_of_day(self : PlainTime) -> Int { sec } -/// Returns the total nanoseconds of this time. +///| Returns the total nanoseconds of this time. pub fn nanosecond_of_day(self : PlainTime) -> Int64 { let sec = self.second_of_day() sec.to_int64() * nanoseconds_per_second + self.nanosecond.to_int64() } -/// Creates a PlainTime from the total seconds of the day. +///| Creates a PlainTime from the total seconds of the day. pub fn PlainTime::from_second_of_day(second : Int) -> PlainTime!Error { if second < 0 || second > seconds_per_day.to_int() { fail!(invalid_time_err) @@ -128,7 +129,7 @@ pub fn PlainTime::from_second_of_day(second : Int) -> PlainTime!Error { PlainTime::of!(hour.to_int(), minute.to_int(), sec.to_int(), 0) } -/// Creates a PlainTime from the total nanoseconds of the day. +///| Creates a PlainTime from the total nanoseconds of the day. pub fn PlainTime::from_nanosecond_of_day(nanosecond : Int64) -> PlainTime!Error { if nanosecond < 0L || nanosecond > nanoseconds_per_day { fail!(invalid_time_err) @@ -148,7 +149,7 @@ pub fn PlainTime::from_nanosecond_of_day(nanosecond : Int64) -> PlainTime!Error ) } -/// Adds specified hours to this time, and returns a new time. +///| Adds specified hours to this time, and returns a new time. pub fn add_hours(self : PlainTime, hours : Int64) -> PlainTime!Error { if hours == 0L { return self @@ -157,7 +158,7 @@ pub fn add_hours(self : PlainTime, hours : Int64) -> PlainTime!Error { PlainTime::of!(new_hour.to_int(), self.minute, self.second, self.nanosecond) } -/// Adds specified minutes to this time, and returns a new time. +///| Adds specified minutes to this time, and returns a new time. pub fn add_minutes(self : PlainTime, minutes : Int64) -> PlainTime!Error { if minutes == 0L { return self @@ -178,7 +179,7 @@ pub fn add_minutes(self : PlainTime, minutes : Int64) -> PlainTime!Error { ) } -/// Adds specified seconds to this time, and returns a new time. +///| Adds specified seconds to this time, and returns a new time. pub fn add_seconds(self : PlainTime, seconds : Int64) -> PlainTime!Error { if seconds == 0L { return self @@ -202,7 +203,7 @@ pub fn add_seconds(self : PlainTime, seconds : Int64) -> PlainTime!Error { ) } -/// Adds specified nanoseconds to this time, and returns a new time. +///| Adds specified nanoseconds to this time, and returns a new time. pub fn add_nanoseconds( self : PlainTime, nanoseconds : Int64 @@ -221,7 +222,7 @@ pub fn add_nanoseconds( PlainTime::from_nanosecond_of_day!(new_nanos) } -/// Adds a duration to this time, and returns a new time. +///| Adds a duration to this time, and returns a new time. pub fn add_duration(self : PlainTime, duration : Duration) -> PlainTime!Error { if duration.is_zero() { return self @@ -229,7 +230,7 @@ pub fn add_duration(self : PlainTime, duration : Duration) -> PlainTime!Error { self.add_nanoseconds!(duration.to_nanoseconds()) } -/// Returns a new time with the specified hour. +///| Returns a new time with the specified hour. pub fn with_hour(self : PlainTime, hour : Int) -> PlainTime!Error { if hour == self.hour { return self @@ -237,7 +238,7 @@ pub fn with_hour(self : PlainTime, hour : Int) -> PlainTime!Error { PlainTime::of!(hour, self.minute, self.second, self.nanosecond) } -/// Returns a new time with the specified minute. +///| Returns a new time with the specified minute. pub fn with_minute(self : PlainTime, minute : Int) -> PlainTime!Error { if minute == self.minute { return self @@ -245,7 +246,7 @@ pub fn with_minute(self : PlainTime, minute : Int) -> PlainTime!Error { PlainTime::of!(self.hour, minute, self.second, self.nanosecond) } -/// Returns a new time with the specified second. +///| Returns a new time with the specified second. pub fn with_second(self : PlainTime, second : Int) -> PlainTime!Error { if second == self.second { return self @@ -253,7 +254,7 @@ pub fn with_second(self : PlainTime, second : Int) -> PlainTime!Error { PlainTime::of!(self.hour, self.minute, second, self.nanosecond) } -/// Returns a new time with the specified nanosecond. +///| Returns a new time with the specified nanosecond. pub fn with_nanosecond(self : PlainTime, nanosecond : Int) -> PlainTime!Error { if nanosecond == self.nanosecond { return self @@ -261,13 +262,13 @@ pub fn with_nanosecond(self : PlainTime, nanosecond : Int) -> PlainTime!Error { PlainTime::of!(self.hour, self.minute, self.second, nanosecond) } -/// Returns the duration between this time and another time. +///| Returns the duration between this time and another time. pub fn until(self : PlainTime, end : PlainTime) -> Duration!Error { let nanoseconds = end.nanosecond_of_day() - self.nanosecond_of_day() Duration::of!(nanoseconds~) } -/// Combines this time with a date to creates a PlainDateTime +///| Combines this time with a date to creates a PlainDateTime pub fn at_date(self : PlainTime, date : PlainDate) -> PlainDateTime { PlainDateTime::{ date, time: self } } @@ -276,42 +277,61 @@ pub fn at_date(self : PlainTime, date : PlainDate) -> PlainDateTime { // * internal helper functions * // ***************************** +///| let min_hour = 0 +///| let max_hour = 23 +///| let min_minute = 0 +///| let max_minute = 59 +///| let min_second = 0 +///| let max_second = 59 +///| let min_nanosecond = 0 +///| let max_nanosecond = 999_999_999 +///| let hours_per_day = 24L +///| let minutes_per_hour = 60L +///| let minutes_per_day : Int64 = 24L * minutes_per_hour +///| let seconds_per_minute = 60L +///| let seconds_per_hour : Int64 = seconds_per_minute * 60L +///| let seconds_per_day : Int64 = seconds_per_hour * 24L +///| let nanoseconds_per_second = 1_000_000_000L +///| let nanoseconds_per_minute : Int64 = nanoseconds_per_second * seconds_per_minute +///| let nanoseconds_per_hour : Int64 = nanoseconds_per_minute * minutes_per_hour +///| let nanoseconds_per_day : Int64 = nanoseconds_per_second * seconds_per_day +///| fn validate_time(h : Int, m : Int, s : Int, ns : Int) -> Bool { let valid_hour = validate_hour(h) let valid_minute = validate_minute(m) @@ -321,18 +341,22 @@ fn validate_time(h : Int, m : Int, s : Int, ns : Int) -> Bool { (valid_hour && valid_minute && valid_second && valid_nano) || zero } +///| fn validate_hour(h : Int) -> Bool { h >= min_hour && h <= max_hour } +///| fn validate_minute(m : Int) -> Bool { m >= min_minute && m <= max_minute } +///| fn validate_second(s : Int) -> Bool { s >= min_second && s <= max_second } +///| fn validate_nano(n : Int) -> Bool { n >= min_nanosecond && n <= max_nanosecond } diff --git a/time/time.mbti b/time/time.mbti index f100bf7..ddd7548 100644 --- a/time/time.mbti +++ b/time/time.mbti @@ -19,14 +19,12 @@ impl Duration { add_minutes(Self, Int64) -> Self! add_nanoseconds(Self, Int64) -> Self! add_seconds(Self, Int64) -> Self! - compare(Self, Self) -> Int from_string(String) -> Self! is_neg(Self) -> Bool is_zero(Self) -> Bool nanoseconds(Self) -> Int of(hours~ : Int64 = .., minutes~ : Int64 = .., seconds~ : Int64 = .., nanoseconds~ : Int64 = ..) -> Self! op_add(Self, Self) -> Self! - op_equal(Self, Self) -> Bool seconds(Self) -> Int64 to_nanoseconds(Self) -> Int64 to_string(Self) -> String @@ -45,7 +43,6 @@ impl Period { add_period(Self, Self) -> Self! add_weeks(Self, Int) -> Self! add_years(Self, Int) -> Self! - compare(Self, Self) -> Int days(Self) -> Int from_string(String) -> Self! is_neg(Self) -> Bool @@ -55,7 +52,6 @@ impl Period { negated(Self) -> Self! of(years~ : Int = .., months~ : Int = .., days~ : Int = ..) -> Self op_add(Self, Self) -> Self! - op_equal(Self, Self) -> Bool op_sub(Self, Self) -> Self! to_string(Self) -> String to_total_months(Self) -> Int64 @@ -116,7 +112,6 @@ impl PlainDateTime { add_seconds(Self, Int64) -> Self! add_weeks(Self, Int64) -> Self! add_years(Self, Int64) -> Self! - compare(Self, Self) -> Int day(Self) -> Int days_in_month(Self) -> Int days_in_week(Self) -> Int @@ -132,7 +127,6 @@ impl PlainDateTime { months_in_year(Self) -> Int nanosecond(Self) -> Int of(Int, Int, Int, hour~ : Int = .., minute~ : Int = .., second~ : Int = .., nanosecond~ : Int = ..) -> Self! - op_equal(Self, Self) -> Bool ordinal(Self) -> Int second(Self) -> Int to_plain_date(Self) -> PlainDate @@ -162,7 +156,6 @@ impl PlainTime { add_nanoseconds(Self, Int64) -> Self! add_seconds(Self, Int64) -> Self! at_date(Self, PlainDate) -> PlainDateTime - compare(Self, Self) -> Int from_nanosecond_of_day(Int64) -> Self! from_second_of_day(Int) -> Self! from_string(String) -> Self! @@ -171,7 +164,6 @@ impl PlainTime { nanosecond(Self) -> Int nanosecond_of_day(Self) -> Int64 of(Int, Int, Int, Int) -> Self! - op_equal(Self, Self) -> Bool second(Self) -> Int second_of_day(Self) -> Int to_string(Self) -> String @@ -194,16 +186,12 @@ pub(all) enum Weekday { Saturday Sunday } -impl Weekday { - op_equal(Self, Self) -> Bool -} impl Eq for Weekday impl Show for Weekday type Zone impl Zone { is_fixed(Self) -> Bool - op_equal(Self, Self) -> Bool to_string(Self) -> String } impl Eq for Zone diff --git a/time/util.mbt b/time/util.mbt index e81769e..353eb3c 100644 --- a/time/util.mbt +++ b/time/util.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| fn add_prefix_zero(s : String, len : Int) -> String { let buf = StringBuilder::new(size_hint=len) for i = s.length(); i < len; i = i + 1 { @@ -21,6 +22,7 @@ fn add_prefix_zero(s : String, len : Int) -> String { buf.to_string() } +///| fn remove_prefix_zero(s : String) -> String { if s.length() == 0 { return s @@ -51,6 +53,7 @@ test "remove_prefix_zero" { inspect!(remove_prefix_zero("000"), content="0") } +///| fn add_suffix_zero(s : String, len : Int) -> String { let buf = StringBuilder::new(size_hint=len) buf.write_string(s) @@ -60,6 +63,7 @@ fn add_suffix_zero(s : String, len : Int) -> String { buf.to_string() } +///| fn remove_suffix_zero(s : String) -> String { if s.length() == 0 { return s @@ -84,7 +88,7 @@ test "remove_suffix_zero" { inspect!(remove_suffix_zero("000"), content="0") } -/// FIXME: use split method of String +///| FIXME: use split method of String fn split(s : String, delimiter : Char) -> Array[String] { let spl = [] if s.length() == 0 { @@ -143,15 +147,17 @@ test "split" { ) } +///| fn int_overflow_err[T]() -> T!Error { raise Failure("Int overflow") } +///| fn int64_overflow_err[T]() -> T!Error { raise Failure("Int64 overflow") } -/// FIXME: use checked_add method of Int +///| FIXME: use checked_add method of Int fn checked_add_int(x : Int, y : Int) -> Int!Error { let r = x.to_int64() + y.to_int64() if r < @int.min_value.to_int64() || r > @int.max_value.to_int64() { @@ -161,7 +167,7 @@ fn checked_add_int(x : Int, y : Int) -> Int!Error { } } -/// FIXME: use checked_mul method of Int +///| FIXME: use checked_mul method of Int fn checked_mul_int(x : Int, y : Int) -> Int!Error { let r = x.to_int64() * y.to_int64() if r < @int.min_value.to_int64() || r > @int.max_value.to_int64() { @@ -171,7 +177,7 @@ fn checked_mul_int(x : Int, y : Int) -> Int!Error { } } -/// FIXME: use checked_add method of Int64 +///| FIXME: use checked_add method of Int64 fn checked_add_int64(x : Int64, y : Int64) -> Int64!Error { let r = x + y // Overflow iff both arguments have the opposite sign of the result @@ -182,7 +188,7 @@ fn checked_add_int64(x : Int64, y : Int64) -> Int64!Error { } } -/// FIXME: use checked_mul method of Int64 +///| FIXME: use checked_mul method of Int64 fn checked_mul_int64(x : Int64, y : Int64) -> Int64!Error { let r = x * y let abs_x = x.abs() @@ -253,6 +259,7 @@ test "checked_mul_int64" { ) } +///| fn floor(x : Double) -> Double { if x.is_pos_inf() || x.is_neg_inf() || x.is_nan() { return x @@ -266,6 +273,7 @@ fn floor(x : Double) -> Double { } } +///| fn floor_div_int(x : Int, y : Int) -> Int!Error { if y == 0 { raise Failure("division by zero") @@ -286,6 +294,7 @@ test "floor_div_int" { ) } +///| fn floor_div_int64(x : Int64, y : Int64) -> Int64!Error { if y == 0L { fail!("division by zero") @@ -306,6 +315,7 @@ test "floor_div_int64" { ) } +///| fn floor_mod_int(x : Int, y : Int) -> Int!Error { x - floor_div_int!(x, y) * y } @@ -322,6 +332,7 @@ test "floor_mod_int" { ) } +///| fn floor_mod_int64(x : Int64, y : Int64) -> Int64!Error { x - floor_div_int64!(x, y) * y } diff --git a/time/weekday.mbt b/time/weekday.mbt index 9288462..99dc00d 100644 --- a/time/weekday.mbt +++ b/time/weekday.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub(all) enum Weekday { Monday Tuesday @@ -22,6 +23,7 @@ pub(all) enum Weekday { Sunday } derive(Eq, Show) +///| fn Weekday::new(week_day : Int) -> Weekday? { match week_day { 1 => Some(Monday) @@ -35,6 +37,7 @@ fn Weekday::new(week_day : Int) -> Weekday? { } } +///| fn value(self : Weekday) -> Int { match self { Monday => 1 diff --git a/time/zone.mbt b/time/zone.mbt index 9eab8f2..9a898b9 100644 --- a/time/zone.mbt +++ b/time/zone.mbt @@ -12,36 +12,38 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Time zone. +///| Time zone. struct Zone { id : String offsets : Array[ZoneOffset] // TODO: offset transition rules } derive(Eq) -/// UTC time zone. +///| UTC time zone. pub let utc_zone : Zone = { id: "UTC", offsets: [utc_offset] } -/// Creates a time zone with fixed offset from time zone id and offset seconds. +///| Creates a time zone with fixed offset from time zone id and offset seconds. pub fn fixed_zone(id : String, offset_seconds : Int) -> Zone!Error { let offset = ZoneOffset::from_seconds!(offset_seconds) Zone::{ id, offsets: [offset] } } -/// Checks if this zone only has one offset. +///| Checks if this zone only has one offset. pub fn is_fixed(self : Zone) -> Bool { self.offsets.length() == 1 } -/// Returns the zone id. +///| Returns the zone id. pub fn to_string(self : Zone) -> String { self.id } +///| pub impl Show for Zone with output(self : Zone, logger : Logger) -> Unit { logger.write_string(self.to_string()) } +///| fn lookup_offset(self : Zone, _secs : Int64) -> ZoneOffset { if self.offsets.length() == 0 { return utc_offset diff --git a/time/zone_offset.mbt b/time/zone_offset.mbt index 5a372e5..9344845 100644 --- a/time/zone_offset.mbt +++ b/time/zone_offset.mbt @@ -12,29 +12,33 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// Time offset from UTC. +///| Time offset from UTC. struct ZoneOffset { id : String seconds : Int dst : Bool } +///| let max_offset_hours = 18 +///| let min_offset_hours = -18 +///| let max_offset_seconds : Int = max_offset_hours * seconds_per_hour.to_int() +///| let min_offset_seconds : Int = min_offset_hours * seconds_per_hour.to_int() -/// UTC+0 offset. +///| UTC+0 offset. pub let utc_offset : ZoneOffset = ZoneOffset::{ id: "Z", seconds: 0, dst: false, } -/// Creates a offset from hours, minutes and seconds. +///| Creates a offset from hours, minutes and seconds. pub fn ZoneOffset::of( hours~ : Int = 0, minutes~ : Int = 0, @@ -47,7 +51,7 @@ pub fn ZoneOffset::of( ZoneOffset::from_seconds!(secs) } -/// Creates a offset from seconds. +///| Creates a offset from seconds. pub fn ZoneOffset::from_seconds(seconds : Int) -> ZoneOffset!Error { if seconds == 0 { return utc_offset @@ -58,38 +62,42 @@ pub fn ZoneOffset::from_seconds(seconds : Int) -> ZoneOffset!Error { { id: create_id(seconds), seconds, dst: false } } -/// Returns the offset id. +///| Returns the offset id. pub fn to_string(self : ZoneOffset) -> String { self.id } +///| pub impl Show for ZoneOffset with output(self : ZoneOffset, logger : Logger) { logger.write_string(self.to_string()) } +///| pub fn op_equal(self : ZoneOffset, other : ZoneOffset) -> Bool { self.seconds == other.seconds } +///| pub fn compare(self : ZoneOffset, other : ZoneOffset) -> Int { other.seconds - self.seconds } -/// Returns the offset id. +///| Returns the offset id. pub fn id(self : ZoneOffset) -> String { self.id } -/// Returns the total seconds of this offset. +///| Returns the total seconds of this offset. pub fn seconds(self : ZoneOffset) -> Int { self.seconds } -/// Checks if this offset is daylight saving time. +///| Checks if this offset is daylight saving time. pub fn is_dst(self : ZoneOffset) -> Bool { self.dst } +///| fn create_id(secs : Int) -> String { if secs == 0 { return "Z" @@ -112,6 +120,7 @@ fn create_id(secs : Int) -> String { buf.to_string() } +///| fn validate_offset(h : Int, m : Int, s : Int) -> Unit!Error { if h < min_offset_hours || h > max_offset_hours { fail!(invalid_offset_err) diff --git a/time/zoned_date_time.mbt b/time/zoned_date_time.mbt index aaf8a0f..5acc759 100644 --- a/time/zoned_date_time.mbt +++ b/time/zoned_date_time.mbt @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// A datetime with a time zone and offset in the ISO 8601 calendar system. +///| A datetime with a time zone and offset in the ISO 8601 calendar system. struct ZonedDateTime { datetime : PlainDateTime zone : Zone offset : ZoneOffset } -/// Creates a ZonedDateTime from year, month, day, hour, minute, second and a time zone. +///| Creates a ZonedDateTime from year, month, day, hour, minute, second and a time zone. /// The default time zone is UTC+0. pub fn date_time( year : Int, @@ -33,7 +33,7 @@ pub fn date_time( ZonedDateTime::of!(year, month, day, hour~, minute~, second~, zone~) } -/// Creates a ZonedDateTime from elapsed seconds since the unix epoch and a time zone. +///| Creates a ZonedDateTime from elapsed seconds since the unix epoch and a time zone. /// The default time zone is UTC+0. pub fn unix( second : Int64, @@ -43,7 +43,7 @@ pub fn unix( ZonedDateTime::from_unix_second!(second, nanosecond~, zone~) } -/// Creates a ZonedDateTime from year, month, day, hour, minute and second. +///| Creates a ZonedDateTime from year, month, day, hour, minute and second. /// The default time zone is UTC+0. pub fn ZonedDateTime::of( year : Int, @@ -58,7 +58,7 @@ pub fn ZonedDateTime::of( create_from_plain(datetime, zone) } -/// Creates a ZonedDateTime from a PlainDateTime and a time zone. +///| Creates a ZonedDateTime from a PlainDateTime and a time zone. /// The default time zone is UTC+0. pub fn ZonedDateTime::from_plain_datetime( datetime : PlainDateTime, @@ -67,7 +67,7 @@ pub fn ZonedDateTime::from_plain_datetime( create_from_plain(datetime, zone) } -/// Creates a ZonedDateTime from elapsed seconds since the unix epoch and a time zone. +///| Creates a ZonedDateTime from elapsed seconds since the unix epoch and a time zone. /// The default time zone is UTC+0. pub fn ZonedDateTime::from_unix_second( second : Int64, @@ -79,7 +79,7 @@ pub fn ZonedDateTime::from_unix_second( { datetime, zone, offset } } -/// Returns a string representing this datetime, like "2008-08-08T20:00:00+8:00[Asia/Beijing]" +///| Returns a string representing this datetime, like "2008-08-08T20:00:00+8:00[Asia/Beijing]" pub fn to_string(self : ZonedDateTime) -> String { let buf = StringBuilder::new(size_hint=0) buf.write_string(self.datetime.to_string()) @@ -92,6 +92,7 @@ pub fn to_string(self : ZonedDateTime) -> String { buf.to_string() } +///| pub impl Show for ZonedDateTime with output( self : ZonedDateTime, logger : Logger @@ -99,142 +100,142 @@ pub impl Show for ZonedDateTime with output( logger.write_string(self.to_string()) } -/// Returns the elapsed seconds since the unix epoch. +///| Returns the elapsed seconds since the unix epoch. pub fn to_unix_second(self : ZonedDateTime) -> Int64 { self.datetime.to_unix_second() - self.offset.seconds().to_int64() } -/// Returns the date part of this datetime, without timezone. +///| Returns the date part of this datetime, without timezone. pub fn to_plain_date(self : ZonedDateTime) -> PlainDate { self.datetime.to_plain_date() } -/// Returns the time part of this datetime, without timezone. +///| Returns the time part of this datetime, without timezone. pub fn to_plain_time(self : ZonedDateTime) -> PlainTime { self.datetime.to_plain_time() } -/// Returns the datetime part of this datetime, without timezone. +///| Returns the datetime part of this datetime, without timezone. pub fn to_plain_date_time(self : ZonedDateTime) -> PlainDateTime { self.datetime } -/// Returns the era of this datetime. +///| Returns the era of this datetime. pub fn era(self : ZonedDateTime) -> String { self.datetime.era() } -/// Returns the year of era of this datetime. +///| Returns the year of era of this datetime. pub fn era_year(self : ZonedDateTime) -> Int { self.datetime.era_year() } -/// Returns the year of this datetime. +///| Returns the year of this datetime. pub fn year(self : ZonedDateTime) -> Int { self.datetime.year() } -/// Returns the month of this datetime. +///| Returns the month of this datetime. pub fn month(self : ZonedDateTime) -> Int { self.datetime.month() } -/// Returns the day of month of this datetime. +///| Returns the day of month of this datetime. pub fn day(self : ZonedDateTime) -> Int { self.datetime.day() } -/// Returns the weekday of this datetime. +///| Returns the weekday of this datetime. pub fn weekday(self : ZonedDateTime) -> Weekday { self.datetime.weekday() } -/// Returns the ordinal day of year of this datetime. +///| Returns the ordinal day of year of this datetime. pub fn ordinal(self : ZonedDateTime) -> Int { self.datetime.ordinal() } -/// Returns the number of days in a month of this datetime. +///| Returns the number of days in a month of this datetime. pub fn days_in_week(self : ZonedDateTime) -> Int { self.datetime.days_in_week() } -/// Returns the number of days in a month of this datetime. +///| Returns the number of days in a month of this datetime. pub fn days_in_month(self : ZonedDateTime) -> Int { self.datetime.days_in_month() } -/// Returns the number of days in a year of this datetime. +///| Returns the number of days in a year of this datetime. pub fn days_in_year(self : ZonedDateTime) -> Int { self.datetime.days_in_year() } -/// Returns the number of months in a year of this datetime. +///| Returns the number of months in a year of this datetime. pub fn months_in_year(self : ZonedDateTime) -> Int { self.datetime.months_in_year() } -/// Checks if this datetime is in a leap year. +///| Checks if this datetime is in a leap year. pub fn in_leap_year(self : ZonedDateTime) -> Bool { self.datetime.in_leap_year() } -/// Returns the hour of this datetime. +///| Returns the hour of this datetime. pub fn hour(self : ZonedDateTime) -> Int { self.datetime.hour() } -/// Returns the minute of this datetime. +///| Returns the minute of this datetime. pub fn minute(self : ZonedDateTime) -> Int { self.datetime.minute() } -/// Returns the second of this datetime. +///| Returns the second of this datetime. pub fn second(self : ZonedDateTime) -> Int { self.datetime.second() } -/// Returns the nanosecond of this datetime. +///| Returns the nanosecond of this datetime. pub fn nanosecond(self : ZonedDateTime) -> Int { self.datetime.nanosecond() } -/// Returns the time zone of this datetime. +///| Returns the time zone of this datetime. pub fn zone(self : ZonedDateTime) -> Zone { self.zone } -/// Returns the time offset of this datetime. +///| Returns the time offset of this datetime. pub fn offset(self : ZonedDateTime) -> ZoneOffset { self.offset } -/// Adds specified years to this datetime, and returns a new datetime. +///| Adds specified years to this datetime, and returns a new datetime. pub fn add_years(self : ZonedDateTime, years : Int64) -> ZonedDateTime!Error { create_from_plain(self.datetime.add_years!(years), self.zone) } -/// Adds specified months to this datetime, and returns a new datetime. +///| Adds specified months to this datetime, and returns a new datetime. pub fn add_months(self : ZonedDateTime, months : Int64) -> ZonedDateTime!Error { create_from_plain(self.datetime.add_months!(months), self.zone) } -/// Adds specified weeks to this datetime, and returns a new datetime. +///| Adds specified weeks to this datetime, and returns a new datetime. pub fn add_weeks(self : ZonedDateTime, weeks : Int64) -> ZonedDateTime!Error { create_from_plain(self.datetime.add_weeks!(weeks), self.zone) } -/// Adds specified days to this datetime, and returns a new datetime. +///| Adds specified days to this datetime, and returns a new datetime. pub fn add_days(self : ZonedDateTime, days : Int64) -> ZonedDateTime!Error { create_from_plain(self.datetime.add_days!(days), self.zone) } -/// Adds specified hours to this datetime, and returns a new datetime. +///| Adds specified hours to this datetime, and returns a new datetime. pub fn add_hours(self : ZonedDateTime, hours : Int64) -> ZonedDateTime!Error { create_from_plain(self.datetime.add_hours!(hours), self.zone) } -/// Adds specified minutes to this datetime, and returns a new datetime. +///| Adds specified minutes to this datetime, and returns a new datetime. pub fn add_minutes( self : ZonedDateTime, minutes : Int64 @@ -242,7 +243,7 @@ pub fn add_minutes( create_from_plain(self.datetime.add_minutes!(minutes), self.zone) } -/// Adds specified seconds to this datetime, and returns a new datetime. +///| Adds specified seconds to this datetime, and returns a new datetime. pub fn add_seconds( self : ZonedDateTime, seconds : Int64 @@ -250,7 +251,7 @@ pub fn add_seconds( create_from_plain(self.datetime.add_seconds!(seconds), self.zone) } -/// Adds specified nanoseconds to this datetime, and returns a new datetime. +///| Adds specified nanoseconds to this datetime, and returns a new datetime. pub fn add_nanoseconds( self : ZonedDateTime, nanoseconds : Int64 @@ -258,42 +259,42 @@ pub fn add_nanoseconds( create_from_plain(self.datetime.add_nanoseconds!(nanoseconds), self.zone) } -/// Returns a new datetime with the specified year. +///| Returns a new datetime with the specified year. pub fn with_year(self : ZonedDateTime, year : Int) -> ZonedDateTime!Error { create_from_plain(self.datetime.with_year!(year), self.zone) } -/// Returns a new datetime with the specified month. +///| Returns a new datetime with the specified month. pub fn with_month(self : ZonedDateTime, month : Int) -> ZonedDateTime!Error { create_from_plain(self.datetime.with_month!(month), self.zone) } -/// Returns a new datetime with the specified day of the month. +///| Returns a new datetime with the specified day of the month. pub fn with_day(self : ZonedDateTime, day : Int) -> ZonedDateTime!Error { create_from_plain(self.datetime.with_day!(day), self.zone) } -/// Returns a new datetime with the specified ordinal day of the year. +///| Returns a new datetime with the specified ordinal day of the year. pub fn with_ordinal(self : ZonedDateTime, ordinal : Int) -> ZonedDateTime!Error { create_from_plain(self.datetime.with_ordinal!(ordinal), self.zone) } -/// Returns a new datetime with the specified hour. +///| Returns a new datetime with the specified hour. pub fn with_hour(self : ZonedDateTime, hour : Int) -> ZonedDateTime!Error { create_from_plain(self.datetime.with_hour!(hour), self.zone) } -/// Returns a new datetime with the specified minute. +///| Returns a new datetime with the specified minute. pub fn with_minute(self : ZonedDateTime, minute : Int) -> ZonedDateTime!Error { create_from_plain(self.datetime.with_minute!(minute), self.zone) } -/// Returns a new datetime with the specified second. +///| Returns a new datetime with the specified second. pub fn with_second(self : ZonedDateTime, second : Int) -> ZonedDateTime!Error { create_from_plain(self.datetime.with_second!(second), self.zone) } -/// Returns a new datetime with the specified nanosecond. +///| Returns a new datetime with the specified nanosecond. pub fn with_nanosecond( self : ZonedDateTime, nanosecond : Int @@ -301,6 +302,7 @@ pub fn with_nanosecond( create_from_plain(self.datetime.with_nanosecond!(nanosecond), self.zone) } +///| fn create_from_plain(datetime : PlainDateTime, zone : Zone) -> ZonedDateTime { let offset = zone.lookup_offset(datetime.to_unix_second()) { datetime, zone, offset } diff --git a/uuid/ops.mbt b/uuid/ops.mbt index 1ea9d5b..1c606e8 100644 --- a/uuid/ops.mbt +++ b/uuid/ops.mbt @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +///| pub fn hash(self : UUID) -> Int { Hash::hash(self.lo) ^ Hash::hash(self.hi) } diff --git a/uuid/uuid.mbt b/uuid/uuid.mbt index dba1275..060fb5c 100644 --- a/uuid/uuid.mbt +++ b/uuid/uuid.mbt @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -/// UUID that complies with RFC 4122. +///| UUID that complies with RFC 4122. /// /// UUID objects are immutable, hashable and usable as mapping keys. /// The Display of UUIDs is like `12345678-1234-1234-1234-123456789abc`; @@ -42,7 +42,7 @@ struct UUID { lo : Int64 } derive(Eq, Compare) -/// Constructs a UUID with the given big-endian bytes. +///| Constructs a UUID with the given big-endian bytes. /// /// The produced UUID is not RFC-4122 compliant; see also `as_version()`. /// @@ -64,7 +64,7 @@ pub fn from_bytes(bytes : Bytes) -> UUID!Error { { hi, lo } } -/// The UUID as a 16-byte string. +///| The UUID as a 16-byte string. pub fn to_bytes(self : UUID) -> Bytes { // XXX: replace with a cheaper way let rv = Bytes::new(16) @@ -99,6 +99,7 @@ test "bytes" { ) } +///| fn hex_char_to_int64(c : Char) -> Int64!Error { let d = if '0' <= c && c <= '9' { c.to_int() - '0'.to_int() @@ -112,7 +113,7 @@ fn hex_char_to_int64(c : Char) -> Int64!Error { d.to_int64() } -/// Constructs a UUID with the given hexadecimal string. +///| Constructs a UUID with the given hexadecimal string. /// /// This function ignores dashes (`-`) in the given string. The remaining /// letters must be exactly 32 hexadecimals, or an error will be raised. @@ -155,20 +156,25 @@ pub fn from_hex(hex : String) -> UUID!Error { } } +///| let hex_table : Array[Int] = "0123456789abcdef" .to_array() .map(fn { c => c.to_int() }) +///| let dash : Int = '-'.to_int() +///| let segments = [8, 4, 4, 0, 4, 12] // XXX: use sum() instead; weird `moon fmt` +///| let size : Int = ( segments.fold(fn { acc, x => acc + x }, init=0) + segments.length() - 2 ) * 2 +///| pub fn to_string(self : UUID) -> String { // This is a manually-composed UTF-16 string let rv = Bytes::new(size) @@ -191,6 +197,7 @@ pub fn to_string(self : UUID) -> String { } } +///| pub impl Show for UUID with output(self : UUID, logger : Logger) -> Unit { logger.write_string(self.to_string()) } diff --git a/uuid/uuid.mbti b/uuid/uuid.mbti index 5bb9cb9..3f2f9cb 100644 --- a/uuid/uuid.mbti +++ b/uuid/uuid.mbti @@ -9,9 +9,7 @@ fn from_hex(String) -> UUID! type UUID impl UUID { as_version(Self, Version) -> Self - compare(Self, Self) -> Int hash(Self) -> Int - op_equal(Self, Self) -> Bool to_bytes(Self) -> Bytes to_string(Self) -> String variant(Self) -> Variant diff --git a/uuid/variant.mbt b/uuid/variant.mbt index 9e44f09..bd1ea02 100644 --- a/uuid/variant.mbt +++ b/uuid/variant.mbt @@ -15,7 +15,7 @@ // This file is partially derived from the Python project: // https://github.com/python/cpython/blob/3.12/Lib/uuid.py -/// The UUID variant. +///| The UUID variant. pub(all) enum Variant { ReservedNCS RFC4122(Version) @@ -23,7 +23,7 @@ pub(all) enum Variant { ReservedFuture } derive(Show) -/// The UUID version number. +///| The UUID version number. /// /// This is only used when the variant is `RFC4122`. /// @@ -36,6 +36,7 @@ pub(all) enum Version { Unknown(Int) } derive(Show) +///| fn Version::from_int64(int : Int64) -> Version { match int { 1L => V1 @@ -47,6 +48,7 @@ fn Version::from_int64(int : Int64) -> Version { } } +///| fn to_int64(self : Version) -> Int64 { match self { V1 => 1L @@ -58,7 +60,7 @@ fn to_int64(self : Version) -> Int64 { } } -/// Retrieves the variant of the UUID. +///| Retrieves the variant of the UUID. pub fn variant(self : UUID) -> Variant { if (self.lo & (0x8000L << 48)) == 0L { ReservedNCS @@ -75,7 +77,7 @@ pub fn variant(self : UUID) -> Variant { } } -/// Retrieves the version number of the UUID. +///| Retrieves the version number of the UUID. /// /// If the variant of the UUID is not `RFC4122`, returns `None`. /// @@ -86,7 +88,7 @@ pub fn version(self : UUID) -> Version? { } } -/// Converts this UUID to RFC-4122 with the given version number. +///| Converts this UUID to RFC-4122 with the given version number. pub fn as_version(self : UUID, version : Version) -> UUID { let { hi, lo } = self // Set the variant to RFC 4122.