Skip to content

Commit 48153db

Browse files
committed
Lay the groundworks for pattern matching
1 parent 8f928cd commit 48153db

18 files changed

+192
-25
lines changed

crates/rune/src/eval/ir.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use crate::eval::prelude::*;
22

33
/// Eval the interior expression.
44
impl Eval<&Ir> for IrInterpreter<'_> {
5-
fn eval(&mut self, ir: &Ir, used: Used) -> Result<IrValue, EvalOutcome> {
5+
type Output = IrValue;
6+
7+
fn eval(&mut self, ir: &Ir, used: Used) -> Result<Self::Output, EvalOutcome> {
68
self.budget.take(ir)?;
79

810
match &ir.kind {
@@ -16,7 +18,10 @@ impl Eval<&Ir> for IrInterpreter<'_> {
1618
IrKind::Value(const_value) => Ok(IrValue::from_const(const_value.clone())),
1719
IrKind::Branches(branches) => self.eval(branches, used),
1820
IrKind::Loop(ir_loop) => self.eval(ir_loop, used),
19-
IrKind::Break(ir_break) => self.eval(ir_break, used),
21+
IrKind::Break(ir_break) => {
22+
self.eval(ir_break, used)?;
23+
Ok(IrValue::Unit)
24+
}
2025
IrKind::Vec(ir_vec) => self.eval(ir_vec, used),
2126
IrKind::Tuple(ir_tuple) => self.eval(ir_tuple, used),
2227
IrKind::Object(ir_object) => self.eval(ir_object, used),

crates/rune/src/eval/ir_binary.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::eval::prelude::*;
22

33
impl Eval<&IrBinary> for IrInterpreter<'_> {
4-
fn eval(&mut self, ir_binary: &IrBinary, used: Used) -> Result<IrValue, EvalOutcome> {
4+
type Output = IrValue;
5+
6+
fn eval(&mut self, ir_binary: &IrBinary, used: Used) -> Result<Self::Output, EvalOutcome> {
57
let span = ir_binary.span();
68
self.budget.take(span)?;
79

crates/rune/src/eval/ir_branches.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
use crate::eval::prelude::*;
22

33
impl Eval<&IrBranches> for IrInterpreter<'_> {
4-
fn eval(&mut self, ir_branches: &IrBranches, used: Used) -> Result<IrValue, EvalOutcome> {
5-
for (ir, branch) in &ir_branches.branches {
6-
if ir.as_bool(self, used)? {
7-
return self.eval(branch, used);
4+
type Output = IrValue;
5+
6+
fn eval(&mut self, ir_branches: &IrBranches, used: Used) -> Result<Self::Output, EvalOutcome> {
7+
for (ir_condition, branch) in &ir_branches.branches {
8+
let guard = self.scopes.push();
9+
10+
let output = if self.eval(ir_condition, used)? {
11+
Some(self.eval(branch, used)?)
12+
} else {
13+
None
14+
};
15+
16+
self.scopes.pop(branch, guard)?;
17+
18+
if let Some(output) = output {
19+
return Ok(output);
820
}
921
}
1022

crates/rune/src/eval/ir_break.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::eval::prelude::*;
22

33
impl Eval<&IrBreak> for IrInterpreter<'_> {
4-
fn eval(&mut self, ir_break: &IrBreak, used: Used) -> Result<IrValue, EvalOutcome> {
4+
type Output = ();
5+
6+
fn eval(&mut self, ir_break: &IrBreak, used: Used) -> Result<(), EvalOutcome> {
57
let span = ir_break.span();
68
self.budget.take(span)?;
79

crates/rune/src/eval/ir_condition.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
use crate::eval::prelude::*;
2+
3+
impl Eval<&IrCondition> for IrInterpreter<'_> {
4+
type Output = bool;
5+
6+
fn eval(
7+
&mut self,
8+
ir_condition: &IrCondition,
9+
used: Used,
10+
) -> Result<Self::Output, EvalOutcome> {
11+
match ir_condition {
12+
IrCondition::Ir(ir) => Ok(ir.as_bool(self, used)?),
13+
IrCondition::Let(ir_let) => {
14+
let value = self.eval(&ir_let.ir, used)?;
15+
Ok(ir_let.pat.matches(self, value, used, ir_condition)?)
16+
}
17+
}
18+
}
19+
}

crates/rune/src/eval/ir_decl.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::eval::prelude::*;
22

33
impl Eval<&IrDecl> for IrInterpreter<'_> {
4-
fn eval(&mut self, im_decl: &IrDecl, used: Used) -> Result<IrValue, EvalOutcome> {
4+
type Output = IrValue;
5+
6+
fn eval(&mut self, im_decl: &IrDecl, used: Used) -> Result<Self::Output, EvalOutcome> {
57
self.budget.take(im_decl)?;
68
let value = self.eval(&*im_decl.value, used)?;
79
self.scopes.decl(&im_decl.name, value, im_decl)?;

crates/rune/src/eval/ir_loop.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
use crate::eval::prelude::*;
22

33
impl Eval<&IrLoop> for IrInterpreter<'_> {
4+
type Output = IrValue;
5+
46
fn eval(&mut self, ir_loop: &IrLoop, used: Used) -> Result<IrValue, EvalOutcome> {
57
let span = ir_loop.span();
68
self.budget.take(span)?;
79

10+
let guard = self.scopes.push();
11+
812
loop {
913
if let Some(condition) = &ir_loop.condition {
10-
if !condition.as_bool(self, used)? {
14+
self.scopes.clear_current(&*condition)?;
15+
16+
if !self.eval(&**condition, used)? {
1117
break;
1218
}
1319
}
@@ -40,6 +46,7 @@ impl Eval<&IrLoop> for IrInterpreter<'_> {
4046
};
4147
}
4248

49+
self.scopes.pop(ir_loop, guard)?;
4350
Ok(IrValue::Unit)
4451
}
4552
}

crates/rune/src/eval/ir_object.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use crate::collections::HashMap;
22
use crate::eval::prelude::*;
33

44
impl Eval<&IrObject> for IrInterpreter<'_> {
5-
fn eval(&mut self, ir_object: &IrObject, used: Used) -> Result<IrValue, EvalOutcome> {
5+
type Output = IrValue;
6+
7+
fn eval(&mut self, ir_object: &IrObject, used: Used) -> Result<Self::Output, EvalOutcome> {
68
let mut object = HashMap::with_capacity(ir_object.assignments.len());
79

810
for (key, value) in ir_object.assignments.iter() {

crates/rune/src/eval/ir_scope.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::eval::prelude::*;
22

33
impl Eval<&IrScope> for IrInterpreter<'_> {
4-
fn eval(&mut self, ir_scope: &IrScope, used: Used) -> Result<IrValue, EvalOutcome> {
4+
type Output = IrValue;
5+
6+
fn eval(&mut self, ir_scope: &IrScope, used: Used) -> Result<Self::Output, EvalOutcome> {
57
self.budget.take(ir_scope)?;
68
let guard = self.scopes.push();
79

crates/rune/src/eval/ir_set.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::eval::prelude::*;
22

33
impl Eval<&IrSet> for IrInterpreter<'_> {
4-
fn eval(&mut self, ir_set: &IrSet, used: Used) -> Result<IrValue, EvalOutcome> {
4+
type Output = IrValue;
5+
6+
fn eval(&mut self, ir_set: &IrSet, used: Used) -> Result<Self::Output, EvalOutcome> {
57
self.budget.take(ir_set)?;
68
let value = self.eval(&*ir_set.value, used)?;
79
self.scopes.set_target(&ir_set.target, value)?;

crates/rune/src/eval/ir_template.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use crate::eval::prelude::*;
22
use std::fmt::Write as _;
33

44
impl Eval<&IrTemplate> for IrInterpreter<'_> {
5-
fn eval(&mut self, ir_template: &IrTemplate, used: Used) -> Result<IrValue, EvalOutcome> {
5+
type Output = IrValue;
6+
7+
fn eval(&mut self, ir_template: &IrTemplate, used: Used) -> Result<Self::Output, EvalOutcome> {
68
self.budget.take(ir_template)?;
79

810
let mut buf = String::new();

crates/rune/src/eval/ir_tuple.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::eval::prelude::*;
22

33
impl Eval<&IrTuple> for IrInterpreter<'_> {
4-
fn eval(&mut self, ir_tuple: &IrTuple, used: Used) -> Result<IrValue, EvalOutcome> {
4+
type Output = IrValue;
5+
6+
fn eval(&mut self, ir_tuple: &IrTuple, used: Used) -> Result<Self::Output, EvalOutcome> {
57
let mut items = Vec::with_capacity(ir_tuple.items.len());
68

79
for item in ir_tuple.items.iter() {

crates/rune/src/eval/ir_vec.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use crate::eval::prelude::*;
22

33
impl Eval<&IrVec> for IrInterpreter<'_> {
4-
fn eval(&mut self, ir_vec: &IrVec, used: Used) -> Result<IrValue, EvalOutcome> {
4+
type Output = IrValue;
5+
6+
fn eval(&mut self, ir_vec: &IrVec, used: Used) -> Result<Self::Output, EvalOutcome> {
57
let mut vec = Vec::with_capacity(ir_vec.items.len());
68

79
for item in ir_vec.items.iter() {

crates/rune/src/eval/mod.rs

+40-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::ir::IrPat;
12
use crate::ir_interpreter::IrInterpreter;
23
use crate::ir_value::IrValue;
34
use crate::{CompileError, ParseError, Spanned};
@@ -7,6 +8,7 @@ mod ir;
78
mod ir_binary;
89
mod ir_branches;
910
mod ir_break;
11+
mod ir_condition;
1012
mod ir_decl;
1113
mod ir_loop;
1214
mod ir_object;
@@ -34,18 +36,33 @@ impl Used {
3436
}
3537

3638
pub(crate) trait Eval<T> {
39+
type Output;
40+
3741
/// Evaluate the given type.
38-
fn eval(&mut self, value: T, used: Used) -> Result<IrValue, EvalOutcome>;
42+
fn eval(&mut self, value: T, used: Used) -> Result<Self::Output, EvalOutcome>;
3943
}
4044

4145
pub(crate) trait ConstAs {
4246
/// Process constant value as a boolean.
4347
fn as_bool(self, compiler: &mut IrInterpreter<'_>, used: Used) -> Result<bool, EvalOutcome>;
4448
}
4549

50+
pub(crate) trait Matches {
51+
/// Test if the current trait matches the given value.
52+
fn matches<S>(
53+
&self,
54+
compiler: &mut IrInterpreter<'_>,
55+
value: IrValue,
56+
used: Used,
57+
spanned: S,
58+
) -> Result<bool, EvalOutcome>
59+
where
60+
S: Spanned;
61+
}
62+
4663
impl<T> ConstAs for T
4764
where
48-
for<'a> IrInterpreter<'a>: Eval<T>,
65+
for<'a> IrInterpreter<'a>: Eval<T, Output = IrValue>,
4966
T: Spanned,
5067
{
5168
fn as_bool(self, compiler: &mut IrInterpreter<'_>, used: Used) -> Result<bool, EvalOutcome> {
@@ -60,6 +77,27 @@ where
6077
}
6178
}
6279

80+
impl Matches for IrPat {
81+
fn matches<S>(
82+
&self,
83+
compiler: &mut IrInterpreter<'_>,
84+
value: IrValue,
85+
used: Used,
86+
spanned: S,
87+
) -> Result<bool, EvalOutcome>
88+
where
89+
S: Spanned,
90+
{
91+
match self {
92+
IrPat::Ignore => Ok(true),
93+
IrPat::Binding(name) => {
94+
compiler.scopes.decl(name, value, spanned)?;
95+
Ok(true)
96+
}
97+
}
98+
}
99+
}
100+
63101
pub(crate) enum EvalOutcome {
64102
/// Encountered ast that is not a constant expression.
65103
NotConst(Span),

crates/rune/src/eval/prelude.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! prelude that can should be used for eval implementations.
22
3-
pub(crate) use crate::eval::{ConstAs, Eval, EvalBreak, EvalOutcome, Used};
3+
pub(crate) use crate::eval::{ConstAs, Eval, EvalBreak, EvalOutcome, Matches, Used};
44
pub(crate) use crate::ir::*;
55
pub(crate) use crate::ir_interpreter::IrInterpreter;
66
pub(crate) use crate::ir_value::IrValue;

crates/rune/src/ir.rs

+32-2
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,41 @@ pub enum IrTemplateComponent {
181181
#[derive(Debug, Clone)]
182182
pub struct IrBranches {
183183
/// branches and their associated conditions.
184-
pub branches: Vec<(Ir, IrScope)>,
184+
pub branches: Vec<(IrCondition, IrScope)>,
185185
/// The default fallback branch.
186186
pub default_branch: Option<IrScope>,
187187
}
188188

189+
/// The condition for a branch.
190+
#[derive(Debug, Clone, Spanned)]
191+
pub enum IrCondition {
192+
/// A simple conditiona ir expression.
193+
Ir(Ir),
194+
/// A pattern match.
195+
Let(IrLet),
196+
}
197+
198+
/// A pattern match.
199+
#[derive(Debug, Clone, Spanned)]
200+
pub struct IrLet {
201+
/// The span of the let condition.
202+
#[rune(span)]
203+
pub span: Span,
204+
/// The pattern.
205+
pub pat: IrPat,
206+
/// The expression the pattern is evaluated on.
207+
pub ir: Ir,
208+
}
209+
210+
/// A pattern.
211+
#[derive(Debug, Clone)]
212+
pub enum IrPat {
213+
/// An ignore pattern `_`.
214+
Ignore,
215+
/// A named binding.
216+
Binding(Box<str>),
217+
}
218+
189219
/// A loop with an optional condition.
190220
#[derive(Debug, Clone, Spanned)]
191221
pub struct IrLoop {
@@ -195,7 +225,7 @@ pub struct IrLoop {
195225
/// The label of the loop.
196226
pub label: Option<Box<str>>,
197227
/// The condition of the loop.
198-
pub condition: Option<Box<Ir>>,
228+
pub condition: Option<Box<IrCondition>>,
199229
/// The body of the loop.
200230
pub body: IrScope,
201231
}

crates/rune/src/ir_compiler.rs

+28-4
Original file line numberDiff line numberDiff line change
@@ -430,17 +430,41 @@ impl Compile<&ast::ExprLet> for IrCompiler<'_> {
430430
}
431431

432432
impl Compile<&ast::Condition> for IrCompiler<'_> {
433-
type Output = ir::Ir;
433+
type Output = ir::IrCondition;
434434

435435
fn compile(&mut self, condition: &ast::Condition) -> Result<Self::Output, CompileError> {
436436
match condition {
437-
ast::Condition::Expr(expr) => {
438-
return self.compile(&**expr);
437+
ast::Condition::Expr(expr) => Ok(ir::IrCondition::Ir(self.compile(&**expr)?)),
438+
ast::Condition::ExprLet(expr_let) => {
439+
let pat = self.compile(&expr_let.pat)?;
440+
let ir = self.compile(&*expr_let.expr)?;
441+
442+
Ok(ir::IrCondition::Let(ir::IrLet {
443+
span: expr_let.span(),
444+
pat,
445+
ir,
446+
}))
447+
}
448+
}
449+
}
450+
}
451+
452+
impl Compile<&ast::Pat> for IrCompiler<'_> {
453+
type Output = ir::IrPat;
454+
455+
fn compile(&mut self, pat: &ast::Pat) -> Result<Self::Output, CompileError> {
456+
match pat {
457+
ast::Pat::PatIgnore(..) => return Ok(ir::IrPat::Ignore),
458+
ast::Pat::PatPath(path) => {
459+
if let Some(ident) = path.path.try_as_ident() {
460+
let name = self.resolve(ident)?;
461+
return Ok(ir::IrPat::Binding(name.into()));
462+
}
439463
}
440464
_ => (),
441465
}
442466

443-
Err(CompileError::const_error(condition, "not supported yet"))
467+
Err(CompileError::const_error(pat, "pattern not supported yet"))
444468
}
445469
}
446470

0 commit comments

Comments
 (0)