[sc-441] Add string patterns

This commit is contained in:
Nicolas Abril 2024-02-27 21:58:03 +01:00
parent 5d9a967713
commit 0fc957ea6e
11 changed files with 48 additions and 19 deletions

View File

@ -1,4 +1,4 @@
use super::{parser::parse_book, Book, Name, Pattern, Term}; use super::{parser::parse_book, Book, Name, NumCtr, Pattern, Term};
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"));
@ -80,6 +80,7 @@ impl Pattern {
pub fn encode_builtins(&mut self) { pub fn encode_builtins(&mut self) {
match self { match self {
Pattern::Lst(pats) => *self = Self::encode_list(std::mem::take(pats)), Pattern::Lst(pats) => *self = Self::encode_list(std::mem::take(pats)),
Pattern::Str(str) => *self = Self::encode_str(str),
Pattern::Ctr(_, pats) => { Pattern::Ctr(_, pats) => {
for pat in pats { for pat in pats {
pat.encode_builtins(); pat.encode_builtins();
@ -94,11 +95,20 @@ impl Pattern {
} }
fn encode_list(elements: Vec<Pattern>) -> Pattern { fn encode_list(elements: Vec<Pattern>) -> Pattern {
let lnil = Pattern::Var(Some(Name::from(LNIL))); let lnil = Pattern::Ctr(Name::from(LNIL), vec![]);
elements.into_iter().rfold(lnil, |acc, mut nxt| { elements.into_iter().rfold(lnil, |acc, mut nxt| {
nxt.encode_builtins(); nxt.encode_builtins();
Pattern::Ctr(Name::from(LCONS), vec![nxt, acc]) Pattern::Ctr(Name::from(LCONS), vec![nxt, acc])
}) })
} }
fn encode_str(str: &str) -> Pattern {
let lnil = Pattern::Ctr(Name::from(LNIL), vec![]);
str.chars().rfold(lnil, |tail, head| {
let head = Pattern::Num(NumCtr::Num(head as u64));
Pattern::Ctr(Name::from(LCONS), vec![head, tail])
})
}
} }

View File

@ -66,7 +66,7 @@ impl Pattern {
to_check.push(el); to_check.push(el);
} }
} }
Pattern::Var(..) | Pattern::Num(..) => {} Pattern::Var(..) | Pattern::Num(..) | Pattern::Str(_) => {}
} }
} }
Ok(()) Ok(())

View File

@ -58,7 +58,7 @@ impl Pattern {
check.push(snd); check.push(snd);
} }
Pattern::Lst(args) => args.iter().for_each(|arg| check.push(arg)), Pattern::Lst(args) => args.iter().for_each(|arg| check.push(arg)),
Pattern::Var(_) | Pattern::Num(_) => {} Pattern::Var(_) | Pattern::Num(_) | Pattern::Str(_) => {}
} }
} }
unbounds unbounds

View File

@ -111,6 +111,7 @@ impl fmt::Display for Pattern {
Pattern::Num(num) => write!(f, "{num}"), Pattern::Num(num) => write!(f, "{num}"),
Pattern::Tup(fst, snd) => write!(f, "({}, {})", fst, snd,), Pattern::Tup(fst, snd) => write!(f, "({}, {})", fst, snd,),
Pattern::Lst(pats) => write!(f, "[{}]", DisplayJoin(|| pats, ", ")), Pattern::Lst(pats) => write!(f, "[{}]", DisplayJoin(|| pats, ", ")),
Pattern::Str(str) => write!(f, "\"{str}\""),
} }
} }
} }

View File

