Support Record patterns
This commit is contained in:
parent
a3f2539993
commit
4c6a93302d
@ -1123,7 +1123,11 @@ impl Parser {
|
||||
let pat = self.pattern()?;
|
||||
(name, pat)
|
||||
}
|
||||
_ => (name.clone(), Pattern::Literal(PatternLiteral::StringPattern(name))),
|
||||
_ => {
|
||||
let qualified_identifier =
|
||||
QualifiedName { id: self.id_store.fresh(), components: vec![name.clone()] };
|
||||
(name, Pattern::VarOrName(qualified_identifier))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1099,10 +1099,7 @@ fn pattern_matching() {
|
||||
body: bx(IfExpressionBody::SimplePatternMatch {
|
||||
pattern: Pattern::Record(
|
||||
qn!(Something),
|
||||
vec![
|
||||
(rc("a"), Pattern::Literal(PatternLiteral::StringPattern(rc("a")))),
|
||||
(rc("b"), Pattern::VarOrName(qn!(x)))
|
||||
]
|
||||
vec![(rc("a"), Pattern::VarOrName(qn!(a))), (rc("b"), Pattern::VarOrName(qn!(x)))]
|
||||
),
|
||||
then_case: vec![exst(NatLiteral(4))].into(),
|
||||
else_case: Some(vec![exst(NatLiteral(9))].into()),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{collections::HashMap, str::FromStr};
|
||||
use std::{collections::HashMap, rc::Rc, str::FromStr};
|
||||
|
||||
use crate::{
|
||||
ast,
|
||||
@ -149,10 +149,9 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
||||
}),
|
||||
NamedStruct { name, fields } => {
|
||||
self.symbol_table.debug();
|
||||
println!("Namedstruct name {} id: {}", name, name.id);
|
||||
let symbol = self.symbol_table.lookup_symbol(&name.id).unwrap();
|
||||
let (tag, type_id) = match symbol.spec() {
|
||||
SymbolSpec::RecordConstructor { tag, members: _, type_id } => (tag, type_id),
|
||||
SymbolSpec::RecordConstructor { tag, type_id } => (tag, type_id),
|
||||
e => return Expression::ReductionError(format!("Bad symbol for NamedStruct: {:?}", e)),
|
||||
};
|
||||
|
||||
@ -279,7 +278,6 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
||||
}
|
||||
|
||||
fn prefix(&mut self, prefix: &ast::PrefixOp, arg: &ast::Expression) -> Expression {
|
||||
println!("PREFIX: {:?} and ARG: {:?}", prefix, arg);
|
||||
let builtin: Option<Builtin> = TryFrom::try_from(prefix).ok();
|
||||
match builtin {
|
||||
Some(op) => Expression::Call {
|
||||
@ -395,11 +393,27 @@ impl ast::Pattern {
|
||||
spec => return Err(format!("Unexpected VarOrName symbol: {:?}", spec).into()),
|
||||
}
|
||||
}
|
||||
ast::Pattern::Record(name, _specified_members /*Vec<(Rc<String>, Pattern)>*/) => {
|
||||
ast::Pattern::Record(name, specified_members) => {
|
||||
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
|
||||
match symbol.spec() {
|
||||
SymbolSpec::RecordConstructor { tag: _, members: _, type_id: _ } => unimplemented!(),
|
||||
spec => return Err(format!("Unexpected Record pattern symbol: {:?}", spec).into()),
|
||||
if let SymbolSpec::RecordConstructor { tag, type_id: _ } = symbol.spec() {
|
||||
//TODO do this computation from the type_id
|
||||
/*
|
||||
if specified_members.iter().any(|(member, _)| !members.contains_key(member)) {
|
||||
return Err(format!("Unknown key in record pattern").into());
|
||||
}
|
||||
*/
|
||||
|
||||
let subpatterns: Result<Vec<(Rc<String>, Pattern)>, PatternError> = specified_members
|
||||
.iter()
|
||||
.map(|(name, pat)| {
|
||||
pat.reduce(symbol_table).map(|reduced_pat| (name.clone(), reduced_pat))
|
||||
})
|
||||
.into_iter()
|
||||
.collect();
|
||||
let subpatterns = subpatterns?;
|
||||
Pattern::Record { tag, subpatterns }
|
||||
} else {
|
||||
return Err(format!("Unexpected Record pattern symbol: {:?}", symbol.spec()).into());
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -108,6 +108,7 @@ pub struct Alternative {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Pattern {
|
||||
Tuple { subpatterns: Vec<Pattern>, tag: Option<u32> },
|
||||
Record { tag: u32, subpatterns: Vec<(Rc<String>, Pattern)> },
|
||||
Literal(Literal),
|
||||
Ignored,
|
||||
Binding(DefId),
|
||||
|
@ -282,7 +282,7 @@ pub enum SymbolSpec {
|
||||
Builtin(Builtin),
|
||||
Func,
|
||||
DataConstructor { tag: u32, type_id: TypeId },
|
||||
RecordConstructor { tag: u32, members: HashMap<Rc<String>, TypeId>, type_id: TypeId },
|
||||
RecordConstructor { tag: u32, type_id: TypeId },
|
||||
GlobalBinding, //Only for global variables, not for function-local ones or ones within a `let` scope context
|
||||
LocalVariable,
|
||||
FunctionParam(u8),
|
||||
@ -515,8 +515,7 @@ impl<'a> SymbolTableRunner<'a> {
|
||||
let spec = match &variant.members {
|
||||
type_inference::VariantMembers::Unit => SymbolSpec::DataConstructor { tag, type_id },
|
||||
type_inference::VariantMembers::Tuple(..) => SymbolSpec::DataConstructor { tag, type_id },
|
||||
type_inference::VariantMembers::Record(..) =>
|
||||
SymbolSpec::RecordConstructor { tag, members: HashMap::new(), type_id },
|
||||
type_inference::VariantMembers::Record(..) => SymbolSpec::RecordConstructor { tag, type_id },
|
||||
};
|
||||
self.table.add_symbol(id, fqsn, spec);
|
||||
}
|
||||
|
@ -261,6 +261,20 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
||||
_ => false,
|
||||
},
|
||||
},
|
||||
Pattern::Record { tag: pattern_tag, subpatterns } => match scrut {
|
||||
//TODO several types of possible error here
|
||||
Primitive::Object { tag, items, ordered_fields: Some(ordered_fields), .. }
|
||||
if tag == pattern_tag =>
|
||||
subpatterns.iter().all(|(field_name, subpat)| {
|
||||
let idx = ordered_fields
|
||||
.iter()
|
||||
.position(|field| field.as_str() == field_name.as_ref())
|
||||
.unwrap();
|
||||
let item = &items[idx];
|
||||
matches(item, subpat, scope)
|
||||
}),
|
||||
_ => false,
|
||||
},
|
||||
}
|
||||
}
|
||||
let cond = self.expression(cond)?;
|
||||
|
@ -172,6 +172,29 @@ if x {
|
||||
eval_assert(&source, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn record_patterns() {
|
||||
let source = r#"
|
||||
type Ara = Kueh { a: Int, b: String } | Morbuk
|
||||
|
||||
let alpha = Ara::Kueh { a: 10, b: "sanchez" }
|
||||
if alpha {
|
||||
is Ara::Kueh { a, b } then (b, a)
|
||||
is _ then ("nooo", 8888)
|
||||
}"#;
|
||||
eval_assert(source, r#"("sanchez", 10)"#);
|
||||
|
||||
let source = r#"
|
||||
type Ara = Kueh { a: Int, b: String } | Morbuk
|
||||
|
||||
let alpha = Ara::Kueh { a: 10, b: "sanchez" }
|
||||
if alpha {
|
||||
is Ara::Kueh { a, b: le_value } then (le_value, (a*2))
|
||||
is _ then ("nooo", 8888)
|
||||
}"#;
|
||||
eval_assert(source, r#"("sanchez", 20)"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_is_patterns() {
|
||||
let source = r#"
|
||||
|
Loading…
Reference in New Issue
Block a user