[sc-548] Add support for i24 and f24

This commit is contained in:
Nicolas Abril 2024-05-03 18:48:52 +02:00
parent ba748c95e8
commit 03fcf344f1
26 changed files with 452 additions and 137 deletions

View File

@ -61,6 +61,7 @@
"peekable", "peekable",
"postcondition", "postcondition",
"prec", "prec",
"powi",
"readback", "readback",
"recursively", "recursively",
"redex", "redex",

View File

@ -13,8 +13,12 @@
(SwapGT _ v x xs) = (List.cons x (Insert v xs)) (SwapGT _ v x xs) = (List.cons x (Insert v xs))
// Generates a random list // Generates a random list
(Rnd 0 s) = [] (Rnd 0 s) = List.nil
(Rnd n s) = (List.cons s (Rnd (- n 1) (% (+ (* s 1664525) 1013904223) 4294967295))) (Rnd n s) =
let s = (^ s (* s 0b10000000000000))
let s = (^ s (/ s 0b100000000000000000))
let s = (^ s (* s 0b100000))
(List.cons s (Rnd (- n 1) s))
// Sums a list // Sums a list
(Sum []) = 0 (Sum []) = 0
@ -22,7 +26,7 @@
(Main) = (Main) =
let n = 10 let n = 10
(Sum (Sort (Rnd (* 2 50) n))) (Sum (Sort (Rnd 0x100 n)))
// Use an argument from cli // Use an argument from cli
// (Main n) = (Sum (Sort (Rnd (* 2 50) n))) // (Main n) = (Sum (Sort (Rnd 0x100 n)))

View File

@ -17,8 +17,12 @@ data Tree = Leaf | (Node l m r)
(Push _ x pair) = (pair λmin λmax λp (p min (List.cons x max))) (Push _ x pair) = (pair λmin λmax λp (p min (List.cons x max)))
// Generates a random list // Generates a random list
(Rnd 0 s) = (List.nil) (Rnd 0 s) = List.nil
(Rnd n s) = (List.cons s (Rnd (- n 1) (% (+ (* s 1664525) 1013904223) 4294967295))) (Rnd n s) =
let s = (^ s (* s 0b10000000000000))
let s = (^ s (/ s 0b100000000000000000))
let s = (^ s (* s 0b100000))
(List.cons s (Rnd (- n 1) s))
// Sums all elements in a concatenation tree // Sums all elements in a concatenation tree
(Sum Leaf) = 0 (Sum Leaf) = 0
@ -26,8 +30,7 @@ data Tree = Leaf | (Node l m r)
// Sorts and sums n random numbers // Sorts and sums n random numbers
(Main) = (Main) =
let n = 12 (Sum (Sort (Rnd 0x100 1)))
(Sum (Sort (Rnd (* 2 n) 1)))
// Use an argument from cli // Use an argument from cli
// (Main n) = (Sum (Sort (Rnd (<< 1 n) 1))) // (Main n) = (Sum (Sort (Rnd (<< 1 n) 1)))

View File

@ -36,45 +36,44 @@ data Arr = Null | (Leaf x) | (Node a b)
// Radix : U60 -> Map // Radix : U60 -> Map
(Radix n) = (Radix n) =
let r = Used let r = Used
let r = (Swap (& n 1) r Free) let r = (Swap (& n 0x1) r Free)
let r = (Swap (& n 2) r Free) let r = (Swap (& n 0x2) r Free)
let r = (Swap (& n 4) r Free) let r = (Swap (& n 0x4) r Free)
let r = (Swap (& n 8) r Free) let r = (Swap (& n 0x8) r Free)
let r = (Swap (& n 16) r Free) let r = (Swap (& n 0x10) r Free)
(Radix2 n r) (Radix2 n r)
(Radix2 n r) = (Radix2 n r) =
let r = (Swap (& n 32) r Free) let r = (Swap (& n 0x20) r Free)
let r = (Swap (& n 64) r Free) let r = (Swap (& n 0x40) r Free)
let r = (Swap (& n 128) r Free) let r = (Swap (& n 0x80) r Free)
let r = (Swap (& n 256) r Free) let r = (Swap (& n 0x100) r Free)
let r = (Swap (& n 512) r Free) let r = (Swap (& n 0x200) r Free)
(Radix3 n r) (Radix3 n r)
(Radix3 n r) = (Radix3 n r) =
let r = (Swap (& n 1024) r Free) let r = (Swap (& n 0x400) r Free)
let r = (Swap (& n 2048) r Free) let r = (Swap (& n 0x800) r Free)
let r = (Swap (& n 4096) r Free) let r = (Swap (& n 0x1000) r Free)
let r = (Swap (& n 8192) r Free) let r = (Swap (& n 0x2000) r Free)
let r = (Swap (& n 16384) r Free) let r = (Swap (& n 0x4000) r Free)
(Radix4 n r) (Radix4 n r)
(Radix4 n r) = (Radix4 n r) =
let r = (Swap (& n 32768) r Free) let r = (Swap (& n 0x8000) r Free)
let r = (Swap (& n 65536) r Free) let r = (Swap (& n 0x10000) r Free)
let r = (Swap (& n 131072) r Free) let r = (Swap (& n 0x20000) r Free)
let r = (Swap (& n 262144) r Free) let r = (Swap (& n 0x40000) r Free)
let r = (Swap (& n 524288) r Free) let r = (Swap (& n 0x80000) r Free)
(Radix5 n r) (Radix5 n r)
(Radix5 n r) = (Radix5 n r) =
let r = (Swap (& n 1048576) r Free) let r = (Swap (& n 0x100000) r Free)
let r = (Swap (& n 2097152) r Free) let r = (Swap (& n 0x200000) r Free)
let r = (Swap (& n 4194304) r Free) let r = (Swap (& n 0x400000) r Free)
let r = (Swap (& n 8388608) r Free) let r = (Swap (& n 0x800000) r Free)
r r
// Reverse : Arr -> Arr // Reverse : Arr -> Arr
(Reverse Null) = Null (Reverse Null) = Null
(Reverse (Leaf a)) = (Leaf a) (Reverse (Leaf a)) = (Leaf a)

View File

