mergeded

6 files changed,157insertions(+),38deletions(-) M gt/core/cmp.gt A gt/core/convert.gt M gt/core/hash.gt M gt/core/ops.gt M gt/core/range.gt M gt/core/result.gt

M gt/core/cmp.gt +35 -2

@@ 1,4 1,11 @@--- Basic module for equality and comparisons. +--- +--- Now that I think of it, we don't have PartialEq or +--- PartialOrd. We don't need them yet 'cause we don't +--- have floats. I'm kinda okay with this tbh, iirc there's +--- a semi-official standard out for ordering NaN's we +--- should look into, and there's a broad design space of +--- Rust crates for NaN-preventing floats and such. type Eq(T) = struct(T) eq: fn(T, T) Bool,@@ 105,7 112,7 @@ const OrdI32 Ord(I32) = Ord {--- `None` is always less than `Some(x)` for any `x`. fn option_ord(|T| ord Ord(T)) Ord(Option(T)) = Ord { - .cmp = fn(|T| x Option(T), y Option(T)) Ordering = + .cmp = fn(x Option(T), y Option(T)) Ordering = -- There's probably some fancy Option combinator to use -- here but I can never keep em straight. match {x, y} with@@ 119,4 126,30 @@ fn option_ord(|T| ord Ord(T)) Ord(Optionend const OrdOptionI32: Ord(Option(I32)) = option_ord(OrdI32) - + +--- A functor that implements `Ord(Result(T, E)) where T, E: Ord`. +--- +--- We take Rust's approch, ofc, any Ok is less than any Err +fn result_ord(|T, E| ord_t Ord(T), ord_e Ord(E)) Ord(Result(T, E)) = + .cmp = fn(x Result(T, E), y Result(T, E)) Ordering = + match {x, y} with + | {Ok xx, Ok yy} -> ord_t.cmp(xx, yy) + | {Err xx, Err yy} -> ord_e.cmp(xx, yy) + | {Ok _, Err _} -> Ordering.Less + | {Err _, Ok _} -> Ordering.Greater + end +end + +--- Create an implementation of Eq from the given implementation +--- of Ord. +--- +--- TODO: This is also kinda a classic coherence problem with modules +--- iirc, so investigate further. I thiiiiink we have to bundle +--- the Ord impl into the Eq one? +fn eq_from_ord(|T| ord Ord(T)) Eq(T) = + Ord { + .eq = fn(x T, y T) Bool = + ord.ord(x, y).is_eq() + end + } +end

A gt/core/convert.gt +39 -0

@@ 0,0 1,39 @@+--- Conversion modules/interfaces. +--- +--- Design ticket for stuff here: TODO +--- from/tryfrom +--- try (? operator) +--- +--- Rust's `Try` trait is absolutely fascinating and bonkers, so +--- look into it a bit more. + + +--- Infallible conversions. +type From(Self, Out) = struct(Self, Out) = + from: fn(Self) Out +end + +--- Fallible conversions. +type TryFrom(Self, Out, E) = struct(Self, Out, E) = + try_from: fn(Self) Result(Out, E) +end + +--- Truncation, for example cutting off half of an U64 to make +--- a U32. +type Truncate(Self, Out) = struct(Self, Out) = + trunc: fn(Self) Out +end + +--- Extend, for example sign-extending I32->I64 or zero-extending +--- U32->U64 +type Extend(Self, Out) = struct(Self, Out) = + extend: fn(Self) Out +end + +--- Bitcast. For example converting an I32 into a U32 or F32. +--- +--- TODO: Should require both types have the same size and +--- compatible layouts. +type bitcast(Self, Out) = struct(Self, Out) = + bitcast: fn(Self) Out +end

M gt/core/hash.gt +27 -34

@@ 1,11 1,14 @@---! Basic hashing function. ---! ---! For now this is SipHash 2-4, shamelessly stolen from ---! Rust's `std::hash::SipHasher`. Implemented from the ---! reference impl at https://github.com/veorq/SipHash ---! ---! We might want a stable hash function sometime too, ---! probably FNV. +--- Basic hashing function. +--- +--- For now this is SipHash 2-4, shamelessly stolen from +--- Rust's `std::hash::SipHasher`. Implemented from the +--- reference impl at https://github.com/veorq/SipHash +--- +--- We might want a stable hash function sometime too, +--- probably FNV. (There's also fxHash, xxHash, wyhash, etc...) +--- +--- TODO: clean up with our built-in bit ops and conversions. +--- Heck, just implement bit ops. const C_ROUNDS: U32 = 2 const D_ROUNDS: U32 = 4@@ 18,11 21,11 @@ fn u64_from_bytes_le(bytes ^[]U8) U64 =todo("this") end -fn u64_to_bytes_le(bytes: U64): [8]U8 = +fn u64_to_bytes_le(bytes U64) [8]U8 = todo("this too") end -fn sipround(v0: U64, v1: U64, v2: U64, v3: U64): {U64, U64, U64, U64} = +fn sipround(v0 U64, v1 U64, v2 U64, v3 U64) {U64, U64, U64, U64} = let v0 = v0 + v1 let v1 = rotl(v1, 13) let v1 = v1 bxor v0@@ 41,38 44,28 @@ fn sipround(v0: U64, v1: U64, v2: U64, vend -fn siphash(input: ^[]U8, k: U128, out: ^uniq[]U8): {} = - assert(out.len() == 8 or out.len() == 16) - let mut v0: U64 = 0x736f6d6570736575 - let mut v1: U64 = 0x646f72616e646f6d - let mut v2: U64 = 0x6c7967656e657261 - let mut v3: U64 = 0x7465646279746573 +fn siphash(input ^[]U8, k U128, out ^uniq[]U8) {} = + assert(out:len() == 8 or out:len() == 16) + let mut v0 U64 = 0x736f6d6570736575 + let mut v1 U64 = 0x646f72616e646f6d + let mut v2 U64 = 0x6c7967656e657261 + let mut v3 U64 = 0x7465646279746573 -- TODO: Figure out how casts work - -- Erlang-like bit patterns? - -- let <<k0:64, k1:64>> = k - -- Or maybe the bit pattern is an operator that extracts bits - -- and returns a tuple, and then we define what types those - -- turn into? - -- https://www.erlang.org/docs/25/programming_examples/bit_syntax.html#segments - -- has some info on it, basically we need to say both how many bits - -- we extract and what type those bits get turned into. - -- let {k0, k1}: {U64, U64} = <<k0:64, k1:64>> k - -- let {k0, k1} = <<k0:64/U64, k1:64/U64>> k - let k0: U64 = (k band 0xFFFF_FFFF) as U32 - let k1: U64 = ((k >> 32) band 0xFFFF_FFFF) as U32 - let left: Size = input.len() band 7 - let mut b: U64 = input.len() << 56 + -- Using convert.gt seems like a fine place to start. + let k0 U64 = Convert.trunc(|U128, U64| k band 0xFFFF_FFFF) + let k1 U64 = Convert.trunc(|U128, U64| (k >> 32) band 0xFFFF_FFFF) + let left Size = input:len() band 7 + let mut b U64 = input:len() << 56 v3 = v3 bxor k1 v2 = v2 bxor k0 v1 = v1 bxor k1 v0 = v0 bxor k0 - if out.len() == 16 then + if out:len() == 16 then v1 = v1 bxor 0xEE end - -- TODO: This hypothetical `range()` function is `start, end, step` like Python's - for i in range(0, input.len(), 8) do + for i in range(0, input:len()):step_by(8) do -- TODO: We assume Rust's slice syntax for now? let bytes = input[i..(i+8)] let m = u64_from_bytes_le(bytes)@@ 89,7 82,7 @@ fn siphash(input: ^[]U8, k: U128, out: ^-- for us. for i in range(1,8) do -- Round input.len() down to the closest multiple of 8 - let input_tail_idx = (input.len() / 8) * 8; + let input_tail_idx = (input:len() / 8) * 8; b = b bor (input[input_tail_idx + i] << i * 8) end

M gt/core/ops.gt +12 -0

@@ 1,3 1,8 @@+--- Fundamental operators. In Rust this is anything that is overloadable. +--- We don't really have any overloading yet, so it's more a a place to +--- play with ideas for such things. + + --- Kinda an equivalent of Rust's Fn() trait. --- --- Just pretend borrowing doesn't matter right now.@@ 40,3 45,10 @@ fn use_apply() =apply(thing2, {}) -- 102 end + +--- Module for indexing values, a la `foo[3]` +type Index(Self, Out, Idx) = struct(Self, Out, Idx) + --- Technically maybe should borrow Self and Out, + --- this isn't terriblt interesting without that distinction. + index: fn(Self, Idx) Out +end

M gt/core/range.gt +39 -0

@@ 20,3 20,42 @@ it results in unexpected behavior (hopef𝔰𝔠𝔬𝔱𝔱𝔪𝔠𝔪 — Today at 5:58 PM see https://github.com/rust-lang/rfcs/pull/3550 -/ + +--- A half-open range bounded between +--- `[start, end)`. +--- +--- TODO: Should this contain an Ord impl? Not very +--- meaningful without it. For now I'll leave it as no, though. +type Range(Idx) = struct(Idx) + start: Idx, + end: Idx, +end + +--- Whether the range contains the item. +fn contains(|Idx| ord Ord(Idx), self Range(Idx), itm Idx) Bool = + ord.ord(self.start, itm).is_ge() and ord.ord(self.end, itm).is_lt() +end + +--- Technically this only needs Eq, not Ord. +fn is_empty(|Idx| ord Ord(Idx), self Range(Idx)) Bool = + ord.ord(self.start, self.end).is_eq() +end + +--- Basically Python's range function that creates an iterator +--- +--- TODO: Figure out how we're implementing iterators. +fn range(|Idx| start Idx, end Idx) Iterator(Idx) = + todo() + Range { + .start = start, + .end = end, + } +end + +--- Should return an iterator that steps multiple items at a time, +--- ideally more efficiently than the naive approach... +fn step_by(|Idx| self Range(Idx)) Iterator(Idx) = + todo() +end + +-- todo: Iterator, Index(?)

M gt/core/result.gt +5 -2

@@ 1,8 1,6 @@--- Basic Result type --- --- TODO: ---- Match syntax -- ---- Sum type details -- pattern match syntax, etc. --- Panics, strings... --- Our general-purpose Result type.@@ 23,6 21,11 @@ end--- Takes a Result and returns the value contained if it is Ok, --- otherwise panics with the given message --- +--- TODO: I honestly kinda don't like how hard it is to stick a sane +--- format string in here in Rust, where you have to do +--- `thing.expect_with(|e| format!("help I got an {}", e))`. +--- But that's a problem for Future Garnet. +--- --- Properties: Panics. fn expect(|T, E| self Result(T, E), message Str) T = match self with