Support Record patterns
This commit is contained in:
parent
a3f2539993
commit
4c6a93302d
@ -1123,7 +1123,11 @@ impl Parser {
|
|||||||
let pat = self.pattern()?;
|
let pat = self.pattern()?;
|
||||||
(name, pat)
|
(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 {
|
body: bx(IfExpressionBody::SimplePatternMatch {
|
||||||
pattern: Pattern::Record(
|
pattern: Pattern::Record(
|
||||||
qn!(Something),
|
qn!(Something),
|
||||||
vec![
|
vec![(rc("a"), Pattern::VarOrName(qn!(a))), (rc("b"), Pattern::VarOrName(qn!(x)))]
|
||||||
(rc("a"), Pattern::Literal(PatternLiteral::StringPattern(rc("a")))),
|
|
||||||
(rc("b"), Pattern::VarOrName(qn!(x)))
|
|
||||||
]
|
|
||||||
),
|
),
|
||||||
then_case: vec![exst(NatLiteral(4))].into(),
|
then_case: vec![exst(NatLiteral(4))].into(),
|
||||||
else_case: Some(vec![exst(NatLiteral(9))].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::{
|
use crate::{
|
||||||
ast,
|
ast,
|
||||||
@ -149,10 +149,9 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
|||||||
}),
|
}),
|
||||||
NamedStruct { name, fields } => {
|
NamedStruct { name, fields } => {
|
||||||
self.symbol_table.debug();
|
self.symbol_table.debug();
|
||||||
println!("Namedstruct name {} id: {}", name, name.id);
|
|
||||||
let symbol = self.symbol_table.lookup_symbol(&name.id).unwrap();
|
let symbol = self.symbol_table.lookup_symbol(&name.id).unwrap();
|
||||||
let (tag, type_id) = match symbol.spec() {
|
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)),
|
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 {
|
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();
|
let builtin: Option<Builtin> = TryFrom::try_from(prefix).ok();
|
||||||
match builtin {
|
match builtin {
|
||||||
Some(op) => Expression::Call {
|
Some(op) => Expression::Call {
|
||||||
@ -395,11 +393,27 @@ impl ast::Pattern {
|
|||||||
spec => return Err(format!("Unexpected VarOrName symbol: {:?}", spec).into()),
|
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();
|
let symbol = symbol_table.lookup_symbol(&name.id).unwrap();
|
||||||
match symbol.spec() {
|
if let SymbolSpec::RecordConstructor { tag, type_id: _ } = symbol.spec() {
|
||||||
SymbolSpec::RecordConstructor { tag: _, members: _, type_id: _ } => unimplemented!(),
|
//TODO do this computation from the type_id
|
||||||
spec => return Err(format!("Unexpected Record pattern symbol: {:?}", spec).into()),
|
/*
|
||||||
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
Tuple { subpatterns: Vec<Pattern>, tag: Option<u32> },
|
Tuple { subpatterns: Vec<Pattern>, tag: Option<u32> },
|
||||||
|
Record { tag: u32, subpatterns: Vec<(Rc<String>, Pattern)> },
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Ignored,
|
Ignored,
|
||||||
Binding(DefId),
|
Binding(DefId),
|
||||||
|
@ -282,7 +282,7 @@ pub enum SymbolSpec {
|
|||||||
Builtin(Builtin),
|
Builtin(Builtin),
|
||||||
Func,
|
Func,
|
||||||
DataConstructor { tag: u32, type_id: TypeId },
|
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
|
GlobalBinding, //Only for global variables, not for function-local ones or ones within a `let` scope context
|
||||||
LocalVariable,
|
LocalVariable,
|
||||||
FunctionParam(u8),
|
FunctionParam(u8),
|
||||||
@ -515,8 +515,7 @@ impl<'a> SymbolTableRunner<'a> {
|
|||||||
let spec = match &variant.members {
|
let spec = match &variant.members {
|
||||||
type_inference::VariantMembers::Unit => SymbolSpec::DataConstructor { tag, type_id },
|
type_inference::VariantMembers::Unit => SymbolSpec::DataConstructor { tag, type_id },
|
||||||
type_inference::VariantMembers::Tuple(..) => SymbolSpec::DataConstructor { tag, type_id },
|
type_inference::VariantMembers::Tuple(..) => SymbolSpec::DataConstructor { tag, type_id },
|
||||||
type_inference::VariantMembers::Record(..) =>
|
type_inference::VariantMembers::Record(..) => SymbolSpec::RecordConstructor { tag, type_id },
|
||||||
SymbolSpec::RecordConstructor { tag, members: HashMap::new(), type_id },
|
|
||||||
};
|
};
|
||||||
self.table.add_symbol(id, fqsn, spec);
|
self.table.add_symbol(id, fqsn, spec);
|
||||||
}
|
}
|
||||||
|
@ -261,6 +261,20 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
_ => false,
|
_ => 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)?;
|
let cond = self.expression(cond)?;
|
||||||
|
@ -172,6 +172,29 @@ if x {
|
|||||||
eval_assert(&source, expected);
|
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]
|
#[test]
|
||||||
fn if_is_patterns() {
|
fn if_is_patterns() {
|
||||||
let source = r#"
|
let source = r#"
|
||||||
|
Loading…
Reference in New Issue
Block a user