@ -1,4 +1,4 @@
use super::{parser::TermParser, Book, Name, NumType, Pattern, Term}; use super::{parser::TermParser, Book, Name, Num, Pattern, Term};
use crate::maybe_grow; use crate::maybe_grow;
const BUILTINS: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/term/builtins.hvm")); const BUILTINS: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/term/builtins.hvm"));
@ -62,11 +62,11 @@ impl Term {
pub fn encode_str(val: &str) -> Term { pub fn encode_str(val: &str) -> Term {
val.chars().rfold(Term::r#ref(SNIL), |acc, char| { val.chars().rfold(Term::r#ref(SNIL), |acc, char| {
Term::call(Term::r#ref(SCONS), [Term::Num { typ: NumType::U24, val: char as u32 }, acc]) Term::call(Term::r#ref(SCONS), [Term::Num { val: Num::U24(char as u32 & 0x00ff_ffff) }, acc])
}) })
} }
pub fn encode_nat(val: u64) -> Term { pub fn encode_nat(val: u32) -> Term {
(0 .. val).fold(Term::r#ref(NAT_ZERO), |acc, _| Term::app(Term::r#ref(NAT_SUCC), acc)) (0 .. val).fold(Term::r#ref(NAT_ZERO), |acc, _| Term::app(Term::r#ref(NAT_SUCC), acc))
} }

View File

@ -1,4 +1,4 @@
use super::{Book, Definition, FanKind, Name, Op, Pattern, Rule, Tag, Term}; use super::{Book, Definition, FanKind, Name, Num, Op, Pattern, Rule, Tag, Term};
use crate::maybe_grow; use crate::maybe_grow;
use std::{fmt, ops::Deref}; use std::{fmt, ops::Deref};
@ -114,7 +114,9 @@ impl fmt::Display for Term {
Term::Fan { fan: FanKind::Tup, tag, els } => write!(f, "{}({})", tag, DisplayJoin(|| els.iter(), ", ")), Term::Fan { fan: FanKind::Tup, tag, els } => write!(f, "{}({})", tag, DisplayJoin(|| els.iter(), ", ")),
Term::Fan { fan: FanKind::Dup, tag, els } => write!(f, "{}{{{}}}", tag, DisplayJoin(|| els, " ")), Term::Fan { fan: FanKind::Dup, tag, els } => write!(f, "{}{{{}}}", tag, DisplayJoin(|| els, " ")),
Term::Era => write!(f, "*"), Term::Era => write!(f, "*"),
Term::Num { typ: _, val } => write!(f, "{val}"), Term::Num { val: Num::U24(val) } => write!(f, "{val}"),
Term::Num { val: Num::I24(val) } => write!(f, "{}{}", if *val < 0 { "-" } else { "+" }, val.abs()),
Term::Num { val: Num::F24(val) } => write!(f, "{val:.3}"),
Term::Nat { val } => write!(f, "#{val}"), Term::Nat { val } => write!(f, "#{val}"),
Term::Str { val } => write!(f, "{val:?}"), Term::Str { val } => write!(f, "{val:?}"),
Term::Opr { opr, fst, snd } => { Term::Opr { opr, fst, snd } => {
@ -374,7 +376,9 @@ impl Term {
} }
Term::Nat { val } => write!(f, "#{val}"), Term::Nat { val } => write!(f, "#{val}"),
Term::Num { typ: _, val } => write!(f, "{val}"), Term::Num { val: Num::U24(val) } => write!(f, "{val}"),
Term::Num { val: Num::I24(val) } => write!(f, "{}{}", if *val < 0 { "-" } else { "+" }, val.abs()),
Term::Num { val: Num::F24(val) } => write!(f, "{val:.3}"),
Term::Str { val } => write!(f, "{val:?}"), Term::Str { val } => write!(f, "{val:?}"),
Term::Ref { nam } => write!(f, "{nam}"), Term::Ref { nam } => write!(f, "{nam}"),
Term::Era => write!(f, "*"), Term::Era => write!(f, "*"),

View File

@ -2,7 +2,7 @@ use indexmap::IndexMap;
use crate::term::Name; use crate::term::Name;
use super::{Definition, Enum, Program, Stmt, Term, Variant}; use super::{Definition, Enum, MBind, Program, Stmt, Term, Variant};
struct Ctx<'a> { struct Ctx<'a> {
variants: &'a IndexMap<Name, Name>, variants: &'a IndexMap<Name, Name>,
@ -58,9 +58,26 @@ impl Stmt {
arm.rgt.order_kwargs(ctx); arm.rgt.order_kwargs(ctx);
} }
} }
Stmt::Switch { .. } => unimplemented!(), Stmt::Switch { arg, arms, .. } => {
Stmt::Fold { .. } => unimplemented!(), arg.order_kwargs(ctx);
Stmt::Do { .. } => unimplemented!(), for arm in arms {
arm.order_kwargs(ctx);
}
}
Stmt::Fold { arg, arms, .. } => {
arg.order_kwargs(ctx);
for arm in arms {
arm.rgt.order_kwargs(ctx);
}
}
Stmt::Do { block, .. } => {
for bind in block {
match bind {
MBind::Ask { val, .. } => val.order_kwargs(ctx),
MBind::Stmt { stmt } => stmt.order_kwargs(ctx),
}
}
}
Stmt::Return { term } => term.order_kwargs(ctx), Stmt::Return { term } => term.order_kwargs(ctx),
} }
} }

View File

