1
0

Implement match logic and syntax

This commit is contained in:
Jeff 2023-12-11 10:18:46 -05:00
parent 99338dedc5
commit 06da345333
6 changed files with 5380 additions and 5249 deletions

12
examples/match.ds Normal file
View File

@ -0,0 +1,12 @@
foo_or_bar = match (random_boolean) {
true => "foo"
false => "bar"
}
num = match (random_integer) {
1 => "one",
2 => { "two" },
* => "neither",
}
[foo_or_bar, num]

View File

@ -13,6 +13,7 @@ use crate::{AbstractTree, Error, Expression, Map, Result, Statement, Type, Value
pub struct Match { pub struct Match {
matcher: Expression, matcher: Expression,
options: Vec<(Expression, Statement)>, options: Vec<(Expression, Statement)>,
fallback: Option<Box<Statement>>,
} }
impl AbstractTree for Match { impl AbstractTree for Match {
@ -24,24 +25,37 @@ impl AbstractTree for Match {
let mut options = Vec::new(); let mut options = Vec::new();
let mut previous_expression = None; let mut previous_expression = None;
let mut next_statement_is_fallback = false;
let mut fallback = None;
for index in 2..node.child_count() { for index in 2..node.child_count() {
let child = node.child(index).unwrap(); let child = node.child(index).unwrap();
if child.kind() == "*" {
next_statement_is_fallback = true;
}
if child.kind() == "expression" { if child.kind() == "expression" {
previous_expression = Some(Expression::from_syntax_node(source, child, context)?); previous_expression = Some(Expression::from_syntax_node(source, child, context)?);
} }
if child.kind() == "statement" { if child.kind() == "statement" {
if let Some(expression) = &previous_expression {
let statement = Statement::from_syntax_node(source, child, context)?; let statement = Statement::from_syntax_node(source, child, context)?;
if next_statement_is_fallback {
fallback = Some(Box::new(statement));
next_statement_is_fallback = false;
} else if let Some(expression) = &previous_expression {
options.push((expression.clone(), statement)); options.push((expression.clone(), statement));
} }
} }
} }
Ok(Match { matcher, options }) Ok(Match {
matcher,
options,
fallback,
})
} }
fn run(&self, source: &str, context: &Map) -> Result<Value> { fn run(&self, source: &str, context: &Map) -> Result<Value> {
@ -55,8 +69,12 @@ impl AbstractTree for Match {
} }
} }
if let Some(fallback) = &self.fallback {
fallback.run(source, context)
} else {
Ok(Value::Empty) Ok(Value::Empty)
} }
}
fn expected_type(&self, _context: &Map) -> Result<Type> { fn expected_type(&self, _context: &Map) -> Result<Type> {
todo!() todo!()

View File

@ -1,4 +1,4 @@
use serde::{ser::SerializeMap, Deserialize, Serialize}; use serde::{ser::SerializeMap, Serialize};
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
collections::BTreeMap, collections::BTreeMap,

View File

@ -285,9 +285,13 @@ module.exports = grammar({
'{', '{',
repeat1( repeat1(
seq( seq(
choice(
$.expression, $.expression,
'*',
),
'=>', '=>',
$.statement, $.statement,
optional(','),
), ),
), ),
'}', '}',

View File

@ -894,11 +894,20 @@
"type": "REPEAT1", "type": "REPEAT1",
"content": { "content": {
"type": "SEQ", "type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [ "members": [
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "expression" "name": "expression"
}, },
{
"type": "STRING",
"value": "*"
}
]
},
{ {
"type": "STRING", "type": "STRING",
"value": "=>" "value": "=>"
@ -906,6 +915,18 @@
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "statement" "name": "statement"
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
} }
] ]
} }

File diff suppressed because it is too large Load Diff