mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-09-11 03:45:29 +03:00
[sc-548] Add support for i24 and f24
This commit is contained in:
parent
ba748c95e8
commit
03fcf344f1
@ -61,6 +61,7 @@
|
|||||||
"peekable",
|
"peekable",
|
||||||
"postcondition",
|
"postcondition",
|
||||||
"prec",
|
"prec",
|
||||||
|
"powi",
|
||||||
"readback",
|
"readback",
|
||||||
"recursively",
|
"recursively",
|
||||||
"redex",
|
"redex",
|
||||||
|
@ -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)))
|
||||||
|
@ -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)))
|
||||||
|
@ -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)
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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, "*"),
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
132
src/term/mod.rs
132
src/term/mod.rs
@ -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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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> {
|
||||||
|
@ -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);
|
||||||
|
@ -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 {
|
||||||
|
@ -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)) };
|
||||||
}
|
}
|
||||||
|
1
tests/golden_tests/compile_term/f24_oper.hvm
Normal file
1
tests/golden_tests/compile_term/f24_oper.hvm
Normal file
@ -0,0 +1 @@
|
|||||||
|
(/ (* +124.0928 1.24) (+ 0.0 -235.12235))
|
1
tests/golden_tests/compile_term/i24_oper.hvm
Normal file
1
tests/golden_tests/compile_term/i24_oper.hvm
Normal file
@ -0,0 +1 @@
|
|||||||
|
(* (+ +1 -1) (- -12 +14))
|
1
tests/golden_tests/compile_term/number_too_large.hvm
Normal file
1
tests/golden_tests/compile_term/number_too_large.hvm
Normal file
@ -0,0 +1 @@
|
|||||||
|
0x10000000
|
@ -1 +1 @@
|
|||||||
(+ 0xFFFF_FFFF (+ 0b101 1_000))
|
(+ 0xFF_FFFF (+ 0b101 1_000))
|
@ -1 +1 @@
|
|||||||
(+ 0b0123456789 0FA)
|
(+ 0b012345 0FA)
|
7
tests/snapshots/compile_term__f24_oper.hvm.snap
Normal file
7
tests/snapshots/compile_term__f24_oper.hvm.snap
Normal 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]
|
7
tests/snapshots/compile_term__i24_oper.hvm.snap
Normal file
7
tests/snapshots/compile_term__i24_oper.hvm.snap
Normal 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]
|
7
tests/snapshots/compile_term__number_too_large.hvm.snap
Normal file
7
tests/snapshots/compile_term__number_too_large.hvm.snap
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
source: tests/golden_tests.rs
|
||||||
|
input_file: tests/golden_tests/compile_term/number_too_large.hvm
|
||||||
|
---
|
||||||
|
Errors:
|
||||||
|
[1mNumber literal outside of range for U24.[0m
|
||||||
|
[0m 1 | [4m[31m0x10000000[0m
|
@ -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]
|
||||||
|
@ -5,4 +5,4 @@ input_file: tests/golden_tests/compile_term/wrong_nums.hvm
|
|||||||
Errors:
|
Errors:
|
||||||
[1m- expected:[0m ')'
|
[1m- expected:[0m ')'
|
||||||
[1m- detected:[0m
|
[1m- detected:[0m
|
||||||
[0m 1 | (+ 0b0123456789 [4m[31m0[0mFA)[0m
|
[0m 1 | (+ 0b012345 [4m[31m0[0mFA)[0m
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user