diff --git a/src/bitvec/bitvec.mbt b/src/bitvec/bitvec.mbt index db28fee..14a1065 100644 --- a/src/bitvec/bitvec.mbt +++ b/src/bitvec/bitvec.mbt @@ -1,141 +1,206 @@ +///| pub struct Bitvector { - v: Array[Byte] + v : Array[Byte] } +///| pub impl Show for Bitvector with to_string(self) { self.raw().to_string() } +///| pub impl Show for Bitvector with output(self, logger) { logger.write_string(self.to_string()) } +///| pub trait BitvectorConvertible { from(Self) -> Bitvector to(Bitvector) -> Self } +///| pub impl BitvectorConvertible for Bool with from(self) { { v: [self.to_int().to_byte()] } } +///| pub impl BitvectorConvertible for Bool with to(bv) { for v in bv.v { - if (v != 0) { - return true; + if v != 0 { + return true } } - return false; + return false } +///| pub impl BitvectorConvertible for Char with from(self) { - { v: self.to_int().to_le_bytes().iter().collect() } + let i = self.to_int() + { + v: [ + i.to_byte(), + (i >> 8).to_byte(), + (i >> 16).to_byte(), + (i >> 24).to_byte(), + ], + } } +///| pub impl BitvectorConvertible for Char with to(bv) { Int::unsafe_to_char(bv.out()) } +///| pub impl BitvectorConvertible for Byte with from(self) { { v: [self] } } +///| pub impl BitvectorConvertible for Byte with to(bv) { bv.v[0] } +///| pub impl BitvectorConvertible for Int with from(self) { - { v: self.to_le_bytes().iter().collect() } + { + v: [ + self.to_byte(), + (self >> 8).to_byte(), + (self >> 16).to_byte(), + (self >> 24).to_byte(), + ], + } } +///| pub impl BitvectorConvertible for Int with to(bv) { bv.to(0U).reinterpret_as_int() } +///| pub impl BitvectorConvertible for UInt with from(self) { - { v: self.to_le_bytes().iter().collect() } + { + v: [ + self.to_byte(), + (self >> 8).to_byte(), + (self >> 16).to_byte(), + (self >> 24).to_byte(), + ], + } } +///| pub impl BitvectorConvertible for UInt with to(bv) { let mut result = 0U - for i in 0..<@math.minimum(bv.v.length(), 4) { + for i in 0..<@cmp.minimum(bv.v.length(), 4) { result = result + (bv.v[i].to_uint() << (i * 8)) } result } +///| pub impl BitvectorConvertible for Int64 with from(self) { - { v: self.to_le_bytes().iter().collect() } + { + v: [ + self.to_byte(), + (self >> 8).to_byte(), + (self >> 16).to_byte(), + (self >> 24).to_byte(), + (self >> 32).to_byte(), + (self >> 40).to_byte(), + (self >> 48).to_byte(), + (self >> 56).to_byte(), + ], + } } +///| pub impl BitvectorConvertible for Int64 with to(bv) { bv.to(0UL).reinterpret_as_int64() } +///| pub impl BitvectorConvertible for UInt64 with from(self) { { v: self.to_le_bytes().iter().collect() } } +///| pub impl BitvectorConvertible for UInt64 with to(bv) { let mut result = 0UL - for i in 0..<@math.minimum(bv.v.length(), 8) { + for i in 0..<@cmp.minimum(bv.v.length(), 8) { result = result + (bv.v[i].to_uint64() << (i * 8)) } result } +///| pub impl BitvectorConvertible for Array[Byte] with from(self) { { v: self } } +///| pub impl BitvectorConvertible for Array[Byte] with to(bv) { bv.v } +///| pub impl BitvectorConvertible for ArrayView[Byte] with from(self) { { v: self.to_array() } } +///| pub impl BitvectorConvertible for ArrayView[Byte] with to(bv) { bv.v } +///| pub impl BitvectorConvertible for Bytes with from(self) { { v: self.to_array() } } +///| pub impl BitvectorConvertible for Bytes with to(bv) { Bytes::from_array(bv.v) } -pub impl BitvectorConvertible for @bytes.View with from(self) { +///| +pub impl BitvectorConvertible for BytesView with from(self) { { v: self.to_bytes().to_array() } } -pub impl BitvectorConvertible for @bytes.View with to(bv) { +///| +pub impl BitvectorConvertible for BytesView with to(bv) { Bytes::from_array(bv.v) } +///| pub impl BitvectorConvertible for Bitvector with from(self) { self } +///| pub impl BitvectorConvertible for Bitvector with to(bv) { bv } +///| pub impl BitvectorConvertible for Float with from(self) { BitvectorConvertible::from(self.reinterpret_as_int()) } +///| pub impl BitvectorConvertible for Float with to(bv) { - bv.to(0).reinterpret_as_float() + Float::reinterpret_from_int(bv.to(0)) } +///| pub impl BitvectorConvertible for Double with from(self) { BitvectorConvertible::from(self.reinterpret_as_int64()) } +///| pub impl BitvectorConvertible for Double with to(bv) { bv.to(0L).reinterpret_as_double() } @@ -143,7 +208,7 @@ pub impl BitvectorConvertible for Double with to(bv) { ///| /// Creates a Bitvector from various number types. /// -pub fn[T: BitvectorConvertible] Bitvector::from(x: T) -> Bitvector { +pub fn[T : BitvectorConvertible] Bitvector::from(x : T) -> Bitvector { x.from() } @@ -152,7 +217,7 @@ pub fn[T: BitvectorConvertible] Bitvector::from(x: T) -> Bitvector { /// /// The argument itself is unused. /// -pub fn[T: BitvectorConvertible] Bitvector::to(self: Bitvector, _x: T) -> T { +pub fn[T : BitvectorConvertible] Bitvector::to(self : Bitvector, _x : T) -> T { T::to(self) } @@ -161,42 +226,41 @@ pub fn[T: BitvectorConvertible] Bitvector::to(self: Bitvector, _x: T) -> T { /// /// The type is either inferred from context, or explicitly noted like `(out(): Int)`. /// -pub fn[T: BitvectorConvertible] Bitvector::out(self: Bitvector) -> T { +pub fn[T : BitvectorConvertible] Bitvector::out(self : Bitvector) -> T { T::to(self) } - ///| /// Create a raw byte representation. This is a **copy**. /// -pub fn Bitvector::raw(self: Bitvector) -> Bytes { +pub fn Bitvector::raw(self : Bitvector) -> Bytes { self.to(b"") } ///| /// Create a raw bytes representation. This is a **reference**. /// -pub fn Bitvector::view(self: Bitvector) -> Array[Byte] { +pub fn Bitvector::view(self : Bitvector) -> Array[Byte] { self.v } ///| /// Reverses the bytes inside the vector. /// -pub fn Bitvector::rev(self: Bitvector) -> Bitvector { +pub fn Bitvector::rev(self : Bitvector) -> Bitvector { { v: self.v.rev() } } +///| test { - let bv = Bitvector::from(2235); - println(bv.to('_')); - println(bv.to(0L)); - println(bv.to(0U)); - println(bv.to(0UL)); - - let bv2 = Bitvector::from(b"hello world".to_array()); - println(bv2.to(0)); - println(bv2.raw()); + let bv = Bitvector::from(2235) + println(bv.to('_')) + println(bv.to(0L)) + println(bv.to(0U)) + println(bv.to(0UL)) + let bv2 = Bitvector::from(b"hello world".to_array()) + println(bv2.to(0)) + println(bv2.raw()) } ///| @@ -206,103 +270,113 @@ test { /// /// The `value` will be truncated when it's too long, and will be sign-extended when it's too short. /// -pub fn[T: BitvectorConvertible] Bitvector::set(self: Bitvector, from: Int, to: Int, value: T) -> Unit { - if (from > to) { - return; +pub fn[T : BitvectorConvertible] Bitvector::set( + self : Bitvector, + from : Int, + to : Int, + value : T, +) -> Unit { + if from > to { + return } - let value = value.from(); - - let cnt = to - from; + let value = value.from() + let cnt = to - from // Clear the bits in the target range. for i in 0..= self.v.length()) { - break; + let byte_idx = (from + i) / 8 + let bit_idx = (from + i) % 8 + if byte_idx >= self.v.length() { + break } - self.v[byte_idx] = (self.v[byte_idx].to_int() & (1 << bit_idx).lnot()).to_byte(); + self.v[byte_idx] = (self.v[byte_idx].to_int() & (1 << bit_idx).lnot()).to_byte() } - + // Set the bits from the value. for i in 0..= self.v.length()) { - break; + let src_byte = i / 8 + let src_bit = i % 8 + let dst_byte = (from + i) / 8 + let dst_bit = (from + i) % 8 + if dst_byte >= self.v.length() { + break + } + let v = if src_byte < value.v.length() { + (value.v[src_byte].to_int() >> src_bit) & 1 + } else { + 0 } - - let v = if (src_byte < value.v.length()) { (value.v[src_byte].to_int() >> src_bit) & 1 } else { 0 }; if v == 1 { - self.v[dst_byte] = (self.v[dst_byte].to_int() | (1 << dst_bit)).to_byte(); + self.v[dst_byte] = (self.v[dst_byte].to_int() | (1 << dst_bit)).to_byte() } } } +///| test "set" { - let v = Bitvector::from(0x22); - v.set(4, 8, Bitvector::from(0xa)); - inspect(v.to(0), content="\{0xa2}"); - v.set(0, 4, Bitvector::from(0x5)); - inspect(v.to(0), content="\{0xa5}"); + let v = Bitvector::from(0x22) + v.set(4, 8, Bitvector::from(0xa)) + inspect(v.to(0), content="\{0xa2}") + v.set(0, 4, Bitvector::from(0x5)) + inspect(v.to(0), content="\{0xa5}") } ///| /// Extracts some bits from this bitvector. Panics on out-of-bound access. /// -pub fn Bitvector::op_as_view(self: Bitvector, start~: Int, end?: Int) -> Bitvector { - let end = if (end is Some(v)) { v } else { self.v.length() * 8 }; - if start >= end || start < 0 { - return { v: [] }; +pub fn Bitvector::op_as_view( + self : Bitvector, + start~ : Int, + end? : Int, +) -> Bitvector { + let end = if end is Some(v) { v } else { self.v.length() * 8 } + if start >= end || start < 0 { + return { v: [] } } - - let cnt = (end - start + 7) / 8; - let res = Array::make(cnt, (0: Byte)); - + let cnt = (end - start + 7) / 8 + let res = Array::make(cnt, (0 : Byte)) for i in 0..<(end - start) { - let src_byte = (start + i) / 8; - let src_bit = (start + i) % 8; - let dst_byte = i / 8; - let dst_bit = i % 8; + let src_byte = (start + i) / 8 + let src_bit = (start + i) % 8 + let dst_byte = i / 8 + let dst_bit = i % 8 if src_byte >= self.v.length() { - break; + break } if ((self.v[src_byte].to_int() >> src_bit) & 1) == 1 { - res[dst_byte] = (res[dst_byte].to_int() | (1 << dst_bit)).to_byte(); + res[dst_byte] = (res[dst_byte].to_int() | (1 << dst_bit)).to_byte() } } - { v: res } } ///| /// Extract a single bit from this bitvector. /// -pub fn Bitvector::op_get(self: Bitvector, pos: Int) -> Int { - self[pos:pos+1].to(0); +pub fn Bitvector::op_get(self : Bitvector, pos : Int) -> Int { + self[pos:pos + 1].to(0) } ///| /// Set a single bit for this bitvector. /// -pub fn Bitvector::op_set(self: Bitvector, pos: Int, val: Bool) -> Unit { +pub fn Bitvector::op_set(self : Bitvector, pos : Int, val : Bool) -> Unit { self.set(pos, pos + 1, val) } +///| test "get" { - let v = Bitvector::from(0xa2); - inspect(v[4:].to(0), content="\{0xa}"); - inspect(v[3], content="0"); - inspect(v[1], content="1"); - v[3] = true; - inspect((v.out(): Int), content="\{0xaa}"); + let v = Bitvector::from(0xa2) + inspect(v[4:].to(0), content="\{0xa}") + inspect(v[3], content="0") + inspect(v[1], content="1") + v[3] = true + inspect((v.out() : Int), content="\{0xaa}") } +///| test "cvt" { - let v = Bitvector::from(0x61); - inspect(v.to(' '), content="a"); - let w = Bitvector::from(0x41200000); // float, 10.0 - inspect(w.to(0.F), content="10"); + let v = Bitvector::from(0x61) + inspect(v.to(' '), content="a") + let w = Bitvector::from(0x41200000) // float, 10.0 + inspect(w.to(0.F), content="10") } diff --git a/src/bitvec/pkg.generated.mbti b/src/bitvec/pkg.generated.mbti new file mode 100644 index 0000000..7cb1ba9 --- /dev/null +++ b/src/bitvec/pkg.generated.mbti @@ -0,0 +1,45 @@ +// Generated using `moon info`, DON'T EDIT IT +package "AdUhTkJm/bitviewer/bitvec" + +// Values + +// Errors + +// Types and methods +pub struct Bitvector { + v : Array[Byte] +} +pub fn[T : BitvectorConvertible] Bitvector::from(T) -> Self +pub fn Bitvector::op_as_view(Self, start~ : Int, end? : Int) -> Self +pub fn Bitvector::op_get(Self, Int) -> Int +pub fn Bitvector::op_set(Self, Int, Bool) -> Unit +pub fn[T : BitvectorConvertible] Bitvector::out(Self) -> T +pub fn Bitvector::raw(Self) -> Bytes +pub fn Bitvector::rev(Self) -> Self +pub fn[T : BitvectorConvertible] Bitvector::set(Self, Int, Int, T) -> Unit +pub fn[T : BitvectorConvertible] Bitvector::to(Self, T) -> T +pub fn Bitvector::view(Self) -> Array[Byte] +pub impl BitvectorConvertible for Bitvector +pub impl Show for Bitvector + +// Type aliases + +// Traits +pub trait BitvectorConvertible { + from(Self) -> Bitvector + to(Bitvector) -> Self +} +pub impl BitvectorConvertible for Bool +pub impl BitvectorConvertible for Byte +pub impl BitvectorConvertible for Char +pub impl BitvectorConvertible for Int +pub impl BitvectorConvertible for Int64 +pub impl BitvectorConvertible for UInt +pub impl BitvectorConvertible for UInt64 +pub impl BitvectorConvertible for Float +pub impl BitvectorConvertible for Double +pub impl BitvectorConvertible for Bytes +pub impl BitvectorConvertible for Array[Byte] +pub impl BitvectorConvertible for ArrayView[Byte] +pub impl BitvectorConvertible for BytesView + diff --git a/src/bitview/bitbuild.mbt b/src/bitview/bitbuild.mbt index 79d4104..294f94a 100644 --- a/src/bitview/bitbuild.mbt +++ b/src/bitview/bitbuild.mbt @@ -3,53 +3,68 @@ /// /// See `extract()` for the details of the specification language. /// -pub fn[T: BitvectorConvertible] Bitviewer::build(spec: String, x: Map[String, T]) -> Bitviewer { +pub fn[T : BitvectorConvertible] Bitviewer::build( + spec : String, + x : Map[String, T], +) -> Bitviewer { (try? Bitviewer::build_malformable(spec, x)).unwrap() } ///| /// Same as `extract()`, but raises an error on malformed specification, rather than panicking. /// -pub fn[T: BitvectorConvertible] Bitviewer::build_malformable(spec: String, x_: Map[String, T]) -> Bitviewer raise Malformed { - let spec = parse_spec(spec); - if (spec.size() == 0) { - return Bitviewer::new(b""); +pub fn[T : BitvectorConvertible] Bitviewer::build_malformable( + spec : String, + x_ : Map[String, T], +) -> Bitviewer raise Malformed { + let spec = parse_spec(spec) + if spec.length() == 0 { + return Bitviewer::new(b"") } - - let x = {}; + let x = {} for k, v in x_ { - x[k] = v.from(); + x[k] = v.from() } - - let places = {}; - let mut from = 0; + let places = {} + let mut from = 0 for k, v in spec { - let len = eval(v.len, x); - places[k] = if (v.from is Some(f)) { let f = eval(f, x); from = f; (f, f + len, v.endian) } else { (from, from + len, v.endian) }; - from += len; + let len = eval(v.len, x) + places[k] = if v.from is Some(f) { + let f = eval(f, x) + from = f + (f, f + len, v.endian) + } else { + (from, from + len, v.endian) + } + from += len } - let max = places.values().map((x) => x.1).maximum().unwrap(); - let bv = Bitvector::from(Array::make((max + 7) / 8, (0: Byte))); + let max = places.values().map(x => x.1).maximum().unwrap() + let bv = Bitvector::from(Array::make((max + 7) / 8, (0 : Byte))) for k, v in places { - let (from, to, endian) = v; - let mut w = if (k.char_at(0) == '=') { - k.to_array()[1:].map((x) => match x { - '0' => false; '1' => true; _ => raise Malformed("'=' expects binary string") - }) |> bit2byte |> Bitvector::from + let (from, to, endian) = v + let mut w = if k.code_unit_at(0) == '='.to_int().to_uint16() { + k.to_array()[1:].map(x => match x { + '0' => false + '1' => true + _ => raise Malformed("'=' expects binary string") + }) + |> bit2byte + |> Bitvector::from } else { - x.get(k).unwrap(); + x.get(k).unwrap() } - if (endian is Big) { - if ((to - from) % 8 != 0) { - raise Malformed("endianness only applies to whole-bytes"); + if endian { + if (to - from) % 8 != 0 { + raise Malformed("endianness only applies to whole-bytes") } - w = w.rev(); + w = w.rev() } - bv.set(from, to, w); + bv.set(from, to, w) } { bytes: bv.raw() } } -pub fn Bitviewer::raw(self: Bitviewer) -> Bitvector { - Bitvector::from(self.bytes); +///| +pub fn Bitviewer::raw(self : Bitviewer) -> Bitvector { + Bitvector::from(self.bytes) } diff --git a/src/bitview/bitbuild_test.mbt b/src/bitview/bitbuild_test.mbt index 1d27637..b71b9cd 100644 --- a/src/bitview/bitbuild_test.mbt +++ b/src/bitview/bitbuild_test.mbt @@ -1,25 +1,24 @@ +///| test "arith" { let spec = -#|h1 : 3*5-4+1; -#|h2 : 4; - - let viewer = Bitviewer::build(spec, { - "h1": 0x234, - "h2": 1 - }); - inspect(viewer.raw(), content=b"\x34\x12".to_string()); - inspect(viewer.raw().to(0), content="\{0x1234}"); + #|h1 : 3*5-4+1; + #|h2 : 4; + let viewer = Bitviewer::build(spec, { "h1": 0x234, "h2": 1 }) + inspect(viewer.raw(), content=b"\x34\x12".to_string()) + inspect(viewer.raw().to(0), content="\{0x1234}") } +///| test "endian" { - let viewer = Bitviewer::build("rev: >32", { "rev": 0x12345678 }); - inspect(viewer.raw(), content=b"\x12\x34\x56\x78".to_string()); + let viewer = Bitviewer::build("rev: >32", { "rev": 0x12345678 }) + inspect(viewer.raw(), content=b"\x12\x34\x56\x78".to_string()) } +///| test "literal" { let viewer = Bitviewer::build("a: 5; =011: 3; b: 6; =01: 2", { "a": 0b10001, - "b": 0b010011 + "b": 0b010011, }) inspect(viewer.raw().to(0), content="\{0b10010011_11010001}") } diff --git a/src/bitview/bitview.mbt b/src/bitview/bitview.mbt index e7b162c..239ac6d 100644 --- a/src/bitview/bitview.mbt +++ b/src/bitview/bitview.mbt @@ -1,22 +1,23 @@ -typealias @bitvec.Bitvector -traitalias @bitvec.BitvectorConvertible +///| +using @bitvec {type Bitvector, trait BitvectorConvertible} +///| struct Bitviewer { - bytes: Bytes + bytes : Bytes } ///| /// Same as `from()`. /// -pub fn[T: BitvectorConvertible] Bitviewer::new(bytes: T) -> Bitviewer { - Bitviewer :: { bytes: T::from(bytes).out() } +pub fn[T : BitvectorConvertible] Bitviewer::new(bytes : T) -> Bitviewer { + Bitviewer::{ bytes: T::from(bytes).out() } } ///| /// Same as `new()`. /// -pub fn[T: BitvectorConvertible] Bitviewer::from(bytes: T) -> Bitviewer { - Bitviewer :: { bytes: T::from(bytes).out() } +pub fn[T : BitvectorConvertible] Bitviewer::from(bytes : T) -> Bitviewer { + Bitviewer::{ bytes: T::from(bytes).out() } } ///| @@ -44,46 +45,50 @@ pub fn[T: BitvectorConvertible] Bitviewer::from(bytes: T) -> Bitviewer { /// /// For floating point fields, just declare their length; `Bitvector` type allows conversion to floating point. /// -pub fn Bitviewer::extract(self: Bitviewer, format: String) -> Map[String, Bitvector] { - let r = try? self.extract_malformable(format); +pub fn Bitviewer::extract( + self : Bitviewer, + format : String, +) -> Map[String, Bitvector] { + let r = try? self.extract_malformable(format) r.unwrap() } ///| /// Works the same as `extract()`, except that it reports an error on malformed specification string. /// -pub fn Bitviewer::extract_malformable(self: Bitviewer, format: String) -> Map[String, Bitvector] raise Malformed { - let spec = parse_spec(format); - let result = {}; - let mut from = 0; +pub fn Bitviewer::extract_malformable( + self : Bitviewer, + format : String, +) -> Map[String, Bitvector] raise Malformed { + let spec = parse_spec(format) + let result = {} + let mut from = 0 for k, v in spec { - if (v.from is Some(v)) { - from = eval(v, result); + if v.from is Some(v) { + from = eval(v, result) } - let len = eval(v.len, result); - - let mut bv = bits(self.bytes, from, len) |> bit2byte |> Bitvector::from; + let len = eval(v.len, result) + let mut bv = bits(self.bytes, from, len) |> bit2byte |> Bitvector::from // Currently we default to little endian. Perhaps make it configurable in the future. - if (v.endian is Big) { - if (len % 8 != 0) { - raise Malformed("endianness only applies to whole-bytes"); + if v.endian { + if len % 8 != 0 { + raise Malformed("endianness only applies to whole-bytes") } - bv = bv.rev(); + bv = bv.rev() } - result[k] = bv; - from += len; + result[k] = bv + from += len } result } -fn bits(bytes: Bytes, from: Int, len: Int) -> Array[Bool] { +///| +fn bits(bytes : Bytes, from : Int, len : Int) -> Array[Bool] { let result = Array::new(capacity=len) - for i = 0; i < len; i = i + 1 { let bit_pos = from + i let ind = bit_pos / 8 let offset = bit_pos % 8 - if ind < bytes.length() { let byte_val = bytes[ind] let bit = (byte_val.to_int() >> offset) & 1 @@ -92,26 +97,22 @@ fn bits(bytes: Bytes, from: Int, len: Int) -> Array[Bool] { result.push(false) } } - result } -fn bit2byte(bits: Array[Bool]) -> Array[Byte] { +///| +fn bit2byte(bits : Array[Bool]) -> Array[Byte] { let byte_cnt = (bits.length() + 7) / 8 let result = Array::new(capacity=byte_cnt) - for i in 0..16; -#|d : 3; - - let viewer = Bitviewer::new(Bitvector::from(0b110_1000110111001111_0010011011011001_0010110L).raw()) - let map = viewer.extract(spec); - inspect(map.get("a").unwrap().to(0), content="\{0b0010110}"); - inspect(map.get("b").unwrap().to(0), content="\{0b0010011011011001}"); - inspect(map.get("c").unwrap().to(0), content="\{0b1100111110001101}"); - inspect(map.get("d").unwrap().to(0), content="\{0b110}"); + #|a : 7; + #|b : <16; + #|c : >16; + #|d : 3; + let viewer = Bitviewer::new( + Bitvector::from(0b110_1000110111001111_0010011011011001_0010110L).raw(), + ) + let map = viewer.extract(spec) + inspect(map.get("a").unwrap().to(0), content="\{0b0010110}") + inspect(map.get("b").unwrap().to(0), content="\{0b0010011011011001}") + inspect(map.get("c").unwrap().to(0), content="\{0b1100111110001101}") + inspect(map.get("d").unwrap().to(0), content="\{0b110}") } +///| test "ref" { let spec = -#|length: 8; -#|string: length*8; - - let viewer = Bitviewer::new(b"\x05abcde"); - let map = viewer.extract(spec); - inspect(map.get("length").unwrap().to(0), content="5"); - println(map.get("string")); // Some(b"\x61...\x65"), which is indeed "abcde" -} + #|length: 8; + #|string: length*8; + let viewer = Bitviewer::new(b"\x05abcde") + let map = viewer.extract(spec) + inspect(map.get("length").unwrap().to(0), content="5") + println(map.get("string")) +} // Some(b"\x61...\x65"), which is indeed "abcde" +///| test "range" { let spec = -#|opcode: 0..6; -#|rd : 7..11; -#|funct3: 12..14; -#|rs : 15..19; -#|rs2 : 20..24; -#|funct7: 25..31; + #|opcode: 0..6; + #|rd : 7..11; + #|funct3: 12..14; + #|rs : 15..19; + #|rs2 : 20..24; + #|funct7: 25..31; // RISC-V: add x5, x10, x22 // opcode = 0b0110011 (0x33), funct3 = funct7 = 0 - let viewer = Bitviewer::new(Bitvector::from(0x016502b3).raw()); - let map = viewer.extract(spec); - inspect(map, content={ - "opcode": b"\x33", - "rd": b"\x05", - "funct3": b"\x00", - "rs": b"\x0a", // 10 - "rs2": b"\x16", // 22 - "funct7": b"\x00", - }.to_string()) + let viewer = Bitviewer::new(Bitvector::from(0x016502b3).raw()) + let map = viewer.extract(spec) + inspect( + map, + content={ + "opcode": b"\x33", + "rd": b"\x05", + "funct3": b"\x00", + "rs": b"\x0a", // 10 + "rs2": b"\x16", // 22 + "funct7": b"\x00", + }.to_string(), + ) } diff --git a/src/bitview/format-parser.mbt b/src/bitview/format-parser.mbt index f1d5c2c..4f65a2b 100644 --- a/src/bitview/format-parser.mbt +++ b/src/bitview/format-parser.mbt @@ -1,34 +1,44 @@ -priv enum Endianness { Little; Big; Unspecified } derive(Show) +///| +type Endianness = Bool // true for Big, false for Little +///| priv enum Kind { - Add; Sub; Mul; Div; + Add + Sub + Mul + Div } derive(Show) +///| priv enum Expr { Const(Int) Var(String) Binary(Kind, Expr, Expr) } derive(Show) +///| priv struct Spec { - endian: Endianness - from: Expr? - len: Expr -} derive(Show) + endian : Endianness + from : Expr? + len : Expr +} -pub suberror Malformed(String) derive(Show) +///| +pub suberror Malformed String derive(Show) -fn disspace(str: String) -> Array[Char] { +///| +fn disspace(str : String) -> Array[Char] { let chars = str.to_array() - chars.filter((x) => not(x.is_whitespace())); + chars.filter(x => not(x.is_whitespace())) } -fn primary(lexer: Lexer) -> Expr raise Malformed { +///| +fn primary(lexer : Lexer) -> Expr raise Malformed { match lexer.peek() { '0'..='9' => Const(lexer.number()) '(' => { - let x = expr(lexer); - if (lexer.ch() != ')') { + let x = expr(lexer) + if lexer.ch() != ')' { raise Malformed("unclosed parentheses") } x @@ -37,84 +47,97 @@ fn primary(lexer: Lexer) -> Expr raise Malformed { } } -fn mul(lexer: Lexer) -> Expr raise Malformed { - let mut n = primary(lexer); - while (lexer.pos < lexer.chars.length()) { +///| +fn mul(lexer : Lexer) -> Expr raise Malformed { + let mut n = primary(lexer) + while lexer.pos < lexer.chars.length() { match lexer.ch() { '*' => { - let x = primary(lexer); - n = Binary(Mul, n, x); + let x = primary(lexer) + n = Binary(Mul, n, x) } '/' => { - let x = primary(lexer); - n = Binary(Div, n, x); + let x = primary(lexer) + n = Binary(Div, n, x) + } + _ => { + lexer.pos -= 1 + break } - _ => { lexer.pos -= 1; break; } } } n } -fn add(lexer: Lexer) -> Expr raise Malformed { - let mut n = mul(lexer); - while (lexer.pos < lexer.chars.length()) { +///| +fn add(lexer : Lexer) -> Expr raise Malformed { + let mut n = mul(lexer) + while lexer.pos < lexer.chars.length() { match lexer.ch() { '+' => { - let x = mul(lexer); - n = Binary(Add, n, x); + let x = mul(lexer) + n = Binary(Add, n, x) } '-' => { - let x = mul(lexer); - n = Binary(Sub, n, x); + let x = mul(lexer) + n = Binary(Sub, n, x) + } + _ => { + lexer.pos -= 1 + break } - _ => { lexer.pos -= 1; break; } } } n } -fn expr(lexer: Lexer) -> Expr raise Malformed { +///| +fn expr(lexer : Lexer) -> Expr raise Malformed { add(lexer) } -fn parse(spec: ArrayView[Char]) -> Spec raise Malformed { - let mut place = 0; - let peek = () => spec[place]; - +///| +fn parse(spec : ArrayView[Char]) -> Spec raise Malformed { + let mut place = 0 + let peek = () => spec[place] let endian = match peek() { - '>' => { place += 1; Big } - '<' => { place += 1; Little } - _ => Unspecified - }; - - let lexer = { chars: Array::from_iter(spec[place:].iter()), pos: 0 }; - let mut len = expr(lexer); - let mut from = None; - if (lexer.check("..")) { - from = Some(len); + '>' => { + place += 1 + true + } + '<' => { + place += 1 + false + } + _ => false + } + let lexer = { chars: Array::from_iter(spec[place:].iter()), pos: 0 } + let mut len = expr(lexer) + let mut from = None + if lexer.check("..") { + from = Some(len) // len = stop - start + 1 (inclusive) - len = Binary(Add, Const(1), Binary(Sub, expr(lexer), len)); + len = Binary(Add, Const(1), Binary(Sub, expr(lexer), len)) } - { endian, from, len } } -fn parse_spec(str: String) -> Map[String, Spec] raise Malformed { - let fields = disspace(str).split((x) => x == ';'); - let result = {}; +///| +fn parse_spec(str : String) -> Map[String, Spec] raise Malformed { + let fields = disspace(str).split(x => x == ';') + let result = {} for field in fields { - let colon = field.search_by((x) => x == ':'); - guard (colon is Some(ind)) else { - raise Malformed("missing colon"); - } - let name = field[:ind]; - let spec = parse(field[ind+1:]); - result[String::from_iter(name.iter())] = spec; + let colon = field.search_by(x => x == ':') + guard colon is Some(ind) else { raise Malformed("missing colon") } + let name = field[:ind] + let spec = parse(field[ind + 1:]) + result[String::from_iter(name.iter())] = spec } result } -fn eval(expr: Expr, k: Map[String, @bitvec.Bitvector]) -> Int { +///| +fn eval(expr : Expr, k : Map[String, @bitvec.Bitvector]) -> Int { match expr { Binary(Add, x, y) => eval(x, k) + eval(y, k) Binary(Sub, x, y) => eval(x, k) - eval(y, k) diff --git a/src/bitview/lexer.mbt b/src/bitview/lexer.mbt index 5ec00cc..581bc8f 100644 --- a/src/bitview/lexer.mbt +++ b/src/bitview/lexer.mbt @@ -1,52 +1,54 @@ +///| priv struct Lexer { - chars: Array[Char] - mut pos: Int + chars : Array[Char] + mut pos : Int } -fn Lexer::ch(self: Lexer) -> Char raise Malformed { - if (self.pos == self.chars.length()) { +///| +fn Lexer::ch(self : Lexer) -> Char raise Malformed { + if self.pos == self.chars.length() { raise Malformed("unexpected end of statement") } let c = self.chars[self.pos] - self.pos += 1; + self.pos += 1 c } -fn Lexer::peek(self: Lexer) -> Char raise Malformed { - if (self.pos == self.chars.length()) { +///| +fn Lexer::peek(self : Lexer) -> Char raise Malformed { + if self.pos == self.chars.length() { raise Malformed("unexpected end of statement") } self.chars[self.pos] } -fn Lexer::number(self: Lexer) -> Int raise Malformed { +///| +fn Lexer::number(self : Lexer) -> Int raise Malformed { let digits = [] while self.pos < self.chars.length() && self.chars[self.pos].is_digit(10) { digits.push(self.chars[self.pos]) self.pos += 1 } - if digits.is_empty() { raise Malformed("expected digit") } - let number_str = String::from_iter(digits.iter()) - match (try? @strconv.parse_int(number_str)) { - Ok(num) => num - Err(_) => raise Malformed("invalid number: \{number_str}") + try @strconv.parse_int(number_str) catch { + _ => raise Malformed("invalid number: \{number_str}") + } noraise { + num => num } } -fn Lexer::ident(self: Lexer) -> String raise Malformed { +///| +fn Lexer::ident(self : Lexer) -> String raise Malformed { if self.pos >= self.chars.length() { raise Malformed("expected identifier") } - let first_char = self.chars[self.pos] if not(first_char.is_ascii_alphabetic() || first_char == '_') { raise Malformed("identifier must start with letter or underscore") } - let chars = [] while self.pos < self.chars.length() { let c = self.chars[self.pos] @@ -57,24 +59,30 @@ fn Lexer::ident(self: Lexer) -> String raise Malformed { break } } - if chars.is_empty() { raise Malformed("expected identifier") } - String::from_iter(chars.iter()) } -fn Lexer::check(self: Lexer, str: String) -> Bool { - if (self.pos + str.length() > self.chars.length()) { - return false; +///| +fn Lexer::check(self : Lexer, str : String) -> Bool { + if self.pos + str.length() > self.chars.length() { + return false } - let old = self.pos; + let old = self.pos for i in str { - if ((try? self.ch()).unwrap() != i) { - self.pos -= 1; - self.pos = old; - return false; + try self.ch() catch { + _ => { + self.pos = old + return false + } + } noraise { + c => + if c != i { + self.pos = old + return false + } } } true diff --git a/src/bitview/pkg.generated.mbti b/src/bitview/pkg.generated.mbti new file mode 100644 index 0000000..25cf42c --- /dev/null +++ b/src/bitview/pkg.generated.mbti @@ -0,0 +1,27 @@ +// Generated using `moon info`, DON'T EDIT IT +package "AdUhTkJm/bitviewer/bitview" + +import( + "AdUhTkJm/bitviewer/bitvec" +) + +// Values + +// Errors +pub suberror Malformed String +pub impl Show for Malformed + +// Types and methods +type Bitviewer +pub fn[T : @bitvec.BitvectorConvertible] Bitviewer::build(String, Map[String, T]) -> Self +pub fn[T : @bitvec.BitvectorConvertible] Bitviewer::build_malformable(String, Map[String, T]) -> Self raise Malformed +pub fn Bitviewer::extract(Self, String) -> Map[String, @bitvec.Bitvector] +pub fn Bitviewer::extract_malformable(Self, String) -> Map[String, @bitvec.Bitvector] raise Malformed +pub fn[T : @bitvec.BitvectorConvertible] Bitviewer::from(T) -> Self +pub fn[T : @bitvec.BitvectorConvertible] Bitviewer::new(T) -> Self +pub fn Bitviewer::raw(Self) -> @bitvec.Bitvector + +// Type aliases + +// Traits +