M src/abase.rs => src/abase.rs +27 -3
@@ 1,7 1,7 @@
//! Base -- the lowest level IR in Effem before generating the output machine code.
use crate::prelude::*;
-use fem::Expr as FExpr;
+use fem::{Expr as FExpr, Type};
#[derive(Clone, Debug)]
pub enum GlobDef {
@@ 59,6 59,16 @@ pub enum Operand {
#[derive(Clone, Debug)]
pub enum Const {
+ I8(i8),
+ I16(i16),
+ I32(i32),
+ I64(i64),
+ Int(isize),
+ N8(u8),
+ N16(u16),
+ N32(u32),
+ N64(u64),
+ Nat(usize),
F64(f64),
}
@@ 101,18 111,32 @@ impl<'c> AbaseDef<'c> {
fn abase(&mut self, expr: &FExpr) -> Result<Expr> {
use crate::fem::ExprKind::*;
match &expr.kind {
+ &Int(x) => Ok(Expr::Operand(Operand::Const(match expr.typ {
+ Type::Int { width: 8, signed: true } => Const::I8(x as i8),
+ Type::Int { width: 16, signed: true } => Const::I16(x as i16),
+ Type::Int { width: 32, signed: true } => Const::I32(x as i32),
+ Type::Int { width: 64, signed: true } => Const::I64(x as i64),
+ Type::Int { width: 8, signed: false } => Const::N8(x as u8),
+ Type::Int { width: 16, signed: false } => Const::N16(x as u16),
+ Type::Int { width: 32, signed: false } => Const::N32(x as u32),
+ Type::Int { width: 64, signed: false } => Const::N64(x as u64),
+ Type::Int { width, signed } => panic!("ice: bad integer type with width={width}, signed={signed}"),
+ Type::ISize => Const::Int(x as isize),
+ Type::NSize => Const::Nat(x as usize),
+ ref t => panic!("ice: integer expr has non-integer type {t}"),
+ }))),
F64(x) => Ok(Expr::Operand(Operand::Const(Const::F64(*x)))),
Fun(ps, b) => Ok(Expr::Operand(Operand::Local(self.abase_fun(ps, b)?))),
App(f, xs) => match &f.kind {
Var(ResName { res: Res::Prim(p) }) => match p {
- Prim::Add => {
+ Prim::Add | Prim::AddF => {
let x = self.abase(&xs[0])?;
let x = self.let_anon_soft(x)?;
let y = self.abase(&xs[1])?;
let y = self.let_anon_soft(y)?;
Ok(Expr::Add(x, y))
}
- Prim::Mul => {
+ Prim::Mul | Prim::MulF => {
let x = self.abase(&xs[0])?;
let x = self.let_anon_soft(x)?;
let y = self.abase(&xs[1])?;
M src/cache.rs => src/cache.rs +8 -1
@@ 118,7 118,12 @@ impl Cache {
}
pub fn fetch_module_local_resolved_names(&mut self, module_id: ModuleId) -> Result<&HashMap<String, Res>> {
- static PRELUDE: &[(&str, Res)] = &[("+", Res::Prim(Prim::Add)), ("*", Res::Prim(Prim::Mul))];
+ static PRELUDE: &[(&str, Res)] = &[
+ ("+", Res::Prim(Prim::Add)),
+ ("*", Res::Prim(Prim::Mul)),
+ ("+f", Res::Prim(Prim::AddF)),
+ ("*f", Res::Prim(Prim::MulF)),
+ ];
if self.module_local_resolved_names.contains_key(&module_id) {
Ok(&self.module_local_resolved_names[&module_id])
@@ 144,6 149,8 @@ impl Cache {
match sname.get(1).unwrap().as_str() {
"+" => Ok(Res::Prim(Prim::Add)),
"*" => Ok(Res::Prim(Prim::Mul)),
+ "+f" => Ok(Res::Prim(Prim::AddF)),
+ "*f" => Ok(Res::Prim(Prim::MulF)),
_ => todo!(), // Err
}
} else if let Some(&res) = self.resolved_names.get(&sname) {
M src/check.rs => src/check.rs +26 -0
@@ 25,6 25,16 @@ impl<'c> CheckDef<'c> {
fn infer(&mut self, expr: &RExpr) -> Result<Expr> {
use resolve::ExprKind as Rek;
match &expr.kind {
+ Rek::Int(x) => Ok(Expr {
+ typ: if (isize::MIN as i128..=isize::MAX as i128).contains(x) {
+ Type::ISize
+ } else if (i64::MIN as i128..=i64::MAX as i128).contains(x) {
+ Type::Int { width: 64, signed: true }
+ } else {
+ Type::Int { width: 128, signed: true }
+ },
+ kind: ExprKind::Int(*x),
+ }),
Rek::F64(x) => Ok(Expr { typ: Type::F64, kind: ExprKind::F64(*x) }),
Rek::Fun(ps, b) if ps.is_empty() => {
let bi = self.infer(b)?;
@@ 53,6 63,10 @@ impl<'c> CheckDef<'c> {
None => panic!("ice: undefined local var of id {id}"),
},
Rek::Var(r @ ResName { res: Res::Prim(Prim::Add | Prim::Mul) }) => Ok(Expr {
+ typ: Type::Fun(vec![Type::ISize, Type::ISize], Box::new(Type::ISize)),
+ kind: ExprKind::Var(r.clone()),
+ }),
+ Rek::Var(r @ ResName { res: Res::Prim(Prim::AddF | Prim::MulF) }) => Ok(Expr {
typ: Type::Fun(vec![Type::F64, Type::F64], Box::new(Type::F64)),
kind: ExprKind::Var(r.clone()),
}),
@@ 64,6 78,18 @@ impl<'c> CheckDef<'c> {
fn check(&mut self, expr: &RExpr, expected: &Type) -> Result<Expr> {
use resolve::ExprKind as Rek;
match &expr.kind {
+ &Rek::Int(x) => {
+ match expected {
+ Type::Int { width: 128, signed: true } if i128::MIN <= x && x <= i128::MAX => (),
+ Type::Int { width: 128, signed: false } if 0 <= x && x as u128 <= u128::MAX => (),
+ Type::Int { width, signed: true } if -(1 << (width - 1)) <= x && x < (1 << (width - 1)) => (),
+ Type::Int { width, signed: false } if 0 <= x && x < (1 << width) => (),
+ Type::ISize if isize::MIN as i128 <= x && x <= isize::MAX as i128 => (),
+ Type::NSize if 0 <= x && x as u128 <= usize::MAX as u128 => (),
+ _ => return err(ExpectedFound(expr.loc, expected.clone(), self.infer(expr)?.typ)),
+ }
+ Ok(Expr { typ: expected.clone(), kind: ExprKind::Int(x) })
+ }
Rek::Fun(ps, b) =>
if let Type::Fun(tps, tr) = expected {
if ps.len() != tps.len() {
M src/eval.rs => src/eval.rs +2 -0
@@ 44,10 44,12 @@ impl<'c, 'd> EvalDef<'c, 'd> {
match expr {
Expr::Add(x, y) => match (self.eval_operand(x)?, self.eval_operand(y)?) {
(Operand::Const(Const::F64(x)), Operand::Const(Const::F64(y))) => Ok(Operand::Const(Const::F64(x + y))),
+ (Operand::Const(Const::Int(x)), Operand::Const(Const::Int(y))) => Ok(Operand::Const(Const::Int(x + y))),
(xe, ye) => panic!("ice: cannot add {xe:?} + {ye:?} ({x:?} + {y:?})"),
},
Expr::Mul(x, y) => match (self.eval_operand(x)?, self.eval_operand(y)?) {
(Operand::Const(Const::F64(x)), Operand::Const(Const::F64(y))) => Ok(Operand::Const(Const::F64(x * y))),
+ (Operand::Const(Const::Int(x)), Operand::Const(Const::Int(y))) => Ok(Operand::Const(Const::Int(x * y))),
(xe, ye) => panic!("ice: cannot add {xe:?} * {ye:?} ({x:?} * {y:?})"),
},
Expr::Call(f, xs) => match self.eval_operand(f)? {
M src/fem.rs => src/fem.rs +1 -0
@@ 11,6 11,7 @@ pub struct Expr {
#[derive(Debug, Clone)]
pub enum ExprKind {
+ Int(i128),
F64(f64),
Fun(Vec<(PubIdent, LocalId)>, Box<Expr>),
App(Box<Expr>, Vec<Expr>),
M src/lex.rs => src/lex.rs +51 -32
@@ 9,7 9,7 @@ use std::path::Path;
#[derive(Debug, Clone, PartialEq)]
pub enum Tok<'s> {
- Int(i64),
+ Int(i128),
Float(f64),
Str(Cow<'s, str>),
Ident(&'s str),
@@ 102,7 102,7 @@ impl<'s> Scanner<'s> {
}
')' | ']' | '}' => Ok(None),
' ' => Ok(None),
- '0'..='9' => self.num().map(Some),
+ '0'..='9' => self.num(false).map(Some),
'"' => self.string().map(|s| Some(Token { tok: Tok::Str(s), offset })),
':' => {
self.consume();
@@ 127,11 127,10 @@ impl<'s> Scanner<'s> {
}),
}
}
- '-' if matches!(self.peek2(), Some('0'..='9')) => Ok(Some(match self.num()? {
- Token { offset, tok: Tok::Int(x) } => Token { offset, tok: Tok::Int(-x) },
- Token { offset, tok: Tok::Float(x) } => Token { offset, tok: Tok::Float(-x) },
- _ => unreachable!(),
- })),
+ '-' if matches!(self.peek2(), Some('0'..='9')) => {
+ self.consume();
+ self.num(true).map(Some)
+ }
_ if ident_char(c) => self.ident().map(|id| Some(Token { offset, tok: Tok::Ident(id) })),
_ => Err(LexErr {
expected: LexThing::Descr("any token tree"),
@@ 257,35 256,46 @@ impl<'s> Scanner<'s> {
.map(|c| c.to_digit(0x10).unwrap() as u8)
}
- fn num(&mut self) -> LResult<Token<'s>> {
- let offset = self.i as u32;
- let mut acc = 0u64;
+ fn num(&mut self, sign: bool) -> LResult<Token<'s>> {
+ let i0 = self.i as u32;
+ let mut i1 = i0;
+ let mut dot = false;
loop {
match self.peek() {
- Some('.') => break self.float(acc),
- Some(c @ '0'..='9') => acc = acc * 10 + (c as u8 - b'0') as u64,
- Some('_') => (),
- _ => break Ok(Token { tok: Tok::Int(acc as i64), offset }),
+ Some('.') if !dot => dot = true,
+ Some('0'..='9' | '_') => (),
+ _ => break,
}
self.consume();
+ i1 += 1;
}
- }
-
- fn float(&mut self, left: u64) -> LResult<Token<'s>> {
- // TODO: Read floats accurately. See [(Clinger, "How to read floating point numbers accurately")](https://dl.acm.org/doi/10.1145/93542.93557).
- self.consume_expect('.')?;
- let mut factor = 0.1;
- let mut right = 0.0;
- loop {
- match self.peek() {
- Some(c @ '0'..='9') => {
- right += factor * (c as u8 - b'0') as f64;
- factor *= 0.1;
- }
- Some('_') => (),
- _ => break Ok(Token { tok: Tok::Float(left as f64 + right), offset: self.i as u32 }),
+ if dot {
+ // TODO: Do this in an in-place and accumulatively, avoiding heap alloc.
+ // To read accurately if we do it ourselves, see
+ // Clinger, "How to read floating point numbers accurately"
+ // https://dl.acm.org/doi/10.1145/93542.93557.
+ let i0 = i0 - sign as u32;
+ let mut s = self.src[i0 as usize..i1 as usize].to_string();
+ s.retain(|c| c != '_');
+ s.parse::<f64>().map(|x| Token { tok: Tok::Float(x), offset: i0 }).map_err(|_| LexErr {
+ expected: LexThing::Descr("float literal that's not way too damn big or whatever's going on here"),
+ found: LexThing::Anon,
+ loc: Loc::new(self.file, i0),
+ })
+ } else {
+ let x = self.src[i0 as usize..i1 as usize]
+ .bytes()
+ .filter(|&c| c != b'_')
+ .fold(0u128, |x, c| x.saturating_mul(10).saturating_add((c - b'0') as u128));
+ if (sign && x > i128::MIN as u128) || (!sign && x > i128::MAX as u128) {
+ Err(LexErr {
+ expected: LexThing::Descr("integer literal within the range of a 128-bit signed integer [-170141183460469231731687303715884105728, 170141183460469231731687303715884105727]"),
+ found: LexThing::Descr("integer literal with a greater magnitude than that"),
+ loc: Loc::new(self.file, i0),
+ })
+ } else {
+ Ok(Token { tok: Tok::Int(if sign { (x as i128).overflowing_neg().0 } else { x as i128 }), offset: i0 })
}
- self.consume();
}
}
@@ 366,12 376,21 @@ mod test {
#[test]
fn test_int() {
- assert!(matches!(Scanner::new(None, "123_456").num(), Ok(Token { tok: Tok::Int(123456), .. })))
+ assert!(matches!(Scanner::new(None, "123_456").num(false).unwrap(), Token { tok: Tok::Int(123456), .. }))
}
#[test]
fn test_float() {
- assert!(matches!(Scanner::new(None, "1_2.03_4").num(), Ok(Token { tok: Tok::Float(x), .. }) if x == 12.034))
+ assert!(
+ matches!(Scanner::new(None, "1_2.03_4").num(false).unwrap(), Token { tok: Tok::Float(x), .. } if x == 12.034)
+ )
+ }
+
+ #[test]
+ fn test_neg_float() {
+ assert!(
+ matches!(Scanner::new(None, "-1_2._03__4").maybe_term().unwrap().unwrap(), Token { tok: Tok::Float(x), .. } if x == -12.034)
+ )
}
#[test]
M src/main.rs => src/main.rs +60 -24
@@ 75,47 75,51 @@ mod test {
use diag::Result;
use eval::*;
- fn run_tmp(main_src: &str) -> std::result::Result<Operand, String> {
+ fn run_tmp(main_src: &str) -> Result<Operand> {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("main.fm"), main_src).unwrap();
let mut cache = Cache::for_package_in(dir.path());
- with_pretty_errors(&mut cache, |cache| {
- let main_id =
- cache.fetch_global_resolved_name(&name_in_cli(&["own", "main", "main"])).unwrap().as_def().unwrap();
+ let r = (|cache: &mut Cache| {
+ let main_id = cache.fetch_global_resolved_name(&name_in_cli(&["own", "main", "main"]))?.as_def().unwrap();
cache.fetch_evaluated(main_id).cloned()
- })
+ })(&mut cache);
+ if let Err(e) = &r {
+ eprintln!("{}", e.render(&mut cache));
+ }
+ r
}
- fn run_tmp_multi(app_module: &[&str], files: &[(&str, &str)]) -> std::result::Result<Operand, String> {
+ fn run_tmp_multi(app_module: &[&str], files: &[(&str, &str)]) -> Result<Operand> {
let dir = tempfile::tempdir().unwrap();
for (path, src) in files {
std::fs::write(dir.path().join(Path::new(path)), src).unwrap();
}
let mut cache = Cache::for_package_in(dir.path());
- with_pretty_errors(&mut cache, |cache| {
- let main_id = cache
- .fetch_global_resolved_name(&name_in_cli(&[app_module, &["main"]].concat()))
- .unwrap()
- .as_def()
- .unwrap();
+ let r = (|cache: &mut Cache| {
+ let main_id =
+ cache.fetch_global_resolved_name(&name_in_cli(&[app_module, &["main"]].concat()))?.as_def().unwrap();
cache.fetch_evaluated(main_id).cloned()
- })
+ })(&mut cache);
+ if let Err(e) = &r {
+ eprintln!("{}", e.render(&mut cache));
+ }
+ r
}
#[test]
fn test_main_literal() {
- assert!(matches!(run_tmp("(def main 123.456)").unwrap(), Operand::Const(Const::F64(x)) if x == 123.456))
+ assert!(matches!(run_tmp("(def main 123.456)"), Ok(Operand::Const(Const::F64(x))) if x == 123.456))
}
#[test]
fn test_main_arithm1() {
- assert!(matches!(run_tmp("(def main (+.prim. 1.0 2.0))").unwrap(), Operand::Const(Const::F64(x)) if x == 3.0))
+ assert!(matches!(run_tmp("(def main (+f.prim. 1.0 2.0))"), Ok(Operand::Const(Const::F64(x))) if x == 3.0))
}
#[test]
fn test_main_arithm2() {
assert!(
- matches!(run_tmp("(def main (+.prim. (*.prim. 13.0 100.0) 37.0))").unwrap(), Operand::Const(Const::F64(x)) if x == 1337.0)
+ matches!(run_tmp("(def main (+f.prim. (*f.prim. 13.0 100.0) 37.0))"), Ok(Operand::Const(Const::F64(x))) if x == 1337.0)
)
}
@@ 123,9 127,9 @@ mod test {
fn test_main_arithm_var() {
let src = "
(def x 1300.0)
- (def main (+ x 37.0))
+ (def main (+f x 37.0))
";
- assert!(matches!(run_tmp(src).unwrap(), Operand::Const(Const::F64(x)) if x == 1337.0))
+ assert!(matches!(run_tmp(src), Ok(Operand::Const(Const::F64(x))) if x == 1337.0))
}
#[test]
@@ 133,9 137,9 @@ mod test {
let src = "
(def main (double 21.0))
(def double (of (Fun [F64] F64)
- (fun [x] (* x 2.0))))
+ (fun [x] (*f x 2.0))))
";
- assert!(matches!(run_tmp(src).unwrap(), Operand::Const(Const::F64(x)) if x == 42.0))
+ assert!(matches!(run_tmp(src), Ok(Operand::Const(Const::F64(x))) if x == 42.0))
}
#[test]
@@ 149,20 153,52 @@ mod test {
#[test]
fn test_modules1() {
let main_src = "(def main (double.double.own. 21.0))";
- let double_src = "(def double (of (Fun [F64] F64) (fun [x] (* x 2.0))))";
+ let double_src = "(def double (of (Fun [F64] F64) (fun [x] (*f x 2.0))))";
assert!(matches!(run_tmp_multi(&["own", "main"], &[
("main.fm", main_src),
("double.fm", double_src)
- ]).unwrap(), Operand::Const(Const::F64(x)) if x == 42.0))
+ ]), Ok(Operand::Const(Const::F64(x))) if x == 42.0))
}
#[test]
fn test_modules2() {
let main_src = "(def main (double.own. 21.0))";
- let lib_src = "(def double (of (Fun [F64] F64) (fun [x] (* x 2.0))))";
+ let lib_src = "(def double (of (Fun [F64] F64) (fun [x] (*f x 2.0))))";
assert!(matches!(run_tmp_multi(&["own", "main"], &[
("main.fm", main_src),
("lib.fm", lib_src)
- ]).unwrap(), Operand::Const(Const::F64(x)) if x == 42.0))
+ ]), Ok(Operand::Const(Const::F64(x))) if x == 42.0))
+ }
+
+ #[test]
+ fn test_add_ints() {
+ let src = "
+ (def main (+ 40 2))
+ ";
+ assert!(matches!(run_tmp(src), Ok(Operand::Const(Const::Int(42)))))
+ }
+
+ #[test]
+ fn test_add_neg_ints() {
+ let src = "
+ (def main (+ -40 -2))
+ ";
+ assert!(matches!(run_tmp(src), Ok(Operand::Const(Const::Int(-42)))))
+ }
+
+ #[test]
+ fn test_check_i8() {
+ let src = "
+ (def main (of I8 42))
+ ";
+ assert!(matches!(run_tmp(src), Ok(Operand::Const(Const::I8(42)))))
+ }
+
+ #[test]
+ fn test_type_err_add_i8_int() {
+ let src = "
+ (def main (+ (of I8 40) 2))
+ ";
+ assert!(run_tmp(src).is_err())
}
}
M src/name.rs => src/name.rs +6 -2
@@ 53,8 53,10 @@ pub struct FileId(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Prim {
- Add = 0,
- Mul = 1,
+ Add,
+ Mul,
+ AddF,
+ MulF,
}
impl fmt::Display for Prim {
@@ 65,6 67,8 @@ impl fmt::Display for Prim {
match self {
Prim::Add => "+",
Prim::Mul => "*",
+ Prim::AddF => "+f",
+ Prim::MulF => "*f",
}
)
}
M src/parse.rs => src/parse.rs +54 -12
@@ 30,6 30,7 @@ pub struct Expr {
#[derive(Debug, Clone)]
pub enum ExprKind {
+ Int(i128),
F64(f64),
Fun(Vec<PrivIdent>, Box<Expr>),
App(Box<Expr>, Vec<Expr>),
@@ 39,6 40,9 @@ pub enum ExprKind {
#[derive(Debug, Clone, PartialEq)]
pub enum Type {
+ Int { width: u8, signed: bool },
+ ISize,
+ NSize,
F64,
Fun(Vec<Type>, Box<Type>),
}
@@ 46,6 50,10 @@ pub enum Type {
impl std::fmt::Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
+ Type::Int { width, signed: true } => write!(f, "I{width}"),
+ Type::Int { width, signed: false } => write!(f, "N{width}"),
+ Type::ISize => write!(f, "Int"),
+ Type::NSize => write!(f, "Nat"),
Type::F64 => write!(f, "F64"),
Type::Fun(ps, r) => {
write!(f, "(Fun [")?;
@@ 82,9 90,9 @@ trait Parser<'s, 't, A> = FnMut(Inp<'s, 't>) -> Res<'s, 't, A> where 's: 't;
impl<'s, 't> Inp<'s, 't> {
fn next(&self) -> Res<'s, 't, &'t Token<'s>> {
match self.tokens.split_first() {
- Some((t, rest)) => Ok((Inp { tokens: rest, dist: self.dist + 1, context: self.context.clone() }, t)),
+ Some((t, rest)) => Ok((Inp { tokens: rest, dist: self.dist + 1, context: self.context }, t)),
None => Err(ParseErr {
- loc: self.context.clone(),
+ loc: self.context,
dist: self.dist,
expecteds: once("continuation of token sequence".to_string()).collect(),
}),
@@ 140,7 148,8 @@ fn def<'s: 't, 't>(inp: Inp<'s, 't>) -> Res<'s, 't, (PrivIdent, Expr)> {
fn expr<'s: 't, 't>(inp: Inp<'s, 't>) -> Res<'s, 't, Expr> {
let loc = inp.context.with_offset(inp.next()?.1.offset);
- let (inp, kind) = alt3(map(lit_float, ExprKind::F64), map(name, ExprKind::Var), parens(pexpr))(inp)?;
+ let (inp, kind) =
+ alt4(map(lit_int, ExprKind::Int), map(lit_float, ExprKind::F64), map(name, ExprKind::Var), parens(pexpr))(inp)?;
Ok((inp, Expr { loc, kind }))
}
@@ 163,7 172,23 @@ fn pexpr<'s: 't, 't>(inp: Inp<'s, 't>) -> Res<'s, 't, ExprKind> {
}
fn typ<'s: 't, 't>(inp: Inp<'s, 't>) -> Res<'s, 't, Type> {
- alt2(give(literally("F64"), Type::F64), parens(ptyp))(inp)
+ alt5(
+ alt4(
+ give(literally("I8"), Type::Int { width: 8, signed: true }),
+ give(literally("I16"), Type::Int { width: 16, signed: true }),
+ give(literally("I32"), Type::Int { width: 32, signed: true }),
+ give(literally("I64"), Type::Int { width: 64, signed: true }),
+ ),
+ alt4(
+ give(literally("N8"), Type::Int { width: 8, signed: false }),
+ give(literally("N16"), Type::Int { width: 16, signed: false }),
+ give(literally("N32"), Type::Int { width: 32, signed: false }),
+ give(literally("N64"), Type::Int { width: 64, signed: false }),
+ ),
+ alt2(give(literally("Int"), Type::ISize), give(literally("Nat"), Type::NSize)),
+ give(literally("F64"), Type::F64),
+ parens(ptyp),
+ )(inp)
}
fn ptyp<'s: 't, 't>(inp: Inp<'s, 't>) -> Res<'s, 't, Type> {
@@ 225,6 250,13 @@ fn lit_float<'s: 't, 't>(inp: Inp<'s, 't>) -> Res<'s, 't, f64> {
})
}
+fn lit_int<'s: 't, 't>(inp: Inp<'s, 't>) -> Res<'s, 't, i128> {
+ inp.filter_next(|t| match t.tok {
+ Tok::Int(x) => Ok(x),
+ _ => Err("*integer literal*"),
+ })
+}
+
// fn lit_int<'s: 't, 't>(inp: Inp<'s, 't>) -> Res<'s, 't, i64> {
// inp.filter_next(|tok| match *tok {
// Tok::Int(x) => Ok(x),
@@ 301,14 333,24 @@ fn alt3<'s: 't, 't, A>(
alt2(f, alt2(g, h))
}
-// fn alt4<'s: 't, 't, A>(
-// f: impl Parser<'s, 't, A>,
-// g: impl Parser<'s, 't, A>,
-// h: impl Parser<'s, 't, A>,
-// i: impl Parser<'s, 't, A>,
-// ) -> impl Parser<'s, 't, A> {
-// alt2(alt2(f, g), alt2(h, i))
-// }
+fn alt4<'s: 't, 't, A>(
+ f: impl Parser<'s, 't, A>,
+ g: impl Parser<'s, 't, A>,
+ h: impl Parser<'s, 't, A>,
+ i: impl Parser<'s, 't, A>,
+) -> impl Parser<'s, 't, A> {
+ alt2(alt2(f, g), alt2(h, i))
+}
+
+fn alt5<'s: 't, 't, A>(
+ f: impl Parser<'s, 't, A>,
+ g: impl Parser<'s, 't, A>,
+ h: impl Parser<'s, 't, A>,
+ i: impl Parser<'s, 't, A>,
+ j: impl Parser<'s, 't, A>,
+) -> impl Parser<'s, 't, A> {
+ alt3(alt2(f, g), alt2(h, i), j)
+}
fn many0<'s: 't, 't, A>(mut f: impl Parser<'s, 't, A>) -> impl Parser<'s, 't, Vec<A>> {
move |mut inp| {
M src/resolve.rs => src/resolve.rs +2 -0
@@ 18,6 18,7 @@ pub struct Expr {
#[derive(Debug, Clone)]
pub enum ExprKind {
+ Int(i128),
F64(f64),
Fun(Vec<(PubIdent, LocalId)>, Box<Expr>),
App(Box<Expr>, Vec<Expr>),
@@ 49,6 50,7 @@ impl<'c> Resolver<'c> {
use parse::ExprKind as Pek;
use ExprKind as Ek;
let kind = match &e.kind {
+ Pek::Int(x) => Ek::Int(*x),
Pek::F64(x) => Ek::F64(*x),
Pek::Fun(params, body) => {
let rparams =