@ -88,7 +88,7 @@ impl Term {
match self { match self {
Term::None => lang::Term::Era, Term::None => lang::Term::Era,
Term::Var { nam } => lang::Term::Var { nam }, Term::Var { nam } => lang::Term::Var { nam },
Term::Num { val } => lang::Term::Num { typ: lang::NumType::U24, val }, Term::Num { val } => lang::Term::Num { val: lang::Num::U24(val) },
Term::Call { fun, args, kwargs } => { Term::Call { fun, args, kwargs } => {
assert!(kwargs.is_empty()); assert!(kwargs.is_empty());
let args = args.into_iter().map(Self::to_lang); let args = args.into_iter().map(Self::to_lang);

View File

@ -7,7 +7,7 @@ use crate::{
use indexmap::{IndexMap, IndexSet}; use indexmap::{IndexMap, IndexSet};
use interner::global::{GlobalPool, GlobalString}; use interner::global::{GlobalPool, GlobalString};
use itertools::Itertools; use itertools::Itertools;
use std::{borrow::Cow, collections::HashMap, ops::Deref}; use std::{borrow::Cow, collections::HashMap, hash::Hash, ops::Deref};
pub mod builtins; pub mod builtins;
pub mod check; pub mod check;
@ -63,7 +63,7 @@ pub struct Definition {
} }
/// A pattern matching rule of a definition. /// A pattern matching rule of a definition.
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Default, PartialEq)]
pub struct Rule { pub struct Rule {
pub pats: Vec<Pattern>, pub pats: Vec<Pattern>,
pub body: Term, pub body: Term,
@ -110,11 +110,10 @@ pub enum Term {
els: Vec<Term>, els: Vec<Term>,
}, },
Num { Num {
typ: NumType, val: Num,
val: u32,
}, },
Nat { Nat {
val: u64, val: u32,
}, },
Str { Str {
val: GlobalString, val: GlobalString,
@ -181,11 +180,11 @@ pub enum Op {
POW, POW,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy)]
pub enum NumType { pub enum Num {
U24 = 1, U24(u32),
I24 = 2, I24(i32),
F24 = 3, F24(f32),
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -328,7 +327,7 @@ impl Clone for Term {
Self::Use { nam, val, nxt } => Self::Use { nam: nam.clone(), val: val.clone(), nxt: nxt.clone() }, Self::Use { nam, val, nxt } => Self::Use { nam: nam.clone(), val: val.clone(), nxt: nxt.clone() },
Self::App { tag, fun, arg } => Self::App { tag: tag.clone(), fun: fun.clone(), arg: arg.clone() }, Self::App { tag, fun, arg } => Self::App { tag: tag.clone(), fun: fun.clone(), arg: arg.clone() },
Self::Fan { fan, tag, els } => Self::Fan { fan: *fan, tag: tag.clone(), els: els.clone() }, Self::Fan { fan, tag, els } => Self::Fan { fan: *fan, tag: tag.clone(), els: els.clone() },
Self::Num { typ, val } => Self::Num { typ: *typ, val: *val }, Self::Num { val } => Self::Num { val: *val },
Self::Nat { val } => Self::Nat { val: *val }, Self::Nat { val } => Self::Nat { val: *val },
Self::Str { val } => Self::Str { val: val.clone() }, Self::Str { val } => Self::Str { val: val.clone() },
Self::Lst { els } => Self::Lst { els: els.clone() }, Self::Lst { els } => Self::Lst { els: els.clone() },
@ -436,19 +435,19 @@ impl Term {
Term::Str { val: STRINGS.get(str) } Term::Str { val: STRINGS.get(str) }
} }
pub fn sub_num(arg: Term, val: u32, typ: NumType) -> Term { pub fn sub_num(arg: Term, val: Num) -> Term {
if val == 0 { if val.is_zero() {
arg arg
} else { } else {
Term::Opr { opr: Op::SUB, fst: Box::new(arg), snd: Box::new(Term::Num { typ, val }) } Term::Opr { opr: Op::SUB, fst: Box::new(arg), snd: Box::new(Term::Num { val }) }
} }
} }
pub fn add_num(arg: Term, val: u32, typ: NumType) -> Term { pub fn add_num(arg: Term, val: Num) -> Term {
if val == 0 { if val.is_zero() {
arg arg
} else { } else {
Term::Opr { opr: Op::ADD, fst: Box::new(arg), snd: Box::new(Term::Num { typ, val }) } Term::Opr { opr: Op::ADD, fst: Box::new(arg), snd: Box::new(Term::Num { val }) }
} }
} }
@ -800,6 +799,71 @@ impl Term {
} }
} }
impl Num {
pub fn is_zero(&self) -> bool {
match self {
Num::U24(val) => *val == 0,
Num::I24(val) => *val == 0,
Num::F24(val) => *val == 0.0,
}
}
pub fn to_bits(&self) -> u32 {
match self {
Num::U24(val) => {
assert!(*val <= 0xFFFFFF);
((val & 0xFFFFFF) << 4) | 0x1
}
Num::I24(val) => (((*val as u32) & 0xFFFFFF) << 4) | 0x2,
Num::F24(val) => {
let bits = val.to_bits();
let sign = (bits >> 31) & 0x1;
let expo = (bits >> 23) & 0xFF;
let mantissa = bits & 0x7FFFFF;
assert!(
(expo == 0) || (expo == 255) || (64 ..= 127).contains(&expo) || (128 ..= 190).contains(&expo)
);
let expo = (expo & 0b0011_1111) | ((expo >> 7) << 6);
let mantissa = mantissa >> 7;
let bits = (sign << 23) | (expo << 16) | mantissa;
(bits << 4) | 0x3
}
}
}
pub fn from_bits(bits: u32) -> Self {
match bits & 0xF {
0x1 => Num::U24((bits >> 4) & 0xFFFFFF),
0x2 => Num::I24((((bits >> 4) & 0xFFFFFF) as i32) << 8 >> 8),
0x3 => {
let bits = (bits >> 4) & 0xFFFFFF;
let sign = (bits >> 23) & 0x1;
let expo = (bits >> 16) & 0x7F;
let mantissa = bits & 0xFFFF;
let i_exp = (expo as i32) - 63;
let bits = (sign << 31) | (((i_exp + 127) as u32) << 23) | (mantissa << 7);
let bits = if mantissa == 0 && i_exp == -63 { sign << 31 } else { bits };
Num::F24(f32::from_bits(bits))
}
_ => unreachable!("Invalid Num bits"),
}
}
}
impl Hash for Num {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.to_bits().hash(state);
}
}
impl PartialEq for Num {
fn eq(&self, other: &Self) -> bool {
self.to_bits() == other.to_bits()
}
}
impl Eq for Num {}
impl Pattern { impl Pattern {
pub fn binds(&self) -> impl DoubleEndedIterator<Item = &Option<Name>> + Clone { pub fn binds(&self) -> impl DoubleEndedIterator<Item = &Option<Name>> + Clone {
self.iter().filter_map(|pat| match pat { self.iter().filter_map(|pat| match pat {
@ -862,7 +926,7 @@ impl Pattern {
Pattern::Ctr(ctr, args) => { Pattern::Ctr(ctr, args) => {
Term::call(Term::Ref { nam: ctr.clone() }, args.iter().map(|arg| arg.to_term())) Term::call(Term::Ref { nam: ctr.clone() }, args.iter().map(|arg| arg.to_term()))
} }
Pattern::Num(val) => Term::Num { typ: NumType::U24, val: *val }, Pattern::Num(val) => Term::Num { val: Num::U24(*val) },
Pattern::Fan(fan, tag, args) => { Pattern::Fan(fan, tag, args) => {
Term::Fan { fan: *fan, tag: tag.clone(), els: args.iter().map(|p| p.to_term()).collect() } Term::Fan { fan: *fan, tag: tag.clone(), els: args.iter().map(|p| p.to_term()).collect() }
} }
@ -960,3 +1024,35 @@ impl Book {
} }
} }
} }
#[test]
fn num_to_from_bits() {
let a = [
Num::U24(0),
Num::I24(0),
Num::F24(0.0),
Num::U24(0xFFFFFF),
Num::I24(0xFFFFFF),
Num::F24(0xFFFFFF as f32),
Num::U24(12345),
Num::I24(12345),
Num::I24(-12345),
Num::I24(-0),
Num::F24(0.0),
Num::F24(-0.0),
Num::F24(0.00123),
Num::F24(12345.023),
Num::F24(-1235.3849),
Num::F24(1.0),
Num::F24(-1.0),
Num::F24(12323658716.0),
Num::F24(-12323658716.0),
Num::F24(-0.00000000000000001),
Num::F24(0.00000000000000001),
Num::F24(5447856134985749851.3457896137815694178),
Num::F24(-5447856134985749851.3457896137815694178),
];
for b in a {
assert_eq!(b, Num::from_bits(Num::to_bits(&b)));
}
}

View File

@ -1,17 +1,12 @@
use crate::{ use crate::{
diagnostics::{DiagnosticOrigin, Diagnostics, Severity}, diagnostics::{DiagnosticOrigin, Diagnostics, Severity},
maybe_grow, maybe_grow,
net::{ net::{CtrKind, INet, NodeId, NodeKind, Port, SlotId, ROOT},
CtrKind::*, term::{num_to_name, term_to_net::Labels, Book, FanKind, Name, Op, Pattern, Tag, Term},
INet, NodeId,
NodeKind::{self, *},
Port, SlotId, ROOT,
},
term::{num_to_name, term_to_net::Labels, Book, FanKind, Name, Pattern, Tag, Term},
}; };
use std::collections::{BTreeSet, HashMap, HashSet}; use std::collections::{BTreeSet, HashMap, HashSet};
use super::{NumType, Op}; use super::Num;
/// Converts an Interaction-INet to a Lambda Calculus term /// Converts an Interaction-INet to a Lambda Calculus term
pub fn net_to_term( pub fn net_to_term(
@ -41,8 +36,8 @@ pub fn net_to_term(
let snd = reader.namegen.decl_name(net, Port(node, 2)); let snd = reader.namegen.decl_name(net, Port(node, 2));
let (fan, tag) = match reader.net.node(node).kind { let (fan, tag) = match reader.net.node(node).kind {
Ctr(Tup(lab)) => (FanKind::Tup, reader.labels.tup.to_tag(lab)), NodeKind::Ctr(CtrKind::Tup(lab)) => (FanKind::Tup, reader.labels.tup.to_tag(lab)),
Ctr(Dup(lab)) => (FanKind::Dup, reader.labels.dup.to_tag(Some(lab))), NodeKind::Ctr(CtrKind::Dup(lab)) => (FanKind::Dup, reader.labels.dup.to_tag(Some(lab))),
_ => unreachable!(), _ => unreachable!(),
}; };
@ -81,6 +76,8 @@ pub struct Reader<'a> {
impl Reader<'_> { impl Reader<'_> {
fn read_term(&mut self, next: Port) -> Term { fn read_term(&mut self, next: Port) -> Term {
use CtrKind::*;
maybe_grow(|| { maybe_grow(|| {
if self.dup_paths.is_none() && !self.seen.insert(next) { if self.dup_paths.is_none() && !self.seen.insert(next) {
self.error(ReadbackError::Cyclic); self.error(ReadbackError::Cyclic);
@ -88,15 +85,14 @@ impl Reader<'_> {
} }
let node = next.node(); let node = next.node();
match &self.net.node(node).kind { match &self.net.node(node).kind {
Era => { NodeKind::Era => {
// Only the main port actually exists in an ERA, the aux ports are just an artifact of this representation. // Only the main port actually exists in an ERA, the aux ports are just an artifact of this representation.
debug_assert!(next.slot() == 0); debug_assert!(next.slot() == 0);
Term::Era Term::Era
} }
// If we're visiting a con node... // If we're visiting a con node...
Ctr(Con(lab)) => match next.slot() { NodeKind::Ctr(CtrKind::Con(lab)) => match next.slot() {
// If we're visiting a port 0, then it is a lambda. // If we're visiting a port 0, then it is a lambda.
0 => { 0 => {
let nam = self.namegen.decl_name(self.net, Port(node, 1)); let nam = self.namegen.decl_name(self.net, Port(node, 1));
@ -117,7 +113,7 @@ impl Reader<'_> {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
Mat => match next.slot() { NodeKind::Mat => match next.slot() {
2 => { 2 => {
// Read the matched expression // Read the matched expression
let arg = self.read_term(self.net.enter_port(Port(node, 0))); let arg = self.read_term(self.net.enter_port(Port(node, 0)));
@ -128,7 +124,7 @@ impl Reader<'_> {
// We expect the pattern matching node to be a CON // We expect the pattern matching node to be a CON
let sel_kind = &self.net.node(sel_node).kind; let sel_kind = &self.net.node(sel_node).kind;
let (zero, succ) = if *sel_kind == Ctr(Con(None)) { let (zero, succ) = if *sel_kind == NodeKind::Ctr(Con(None)) {
let zero_term = self.read_term(self.net.enter_port(Port(sel_node, 1))); let zero_term = self.read_term(self.net.enter_port(Port(sel_node, 1)));
let mut succ_term = self.read_term(self.net.enter_port(Port(sel_node, 2))); let mut succ_term = self.read_term(self.net.enter_port(Port(sel_node, 2)));
@ -157,7 +153,7 @@ impl Reader<'_> {
Term::Err Term::Err
} }
}, },
Ref { def_name } => { NodeKind::Ref { def_name } => {
if def_name.is_generated() { if def_name.is_generated() {
// Dereference generated names since the user is not aware of them // Dereference generated names since the user is not aware of them
let def = &self.book.defs[def_name]; let def = &self.book.defs[def_name];
@ -170,7 +166,7 @@ impl Reader<'_> {
} }
} }
// If we're visiting a fan node... // If we're visiting a fan node...
Ctr(kind @ (Dup(_) | Tup(_))) => { NodeKind::Ctr(kind @ (Dup(_) | Tup(_))) => {
let (fan, lab) = match *kind { let (fan, lab) = match *kind {
Tup(lab) => (FanKind::Tup, lab), Tup(lab) => (FanKind::Tup, lab),
Dup(lab) => (FanKind::Dup, Some(lab)), Dup(lab) => (FanKind::Dup, Some(lab)),
@ -217,7 +213,7 @@ impl Reader<'_> {
_ => unreachable!(), _ => unreachable!(),
} }
} }
Num { val: _ } => { NodeKind::Num { val: _ } => {
let (flp, arg) = self.read_opr_arg(next); let (flp, arg) = self.read_opr_arg(next);
match arg { match arg {
NumArg::Sym(opr) => Term::Opr { NumArg::Sym(opr) => Term::Opr {
@ -225,26 +221,26 @@ impl Reader<'_> {
fst: Box::new(Term::Err), fst: Box::new(Term::Err),
snd: Box::new(Term::Err), snd: Box::new(Term::Err),
}, },
NumArg::Num(typ, val) => Term::Num { typ, val }, NumArg::Num(typ, val) => Term::Num { val: Num::from_bits_and_type(val, typ) },
NumArg::Par(opr, val) => { NumArg::Par(opr, val) => {
if flp { if flp {
Term::Opr { Term::Opr {
opr: Op::from_native_tag(opr, NumType::U24), opr: Op::from_native_tag(opr, NumType::U24),
fst: Box::new(Term::Num { typ: NumType::U24, val }), fst: Box::new(Term::Num { val: Num::from_bits_and_type(val, NumType::U24) }),
snd: Box::new(Term::Err), snd: Box::new(Term::Err),
} }
} else { } else {
Term::Opr { Term::Opr {
opr: Op::from_native_tag(opr, NumType::U24), opr: Op::from_native_tag(opr, NumType::U24),
fst: Box::new(Term::Err), fst: Box::new(Term::Err),
snd: Box::new(Term::Num { typ: NumType::U24, val }), snd: Box::new(Term::Num { val: Num::from_bits_and_type(val, NumType::U24) }),
} }
} }
} }
NumArg::Oth(_) => unreachable!(), NumArg::Oth(_) => unreachable!(),
} }
} }
Opr => match next.slot() { NodeKind::Opr => match next.slot() {
2 => { 2 => {
let port0_kind = self.net.node(self.net.enter_port(Port(node, 0)).node()).kind.clone(); let port0_kind = self.net.node(self.net.enter_port(Port(node, 0)).node()).kind.clone();
if port0_kind == NodeKind::Opr { if port0_kind == NodeKind::Opr {
@ -253,7 +249,7 @@ impl Reader<'_> {
if let Term::Opr { opr, fst, snd: _ } = &fst { if let Term::Opr { opr, fst, snd: _ } = &fst {
let (flip, arg) = self.read_opr_arg(self.net.enter_port(Port(node, 1))); let (flip, arg) = self.read_opr_arg(self.net.enter_port(Port(node, 1)));
let snd = Box::new(match arg { let snd = Box::new(match arg {
NumArg::Num(typ, val) => Term::Num { typ, val }, NumArg::Num(typ, val) => Term::Num { val: Num::from_bits_and_type(val, typ) },
NumArg::Oth(term) => term, NumArg::Oth(term) => term,
NumArg::Sym(_) | NumArg::Par(_, _) => { NumArg::Sym(_) | NumArg::Par(_, _) => {
self.error(ReadbackError::InvalidNumericOp); self.error(ReadbackError::InvalidNumericOp);
@ -271,34 +267,36 @@ impl Reader<'_> {
let (flip0, arg0) = self.read_opr_arg(self.net.enter_port(Port(node, 0))); let (flip0, arg0) = self.read_opr_arg(self.net.enter_port(Port(node, 0)));
let (flip1, arg1) = self.read_opr_arg(self.net.enter_port(Port(node, 1))); let (flip1, arg1) = self.read_opr_arg(self.net.enter_port(Port(node, 1)));
let (arg0, arg1) = if flip0 != flip1 { (arg1, arg0) } else { (arg0, arg1) }; let (arg0, arg1) = if flip0 != flip1 { (arg1, arg0) } else { (arg0, arg1) };
use NumArg::*;
match (arg0, arg1) { match (arg0, arg1) {
(Sym(opr), Num(typ, val)) | (Num(typ, val), Sym(opr)) => Term::Opr { (NumArg::Sym(opr), NumArg::Num(typ, val)) | (NumArg::Num(typ, val), NumArg::Sym(opr)) => {
Term::Opr {
opr: Op::from_native_tag(opr, typ),
fst: Box::new(Term::Num { val: Num::from_bits_and_type(val, typ) }),
snd: Box::new(Term::Err),
}
}
(NumArg::Num(typ, num1), NumArg::Par(opr, num2))
| (NumArg::Par(opr, num1), NumArg::Num(typ, num2)) => Term::Opr {
opr: Op::from_native_tag(opr, typ), opr: Op::from_native_tag(opr, typ),
fst: Box::new(Term::Num { typ, val }), fst: Box::new(Term::Num { val: Num::from_bits_and_type(num1, typ) }),
snd: Box::new(Term::Err), snd: Box::new(Term::Num { val: Num::from_bits_and_type(num2, typ) }),
},
(Num(typ, num1), Par(opr, num2)) | (Par(opr, num1), Num(typ, num2)) => Term::Opr {
opr: Op::from_native_tag(opr, typ),
fst: Box::new(Term::Num { typ, val: num1 }),
snd: Box::new(Term::Num { typ, val: num2 }),
}, },
// No type, so assuming u24 // No type, so assuming u24
(Sym(opr), Oth(term)) | (Oth(term), Sym(opr)) => Term::Opr { (NumArg::Sym(opr), NumArg::Oth(term)) | (NumArg::Oth(term), NumArg::Sym(opr)) => Term::Opr {
opr: Op::from_native_tag(opr, NumType::U24), opr: Op::from_native_tag(opr, NumType::U24),
fst: Box::new(term), fst: Box::new(term),
snd: Box::new(Term::Err), snd: Box::new(Term::Err),
}, },
(Par(opr, num), Oth(term)) => Term::Opr { (NumArg::Par(opr, num), NumArg::Oth(term)) => Term::Opr {
opr: Op::from_native_tag(opr, NumType::U24), opr: Op::from_native_tag(opr, NumType::U24),
fst: Box::new(Term::Num { typ: NumType::U24, val: num }), fst: Box::new(Term::Num { val: Num::from_bits_and_type(num, NumType::U24) }),
snd: Box::new(term), snd: Box::new(term),
}, },
(Oth(term), Par(opr, num)) => Term::Opr { (NumArg::Oth(term), NumArg::Par(opr, num)) => Term::Opr {
opr: Op::from_native_tag(opr, NumType::U24), opr: Op::from_native_tag(opr, NumType::U24),
fst: Box::new(term), fst: Box::new(term),
snd: Box::new(Term::Num { typ: NumType::U24, val: num }), snd: Box::new(Term::Num { val: Num::from_bits_and_type(num, NumType::U24) }),
}, },
_ => { _ => {
self.error(ReadbackError::InvalidNumericOp); self.error(ReadbackError::InvalidNumericOp);
@ -312,7 +310,7 @@ impl Reader<'_> {
Term::Err Term::Err
} }
}, },
Rot => { NodeKind::Rot => {
self.error(ReadbackError::ReachedRoot); self.error(ReadbackError::ReachedRoot);
Term::Err Term::Err
} }
@ -323,7 +321,7 @@ impl Reader<'_> {
fn read_opr_arg(&mut self, next: Port) -> (bool, NumArg) { fn read_opr_arg(&mut self, next: Port) -> (bool, NumArg) {
let node = next.node(); let node = next.node();
match &self.net.node(node).kind { match &self.net.node(node).kind {
Num { val } => { NodeKind::Num { val } => {
self.seen.insert(next); self.seen.insert(next);
let flipped = ((val >> 28) & 0x1) != 0; let flipped = ((val >> 28) & 0x1) != 0;
let typ = val & 0xf; let typ = val & 0xf;
@ -381,7 +379,7 @@ impl Reader<'_> {
// Eta-reduce the readback inet. // Eta-reduce the readback inet.
// This is not valid for all kinds of nodes, only CON/TUP/DUP, due to their interaction rules. // This is not valid for all kinds of nodes, only CON/TUP/DUP, due to their interaction rules.
if matches!(node_kind, Ctr(_)) { if matches!(node_kind, NodeKind::Ctr(_)) {
match (fst_port, snd_port) { match (fst_port, snd_port) {
(Port(fst_node, 1), Port(snd_node, 2)) if fst_node == snd_node => { (Port(fst_node, 1), Port(snd_node, 2)) if fst_node == snd_node => {
if self.net.node(fst_node).kind == *node_kind { if self.net.node(fst_node).kind == *node_kind {
@ -427,6 +425,13 @@ enum NumArg {
Oth(Term), Oth(Term),
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum NumType {
U24 = 1,
I24 = 2,
F24 = 3,
}
impl Op { impl Op {
fn from_native_tag(val: u32, typ: NumType) -> Op { fn from_native_tag(val: u32, typ: NumType) -> Op {
match val { match val {
@ -476,6 +481,12 @@ impl NumType {
} }
} }
impl Num {
fn from_bits_and_type(bits: u32, typ: NumType) -> Self {
Num::from_bits((bits & 0x00ff_ffff) << 4 | (typ as u32))
}
}
/* Insertion of dups in the middle of the term */ /* Insertion of dups in the middle of the term */
/// Represents `let #tag(fst, snd) = val` / `let #tag{fst snd} = val` /// Represents `let #tag(fst, snd) = val` / `let #tag{fst snd} = val`
@ -589,7 +600,7 @@ impl NameGen {
// If port is linked to an erase node, return an unused variable // If port is linked to an erase node, return an unused variable
let var_use = net.enter_port(var_port); let var_use = net.enter_port(var_port);
let var_kind = &net.node(var_use.node()).kind; let var_kind = &net.node(var_use.node()).kind;
(*var_kind != Era).then(|| self.var_name(var_port)) (*var_kind != NodeKind::Era).then(|| self.var_name(var_port))
} }
pub fn unique(&mut self) -> Name { pub fn unique(&mut self) -> Name {

View File

@ -1,15 +1,13 @@
use crate::{ use crate::{
maybe_grow, maybe_grow,
term::{ term::{
display::DisplayFn, Adt, Book, Definition, FanKind, MatchRule, Name, Op, Pattern, Rule, Tag, Term, display::DisplayFn, Adt, Book, Definition, FanKind, MatchRule, Name, Num, Op, Pattern, Rule, Tag, Term,
STRINGS, STRINGS,
}, },
}; };
use highlight_error::highlight_error; use highlight_error::highlight_error;
use TSPL::Parser; use TSPL::Parser;
use super::NumType;
// hvml grammar description: // hvml grammar description:
// <Book> ::= (<Data> | <Rule>)* // <Book> ::= (<Data> | <Rule>)*
// <Data> ::= "data" <Name> "=" ( <Name> | "(" <Name> (<Name>)* ")" )+ // <Data> ::= "data" <Name> "=" ( <Name> | "(" <Name> (<Name>)* ")" )+
@ -188,8 +186,8 @@ impl<'a> TermParser<'a> {
// Number // Number
if self.peek_one().map_or(false, |c| c.is_ascii_digit()) { if self.peek_one().map_or(false, |c| c.is_ascii_digit()) {
unexpected_tag(self)?; unexpected_tag(self)?;
let num = self.parse_u64()?; let num = self.parse_u32()?;
return Ok(Pattern::Num(num as u32)); return Ok(Pattern::Num(num));
} }
// Channel // Channel
@ -303,7 +301,7 @@ impl<'a> TermParser<'a> {
if self.starts_with("#") { if self.starts_with("#") {
self.consume("#")?; self.consume("#")?;
unexpected_tag(self)?; unexpected_tag(self)?;
let val = self.parse_u64()?; let val = self.parse_u32()?;
return Ok(Term::Nat { val }); return Ok(Term::Nat { val });
} }
@ -318,14 +316,61 @@ impl<'a> TermParser<'a> {
if self.starts_with("'") { if self.starts_with("'") {
unexpected_tag(self)?; unexpected_tag(self)?;
let char = self.parse_quoted_char()?; let char = self.parse_quoted_char()?;
return Ok(Term::Num { typ: NumType::U24, val: char as u32 }); return Ok(Term::Num { val: Num::U24(char as u32 & 0x00ff_ffff) });
} }
// Native num // Native Number
if self.peek_one().map_or(false, |c| c.is_ascii_digit()) { if self.peek_one().map_or(false, |c| "0123456789+-".contains(c)) {
unexpected_tag(self)?; unexpected_tag(self)?;
let val = self.parse_u64()?;
return Ok(Term::Num { typ: NumType::U24, val: val as u32 }); let ini_idx = *self.index();
// Parses sign
let sgn = if self.try_consume("+") {
Some(1)
} else if self.try_consume("-") {
Some(-1)
} else {
None
};
// Parses main value
let num = self.parse_u32()?;
// Parses frac value (Float type)
// TODO: Will lead to some rounding errors
// TODO: Doesn't cover very large/small numbers
let fra = if let Some('.') = self.peek_one() {
self.consume(".")?;
let ini_idx = *self.index();
let fra = self.parse_u32()? as f32;
let end_idx = *self.index();
let fra = fra / 10f32.powi((end_idx - ini_idx) as i32);
Some(fra)
} else {
None
};
// F24
if let Some(fra) = fra {
let sgn = sgn.unwrap_or(1);
return Ok(Term::Num { val: Num::F24(sgn as f32 * (num as f32 + fra)) });
}
// I24
if let Some(sgn) = sgn {
let num = sgn * num as i32;
if !(-0x00800000 ..= 0x007fffff).contains(&num) {
return self.num_range_err(ini_idx, "I24");
}
return Ok(Term::Num { val: Num::I24(num) });
}
// U24
if num >= 1 << 24 {
return self.num_range_err(ini_idx, "U24");
}
return Ok(Term::Num { val: Num::U24(num) });
} }
// Use // Use
@ -493,7 +538,7 @@ impl<'a> TermParser<'a> {
} }
} }
c if c.is_ascii_digit() => { c if c.is_ascii_digit() => {
let val = self.parse_u64()?; let val = self.parse_u32()?;
if val != expected_num { if val != expected_num {
return self.expected(&expected_num.to_string()); return self.expected(&expected_num.to_string());
} }
@ -509,6 +554,115 @@ impl<'a> TermParser<'a> {
self.consume("}")?; self.consume("}")?;
Ok(Term::Swt { arg: Box::new(arg), bnd: Some(bnd), with, pred, arms }) Ok(Term::Swt { arg: Box::new(arg), bnd: Some(bnd), with, pred, arms })
} }
fn num_range_err<T>(&mut self, ini_idx: usize, typ: &str) -> Result<T, String> {
let ctx = highlight_error(ini_idx, *self.index(), self.input());
Err(format!("\x1b[1mNumber literal outside of range for {}.\x1b[0m\n{}", typ, ctx))
}
/* Utils */
/// Checks if the next characters in the input start with the given string.
/// Skips trivia.
fn skip_starts_with(&mut self, text: &str) -> bool {
self.skip_trivia();
self.starts_with(text)
}
fn skip_peek_one(&mut self) -> Option<char> {
self.skip_trivia();
self.peek_one()
}
/// Parses a list-like structure like "[x1, x2, x3,]".
///
/// `parser` is a function that parses an element of the list.
///
/// If `hard_sep` the separator between elements is mandatory.
/// Always accepts trailing separators.
///
/// `min_els` determines how many elements must be parsed at minimum.
fn list_like<T>(
&mut self,
parser: impl Fn(&mut Self) -> Result<T, String>,
start: &str,
end: &str,
sep: &str,
hard_sep: bool,
min_els: usize,
) -> Result<Vec<T>, String> {
self.consume(start)?;
let mut els = vec![];
for i in 0 .. min_els {
els.push(parser(self)?);
if hard_sep && !(i == min_els - 1 && self.skip_starts_with(end)) {
self.consume(sep)?;
} else {
self.try_consume(sep);
}
}
while !self.try_consume(end) {
els.push(parser(self)?);
if hard_sep && !self.skip_starts_with(end) {
self.consume(sep)?;
} else {
self.try_consume(sep);
}
}
Ok(els)
}
fn labelled<T>(
&mut self,
parser: impl Fn(&mut Self) -> Result<T, String>,
label: &str,
) -> Result<T, String> {
match parser(self) {
Ok(val) => Ok(val),
Err(_) => self.expected(label),
}
}
fn expected_spanned<T>(&mut self, exp: &str, ini_idx: usize, end_idx: usize) -> Result<T, String> {
let ctx = highlight_error(ini_idx, end_idx, self.input());
let is_eof = self.is_eof();
let detected = DisplayFn(|f| if is_eof { write!(f, " end of input") } else { write!(f, "\n{ctx}") });
Err(format!("\x1b[1m- expected:\x1b[0m {}\n\x1b[1m- detected:\x1b[0m{}", exp, detected))
}
/// Consumes text if the input starts with it. Otherwise, do nothing.
fn try_consume(&mut self, text: &str) -> bool {
self.skip_trivia();
if self.starts_with(text) {
self.consume(text).unwrap();
true
} else {
false
}
}
fn parse_u32(&mut self) -> Result<u32, String> {
self.skip_trivia();
let radix = match self.peek_many(2) {
Some("0x") => {
self.advance_many(2);
16
}
Some("0b") => {
self.advance_many(2);
2
}
_ => 10,
};
let num_str = self.take_while(move |c| c.is_digit(radix) || c == '_');
let num_str = num_str.chars().filter(|c| *c != '_').collect::<String>();
if num_str.is_empty() {
self.expected("numeric digit")
} else {
u32::from_str_radix(&num_str, radix).map_err(|e| e.to_string())
}
}
} }
impl<'a> Parser<'a> for TermParser<'a> { impl<'a> Parser<'a> for TermParser<'a> {

View File

@ -108,8 +108,8 @@ impl<'t, 'l> EncodeTermState<'t, 'l> {
Term::Var { nam } => self.link_var(false, nam, up), Term::Var { nam } => self.link_var(false, nam, up),
Term::Lnk { nam } => self.link_var(true, nam, up), Term::Lnk { nam } => self.link_var(true, nam, up),
Term::Ref { nam } => self.link(up, Place::Tree(LoanedMut::new(Tree::Ref { nam: nam.to_string() }))), Term::Ref { nam } => self.link(up, Place::Tree(LoanedMut::new(Tree::Ref { nam: nam.to_string() }))),
Term::Num { typ, val } => { Term::Num { val } => {
let val = (*val << 4) | (*typ as u32); let val = val.to_bits();
self.link(up, Place::Tree(LoanedMut::new(Tree::Num { val }))) self.link(up, Place::Tree(LoanedMut::new(Tree::Num { val })))
} }
// A lambda becomes to a con node. Ports: // A lambda becomes to a con node. Ports:
@ -170,18 +170,20 @@ impl<'t, 'l> EncodeTermState<'t, 'l> {
// Partially apply // Partially apply
match (fst.as_ref(), snd.as_ref()) { match (fst.as_ref(), snd.as_ref()) {
// Put oper in fst // Put oper in fst
(Term::Num { typ: _, val }, snd) => { (Term::Num { val }, snd) => {
let num_val = (*val << 4) | opr.to_native_tag(); let val = val.to_bits();
let fst = Place::Tree(LoanedMut::new(Tree::Num { val: num_val })); let val = (val & 0xffff_fff0) | opr.to_native_tag();
let fst = Place::Tree(LoanedMut::new(Tree::Num { val }));
let node = self.new_opr(); let node = self.new_opr();
self.link(fst, node.0); self.link(fst, node.0);
self.encode_term(snd, node.1); self.encode_term(snd, node.1);
self.link(up, node.2); self.link(up, node.2);
} }
// Put oper in snd // Put oper in snd
(fst, Term::Num { typ: _, val }) => { (fst, Term::Num { val }) => {
let num_val = (*val << 4) | opr.to_native_tag(); let val = val.to_bits();
let snd = Place::Tree(LoanedMut::new(Tree::Num { val: num_val })); let val = (val & 0xffff_fff0) | opr.to_native_tag();
let snd = Place::Tree(LoanedMut::new(Tree::Num { val }));
let node = self.new_opr(); let node = self.new_opr();
self.encode_term(fst, node.0); self.encode_term(fst, node.0);
self.link(snd, node.1); self.link(snd, node.1);

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
diagnostics::{Diagnostics, WarningType}, diagnostics::{Diagnostics, WarningType},
term::{builtins, Adts, Constructors, Ctx, Definition, FanKind, Name, NumType, Pattern, Rule, Tag, Term}, term::{builtins, Adts, Constructors, Ctx, Definition, FanKind, Name, Num, Pattern, Rule, Tag, Term},
}; };
use std::collections::{BTreeSet, HashSet}; use std::collections::{BTreeSet, HashSet};
@ -280,7 +280,7 @@ fn num_rule(
if let Some(var) = var { if let Some(var) = var {
body = Term::Use { body = Term::Use {
nam: Some(var.clone()), nam: Some(var.clone()),
val: Box::new(Term::Num { typ: NumType::U24, val: *num }), val: Box::new(Term::Num { val: Num::U24(*num) }),
nxt: Box::new(std::mem::take(&mut body)), nxt: Box::new(std::mem::take(&mut body)),
}; };
} }
@ -301,7 +301,7 @@ fn num_rule(
let mut body = rule.body.clone(); let mut body = rule.body.clone();
if let Some(var) = var { if let Some(var) = var {
let last_num = *nums.last().unwrap(); let last_num = *nums.last().unwrap();
let var_recovered = Term::add_num(Term::Var { nam: pred_var.clone() }, 1 + last_num, NumType::U24); let var_recovered = Term::add_num(Term::Var { nam: pred_var.clone() }, Num::U24(1 + last_num));
body = Term::Use { nam: Some(var.clone()), val: Box::new(var_recovered), nxt: Box::new(body) }; body = Term::Use { nam: Some(var.clone()), val: Box::new(var_recovered), nxt: Box::new(body) };
} }
let rule = Rule { pats: rule.pats[1 ..].to_vec(), body }; let rule = Rule { pats: rule.pats[1 ..].to_vec(), body };
@ -319,10 +319,10 @@ fn num_rule(
let val = if i > 0 { let val = if i > 0 {
// switch arg = (pred +1 +num_i-1 - num_i) { 0: body_i; _: acc } // switch arg = (pred +1 +num_i-1 - num_i) { 0: body_i; _: acc }
// nums[i] >= nums[i-1]+1, so we do a sub here. // nums[i] >= nums[i-1]+1, so we do a sub here.
Term::sub_num(Term::Var { nam: pred_var.clone() }, nums[i] - 1 - nums[i - 1], NumType::U24) Term::sub_num(Term::Var { nam: pred_var.clone() }, Num::U24(nums[i] - 1 - nums[i - 1]))
} else { } else {
// switch arg = (arg -num_0) { 0: body_0; _: acc} // switch arg = (arg -num_0) { 0: body_0; _: acc}
Term::sub_num(Term::Var { nam: arg.clone() }, nums[i], NumType::U24) Term::sub_num(Term::Var { nam: arg.clone() }, Num::U24(nums[i]))
}; };
Term::Swt { Term::Swt {

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
diagnostics::{Diagnostics, WarningType, ERR_INDENT_SIZE}, diagnostics::{Diagnostics, WarningType, ERR_INDENT_SIZE},
maybe_grow, maybe_grow,
term::{Adts, Constructors, Ctx, MatchRule, Name, NumType, Term}, term::{Adts, Constructors, Ctx, MatchRule, Name, Num, Term},
}; };
use std::collections::HashMap; use std::collections::HashMap;
@ -105,9 +105,9 @@ impl Term {
let n_nums = arms.len() - 1; let n_nums = arms.len() - 1;
for (i, arm) in arms.iter_mut().enumerate() { for (i, arm) in arms.iter_mut().enumerate() {
let orig = if i == n_nums { let orig = if i == n_nums {
Term::add_num(Term::Var { nam: pred.clone().unwrap() }, i as u32, NumType::U24) Term::add_num(Term::Var { nam: pred.clone().unwrap() }, Num::U24(i as u32))
} else { } else {
Term::Num { typ: NumType::U24, val: i as u32 } Term::Num { val: Num::U24(i as u32) }
}; };
*arm = Term::Use { nam: bnd.clone(), val: Box::new(orig), nxt: Box::new(std::mem::take(arm)) }; *arm = Term::Use { nam: bnd.clone(), val: Box::new(orig), nxt: Box::new(std::mem::take(arm)) };
} }

View File

@ -0,0 +1 @@
(/ (* +124.0928 1.24) (+ 0.0 -235.12235))

View File

@ -0,0 +1 @@
(* (+ +1 -1) (- -12 +14))

View File

@ -0,0 +1 @@
0x10000000

View File

@ -1 +1 @@
(+ 0xFFFF_FFFF (+ 0b101 1_000)) (+ 0xFF_FFFF (+ 0b101 1_000))

View File

@ -1 +1 @@
(+ 0b0123456789 0FA) (+ 0b012345 0FA)

View File

@ -0,0 +1,7 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_term/f24_oper.hvm
---
b
& $(1.240 $(:[/] $(a b))) ~ [*4583519]
& $(-235.121 a) ~ [+0]

View File

@ -0,0 +1,7 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_term/i24_oper.hvm
---
b
& $(-1 $(:[*] $(a b))) ~ [+1]
& $(+14 a) ~ [-16777204]

View File

@ -0,0 +1,7 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_term/number_too_large.hvm
---
Errors:
Number literal outside of range for U24.
 1 | 0x10000000

View File

@ -3,5 +3,5 @@ source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_term/nums.hvm input_file: tests/golden_tests/compile_term/nums.hvm
--- ---
b b
& $(a b) ~ :[+16777215] & $(a b) ~ [+16777215]
& $(1000 a) ~ [+5] & $(1000 a) ~ [+5]

View File

@ -5,4 +5,4 @@ input_file: tests/golden_tests/compile_term/wrong_nums.hvm
Errors: Errors:
- expected: ')' - expected: ')'
- detected: - detected:
 1 | (+ 0b0123456789 0FA)  1 | (+ 0b012345 0FA)

View File

@ -2,4 +2,4 @@
source: tests/golden_tests.rs source: tests/golden_tests.rs
input_file: examples/bubble_sort.hvm input_file: examples/bubble_sort.hvm
--- ---
2721105 5525035

View File

@ -2,4 +2,4 @@
source: tests/golden_tests.rs source: tests/golden_tests.rs
input_file: examples/quick_sort.hvm input_file: examples/quick_sort.hvm
--- ---
7311046 12741879