Conditional match expressions. I can't help but feel I'm committing some kind of crime against programming language design here.
This commit is contained in:
parent
9080dc6f1e
commit
e600d59f6e
|
@ -76,6 +76,12 @@ pub enum Instruction {
|
||||||
pattern_template: AnyValue,
|
pattern_template: AnyValue,
|
||||||
expr: Expr,
|
expr: Expr,
|
||||||
},
|
},
|
||||||
|
Cond {
|
||||||
|
value_var: String,
|
||||||
|
pattern_template: AnyValue,
|
||||||
|
on_match: Box<Instruction>,
|
||||||
|
on_nomatch: Box<Instruction>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -477,6 +483,17 @@ impl Env {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Instruction::Cond { value_var, pattern_template, on_match, on_nomatch } => {
|
||||||
|
let (binding_names, pattern) = self.instantiate_pattern(pattern_template)?;
|
||||||
|
let value = self.lookup(value_var, "value in conditional expression")?;
|
||||||
|
match pattern.match_value(&value) {
|
||||||
|
None => self.eval(t, on_nomatch)?,
|
||||||
|
Some(captures) => {
|
||||||
|
self.extend(&binding_names, captures);
|
||||||
|
self.eval(t, on_match)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -664,7 +681,7 @@ impl<'t> Parser<'t> {
|
||||||
T::default()
|
T::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self, target: &str) -> Parsed<Instruction> {
|
pub fn parse(&mut self, target: &str, outer_target: &str) -> Parsed<Instruction> {
|
||||||
if self.ateof() {
|
if self.ateof() {
|
||||||
return Parsed::Eof;
|
return Parsed::Eof;
|
||||||
}
|
}
|
||||||
|
@ -679,7 +696,7 @@ impl<'t> Parser<'t> {
|
||||||
if let Some(tokens) = self.peek().as_sequence() {
|
if let Some(tokens) = self.peek().as_sequence() {
|
||||||
self.drop();
|
self.drop();
|
||||||
let mut inner_parser = Parser::new(tokens);
|
let mut inner_parser = Parser::new(tokens);
|
||||||
let instructions = inner_parser.parse_all(target);
|
let instructions = inner_parser.parse_all(target, outer_target);
|
||||||
self.errors.extend(inner_parser.errors);
|
self.errors.extend(inner_parser.errors);
|
||||||
return Parsed::Value(Instruction::Sequence { instructions });
|
return Parsed::Value(Instruction::Sequence { instructions });
|
||||||
}
|
}
|
||||||
|
@ -694,7 +711,7 @@ impl<'t> Parser<'t> {
|
||||||
Instruction::During { target, pattern_template, body } },
|
Instruction::During { target, pattern_template, body } },
|
||||||
"?" => |target, pattern_template, body| { // "??"
|
"?" => |target, pattern_template, body| { // "??"
|
||||||
Instruction::OnMessage { target, pattern_template, body } },
|
Instruction::OnMessage { target, pattern_template, body } },
|
||||||
"-" => match self.parse(target) { // "?-"
|
"-" => match self.parse(target, outer_target) { // "?-"
|
||||||
Parsed::Value(i) => return Parsed::Value(Instruction::OnStop {
|
Parsed::Value(i) => return Parsed::Value(Instruction::OnStop {
|
||||||
body: Box::new(i),
|
body: Box::new(i),
|
||||||
}),
|
}),
|
||||||
|
@ -709,7 +726,7 @@ impl<'t> Parser<'t> {
|
||||||
}
|
}
|
||||||
let pattern_template = self.shift();
|
let pattern_template = self.shift();
|
||||||
|
|
||||||
return match self.parse(target) {
|
return match self.parse(target, outer_target) {
|
||||||
Parsed::Eof =>
|
Parsed::Eof =>
|
||||||
self.error(format!(
|
self.error(format!(
|
||||||
"Missing instruction in react with pattern {:?}",
|
"Missing instruction in react with pattern {:?}",
|
||||||
|
@ -733,7 +750,7 @@ impl<'t> Parser<'t> {
|
||||||
let m = format!("Missing instruction after retarget: {:?}", self.peek());
|
let m = format!("Missing instruction after retarget: {:?}", self.peek());
|
||||||
return self.error(m);
|
return self.error(m);
|
||||||
}
|
}
|
||||||
return self.parse(&s);
|
return self.parse(&s, target);
|
||||||
}
|
}
|
||||||
Symbolic::Bare(s) => {
|
Symbolic::Bare(s) => {
|
||||||
if s == "let" {
|
if s == "let" {
|
||||||
|
@ -774,26 +791,30 @@ impl<'t> Parser<'t> {
|
||||||
}
|
}
|
||||||
Symbolic::Literal(s) => {
|
Symbolic::Literal(s) => {
|
||||||
if s == "~" { // "=~"
|
if s == "~" { // "=~"
|
||||||
// s.drop();
|
self.drop();
|
||||||
// if self.ateof() {
|
if self.ateof() {
|
||||||
// return self.error("Missing pattern, true-instruction and false-continuation in match");
|
return self.error("Missing pattern, true-instruction and false-continuation in match");
|
||||||
// }
|
}
|
||||||
// let match_template = self.shift();
|
let match_template = self.shift();
|
||||||
// return match self.parse(target) {
|
return match self.parse(outer_target, outer_target) {
|
||||||
// Parsed::Eof =>
|
Parsed::Eof =>
|
||||||
// self.error(format!(
|
self.error(format!(
|
||||||
// "Missing true-instruction in conditional with pattern {:?}",
|
"Missing true-instruction in conditional with pattern {:?}",
|
||||||
// match_template)),
|
match_template)),
|
||||||
// Parsed::Skip =>
|
Parsed::Skip =>
|
||||||
// Parsed::Skip,
|
Parsed::Skip,
|
||||||
// Parsed::Value(true_instruction) => {
|
Parsed::Value(true_instruction) => {
|
||||||
// let false_instructions = self.parse_all();
|
let false_instructions = self.parse_all(outer_target, outer_target);
|
||||||
// Parsed::Value(Instruction::Cond {
|
Parsed::Value(Instruction::Cond {
|
||||||
// value: target.to_owned(),
|
value_var: target.to_owned(),
|
||||||
// pattern: match_template,
|
pattern_template: match_template,
|
||||||
// on_match: true_instruction,
|
on_match: Box::new(true_instruction),
|
||||||
// on_nomatch: self.parse_all(
|
on_nomatch: Box::new(Instruction::Sequence {
|
||||||
// };
|
instructions: false_instructions,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
/* fall through */
|
/* fall through */
|
||||||
}
|
}
|
||||||
|
@ -807,10 +828,10 @@ impl<'t> Parser<'t> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_all(&mut self, target: &str) -> Vec<Instruction> {
|
pub fn parse_all(&mut self, target: &str, outer_target: &str) -> Vec<Instruction> {
|
||||||
let mut instructions = Vec::new();
|
let mut instructions = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
match self.parse(target) {
|
match self.parse(target, outer_target) {
|
||||||
Parsed::Value(i) => instructions.push(i),
|
Parsed::Value(i) => instructions.push(i),
|
||||||
Parsed::Skip => (),
|
Parsed::Skip => (),
|
||||||
Parsed::Eof => break,
|
Parsed::Eof => break,
|
||||||
|
@ -820,7 +841,7 @@ impl<'t> Parser<'t> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_top(&mut self, target: &str) -> Result<Option<Instruction>, Vec<String>> {
|
pub fn parse_top(&mut self, target: &str) -> Result<Option<Instruction>, Vec<String>> {
|
||||||
let instructions = self.parse_all(target);
|
let instructions = self.parse_all(target, target);
|
||||||
if self.errors.is_empty() {
|
if self.errors.is_empty() {
|
||||||
match instructions.len() {
|
match instructions.len() {
|
||||||
0 => Ok(None),
|
0 => Ok(None),
|
||||||
|
|
Loading…
Reference in New Issue