@ -147,6 +147,7 @@ pub enum Pattern {
Num(NumCtr), Num(NumCtr),
Tup(Box<Pattern>, Box<Pattern>), Tup(Box<Pattern>, Box<Pattern>),
Lst(Vec<Pattern>), Lst(Vec<Pattern>),
Str(GlobalString),
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -640,6 +641,7 @@ impl Pattern {
set.push(nam); set.push(nam);
} }
Pattern::Num(_) => {} Pattern::Num(_) => {}
Pattern::Str(_) => {}
} }
} }
let mut set = Vec::new(); let mut set = Vec::new();
@ -664,6 +666,7 @@ impl Pattern {
Pattern::Num(_) => Box::new([].iter()), Pattern::Num(_) => Box::new([].iter()),
Pattern::Tup(fst, snd) => Box::new([fst.as_ref(), snd.as_ref()].into_iter()), Pattern::Tup(fst, snd) => Box::new([fst.as_ref(), snd.as_ref()].into_iter()),
Pattern::Lst(els) => Box::new(els.iter()), Pattern::Lst(els) => Box::new(els.iter()),
Pattern::Str(_) => Box::new([].iter()),
} }
} }
@ -687,6 +690,7 @@ impl Pattern {
Pattern::Num(NumCtr::Succ(num, _)) => Some(Name::new(format!("{num}+"))), Pattern::Num(NumCtr::Succ(num, _)) => Some(Name::new(format!("{num}+"))),
Pattern::Tup(_, _) => Some(Name::new("(,)")), Pattern::Tup(_, _) => Some(Name::new("(,)")),
Pattern::Lst(_) => todo!(), Pattern::Lst(_) => todo!(),
Pattern::Str(_) => todo!(),
} }
} }
@ -702,11 +706,12 @@ impl Pattern {
pub fn is_simple(&self) -> bool { pub fn is_simple(&self) -> bool {
match self { match self {
Pattern::Var(_) => true, Pattern::Var(_) => true,
Pattern::Ctr(_, args) | Pattern::Lst(args) => args.iter().all(|arg| matches!(arg, Pattern::Var(_))), Pattern::Ctr(_, args) => args.iter().all(|arg| matches!(arg, Pattern::Var(_))),
Pattern::Num(_) => true, Pattern::Num(_) => true,
Pattern::Tup(fst, snd) => { Pattern::Tup(fst, snd) => {
matches!(fst.as_ref(), Pattern::Var(_)) && matches!(snd.as_ref(), Pattern::Var(_)) matches!(fst.as_ref(), Pattern::Var(_)) && matches!(snd.as_ref(), Pattern::Var(_))
} }
Pattern::Lst(_) | Pattern::Str(_) => todo!(),
} }
} }
@ -721,6 +726,7 @@ impl Pattern {
Pattern::Num(NumCtr::Num(_)) => Type::Num, Pattern::Num(NumCtr::Num(_)) => Type::Num,
Pattern::Num(NumCtr::Succ(n, _)) => Type::NumSucc(*n), Pattern::Num(NumCtr::Succ(n, _)) => Type::NumSucc(*n),
Pattern::Lst(..) => Type::Adt(builtins::LIST.into()), Pattern::Lst(..) => Type::Adt(builtins::LIST.into()),
Pattern::Str(..) => Type::Adt(builtins::STRING.into()),
} }
} }
@ -736,11 +742,7 @@ impl Pattern {
Pattern::Num(NumCtr::Succ(val, Some(Some(nam)))) => Term::add_num(Term::Var { nam: nam.clone() }, *val), Pattern::Num(NumCtr::Succ(val, Some(Some(nam)))) => Term::add_num(Term::Var { nam: nam.clone() }, *val),
Pattern::Num(NumCtr::Succ(_, Some(None))) => Term::Era, Pattern::Num(NumCtr::Succ(_, Some(None))) => Term::Era,
Pattern::Tup(fst, snd) => Term::Tup { fst: Box::new(fst.to_term()), snd: Box::new(snd.to_term()) }, Pattern::Tup(fst, snd) => Term::Tup { fst: Box::new(fst.to_term()), snd: Box::new(snd.to_term()) },
Pattern::Lst(_) => { Pattern::Lst(_) | Pattern::Str(_) => todo!(),
let mut p = self.clone();
p.encode_builtins();
p.to_term()
}
} }
} }

View File

@ -405,26 +405,27 @@ where
.map(Pattern::Lst) .map(Pattern::Lst)
.boxed(); .boxed();
let num = any() let num_val = any()
.filter(|t| matches!(t, Token::Num(_))) .filter(|t| matches!(t, Token::Num(_)))
.map(|t| { .map(|t| {
let Token::Num(n) = t else { unreachable!() }; let Token::Num(n) = t else { unreachable!() };
n n
}) });
.labelled("<Num>");
let num_pat = num.map(|n| Pattern::Num(NumCtr::Num(n))); let num = num_val.map(|n| Pattern::Num(NumCtr::Num(n))).labelled("<Num>");
let succ_pat = num let succ = num_val
.then_ignore(just(Token::Add)) .then_ignore(just(Token::Add))
.then(name_or_era().or_not()) .then(name_or_era().or_not())
.map(|(num, nam)| Pattern::Num(NumCtr::Succ(num, nam))) .map(|(num, nam)| Pattern::Num(NumCtr::Succ(num, nam)))
.labelled("<Num>+") .labelled("<Num>+")
.boxed(); .boxed();
let chr_pat = select!(Token::Char(c) => Pattern::Num(NumCtr::Num(c))).labelled("<Char>").boxed(); let chr = select!(Token::Char(c) => Pattern::Num(NumCtr::Num(c))).labelled("<Char>").boxed();
choice((succ_pat, num_pat, chr_pat, var, ctr, list, tup)) let str = select!(Token::Str(s) => Pattern::Str(s)).labelled("<String>").boxed();
choice((succ, num, chr, str, var, ctr, list, tup))
}) })
} }

View File

@ -52,7 +52,8 @@ impl Term {
*p = Some(Some(Name::new(format!("{nam}-{n}")))); *p = Some(Some(Name::new(format!("{nam}-{n}"))));
} }
Pattern::Tup(_, _) => (), Pattern::Tup(_, _) => (),
Pattern::Lst(..) => unreachable!(), Pattern::Lst(..) => (),
Pattern::Str(..) => (),
} }
} }
} }

View File

@ -36,6 +36,7 @@ impl Pattern {
} }
Pattern::Var(None) => (), Pattern::Var(None) => (),
Pattern::Num(_) => (), Pattern::Num(_) => (),
Pattern::Str(_) => (),
Pattern::Tup(fst, snd) => { Pattern::Tup(fst, snd) => {
to_resolve.push(fst); to_resolve.push(fst);
to_resolve.push(snd); to_resolve.push(snd);

View File

@ -0,0 +1,6 @@
(is_as "As") = 2
(is_as "as") = 2
(is_as "") = 1
(is_as *) = 0
main = *

View File

@ -2,5 +2,5 @@
source: tests/golden_tests.rs source: tests/golden_tests.rs
input_file: tests/golden_tests/compile_file/missing_pat.hvm input_file: tests/golden_tests/compile_file/missing_pat.hvm
--- ---
At tests/golden_tests/compile_file/missing_pat.hvm:2:3: found ':' expected '(', '#', '$', <Name>, '[', '{', 'λ', 'let', 'match', '*', '|', <Num>+, <Num>, or <Char> At tests/golden_tests/compile_file/missing_pat.hvm:2:3: found ':' expected '(', '#', '$', <Name>, '[', '{', 'λ', 'let', 'match', '*', '|', <Num>+, <Num>, <Char>, or <String>
 2 | : *  2 | : *

View File

@ -0,0 +1,7 @@
---
source: tests/golden_tests.rs
input_file: tests/golden_tests/simplify_matches/match_str.hvm
---
(is_as) = λa match a { (List.cons b c): (match b { 65: λd (match d { (List.cons f g): λh (match f { 115: λ* λj (match j { (List.cons * *): λ* 0; (List.nil): λ* 2 } *); *: λ* λ* 0 } h g); (List.nil): λ* 0 } *); 97: λhb (match hb { (List.cons jb kb): λlb (match jb { 115: λ* λnb (match nb { (List.cons * *): λ* 0; (List.nil): λ* 2 } *); *: λ* λ* 0 } lb kb); (List.nil): λ* 0 } *); *: λ* 0 } c); (List.nil): 1 }
(main) = *