2024-02-29 17:51:38 -06:00
|
|
|
//! A work-in-progress tree walk interpreter for Conlang
|
|
|
|
//!
|
|
|
|
//! Currently, major parts of the interpreter are not yet implemented, and major parts will never be
|
|
|
|
//! implemented in its current form. Namely, since no [ConValue] has a stable location, it's
|
|
|
|
//! meaningless to get a pointer to one, and would be undefined behavior to dereference a pointer to
|
|
|
|
//! one in any situation.
|
|
|
|
|
2024-04-19 10:49:25 -05:00
|
|
|
use std::{borrow::Borrow, rc::Rc};
|
2024-04-13 03:33:26 -05:00
|
|
|
|
2024-02-29 17:51:38 -06:00
|
|
|
use super::*;
|
2024-02-29 19:49:50 -06:00
|
|
|
use cl_ast::*;
|
2025-01-28 06:23:37 -06:00
|
|
|
use cl_structures::intern::interned::Interned;
|
2024-02-29 17:51:38 -06:00
|
|
|
/// A work-in-progress tree walk interpreter for Conlang
|
|
|
|
pub trait Interpret {
|
|
|
|
/// Interprets this thing in the given [`Environment`].
|
|
|
|
///
|
|
|
|
/// Everything returns a value!™
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Interpret for File {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
for item in &self.items {
|
|
|
|
item.interpret(env)?;
|
|
|
|
}
|
|
|
|
Ok(ConValue::Empty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Item {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
match &self.kind {
|
|
|
|
ItemKind::Alias(item) => item.interpret(env),
|
|
|
|
ItemKind::Const(item) => item.interpret(env),
|
|
|
|
ItemKind::Static(item) => item.interpret(env),
|
|
|
|
ItemKind::Module(item) => item.interpret(env),
|
|
|
|
ItemKind::Function(item) => item.interpret(env),
|
|
|
|
ItemKind::Struct(item) => item.interpret(env),
|
|
|
|
ItemKind::Enum(item) => item.interpret(env),
|
|
|
|
ItemKind::Impl(item) => item.interpret(env),
|
2025-01-28 06:23:37 -06:00
|
|
|
ItemKind::Use(item) => {
|
|
|
|
eprintln!("TODO: namespaces and imports in the interpreter!\n{item}\n");
|
|
|
|
Ok(ConValue::Empty)
|
|
|
|
}
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Alias {
|
2024-04-19 10:49:25 -05:00
|
|
|
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
println!("TODO: {self}");
|
|
|
|
Ok(ConValue::Empty)
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Const {
|
2024-07-11 03:07:56 -05:00
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Const { name, ty: _, init } = self;
|
|
|
|
|
|
|
|
let init = init.as_ref().interpret(env)?;
|
|
|
|
env.insert(*name, Some(init));
|
2024-04-19 10:49:25 -05:00
|
|
|
Ok(ConValue::Empty)
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Static {
|
2024-07-11 03:07:56 -05:00
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Static { mutable: _, name, ty: _, init } = self;
|
|
|
|
|
|
|
|
let init = init.as_ref().interpret(env)?;
|
|
|
|
env.insert(*name, Some(init));
|
2024-04-19 10:49:25 -05:00
|
|
|
Ok(ConValue::Empty)
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Module {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
2024-07-11 02:48:35 -05:00
|
|
|
let Self { name, kind } = self;
|
2025-01-28 06:20:10 -06:00
|
|
|
env.push_frame(Interned::to_ref(name), Default::default());
|
|
|
|
let out = match kind {
|
2024-02-29 17:51:38 -06:00
|
|
|
ModuleKind::Inline(file) => file.interpret(env),
|
2025-01-28 06:20:10 -06:00
|
|
|
ModuleKind::Outline => {
|
2025-01-29 04:15:33 -06:00
|
|
|
eprintln!("Module {name} specified, but not imported.");
|
2025-01-28 06:20:10 -06:00
|
|
|
Ok(ConValue::Empty)
|
|
|
|
}
|
|
|
|
};
|
2025-01-29 04:15:33 -06:00
|
|
|
|
2025-01-28 06:20:10 -06:00
|
|
|
let frame = env
|
|
|
|
.pop_frame()
|
|
|
|
.expect("Environment frames must be balanced");
|
|
|
|
env.insert(*name, Some(ConValue::Module(frame.into())));
|
|
|
|
|
|
|
|
out
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Function {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
// register the function in the current environment
|
|
|
|
env.insert_fn(self);
|
|
|
|
Ok(ConValue::Empty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Struct {
|
2024-04-19 10:49:25 -05:00
|
|
|
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
println!("TODO: {self}");
|
|
|
|
Ok(ConValue::Empty)
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Enum {
|
2024-04-19 10:49:25 -05:00
|
|
|
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
println!("TODO: {self}");
|
|
|
|
Ok(ConValue::Empty)
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Impl {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
2024-04-19 10:49:25 -05:00
|
|
|
println!("TODO: {self}");
|
|
|
|
let Self { target: _, body } = self;
|
|
|
|
body.interpret(env)
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Stmt {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { extents: _, kind, semi } = self;
|
|
|
|
let out = match kind {
|
|
|
|
StmtKind::Empty => ConValue::Empty,
|
|
|
|
StmtKind::Item(stmt) => stmt.interpret(env)?,
|
|
|
|
StmtKind::Expr(stmt) => stmt.interpret(env)?,
|
|
|
|
};
|
|
|
|
Ok(match semi {
|
|
|
|
Semi::Terminated => ConValue::Empty,
|
|
|
|
Semi::Unterminated => out,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2025-01-29 04:15:33 -06:00
|
|
|
|
2024-02-29 17:51:38 -06:00
|
|
|
impl Interpret for Expr {
|
2024-04-13 03:33:26 -05:00
|
|
|
#[inline]
|
2024-02-29 17:51:38 -06:00
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { extents: _, kind } = self;
|
2024-04-13 03:33:26 -05:00
|
|
|
kind.interpret(env)
|
|
|
|
}
|
|
|
|
}
|
2025-01-29 04:15:33 -06:00
|
|
|
|
2024-04-13 03:33:26 -05:00
|
|
|
impl Interpret for ExprKind {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
match self {
|
2024-04-20 15:02:16 -05:00
|
|
|
ExprKind::Empty => Ok(ConValue::Empty),
|
2025-01-29 03:56:19 -06:00
|
|
|
ExprKind::Quote(q) => q.interpret(env),
|
2024-07-30 18:02:09 -05:00
|
|
|
ExprKind::Let(v) => v.interpret(env),
|
2025-01-29 04:15:33 -06:00
|
|
|
ExprKind::Match(v) => v.interpret(env),
|
2024-02-29 17:51:38 -06:00
|
|
|
ExprKind::Assign(v) => v.interpret(env),
|
2024-05-19 14:31:30 -05:00
|
|
|
ExprKind::Modify(v) => v.interpret(env),
|
2024-02-29 17:51:38 -06:00
|
|
|
ExprKind::Binary(v) => v.interpret(env),
|
|
|
|
ExprKind::Unary(v) => v.interpret(env),
|
2024-07-26 05:26:08 -05:00
|
|
|
ExprKind::Cast(v) => v.interpret(env),
|
2024-05-19 13:55:28 -05:00
|
|
|
ExprKind::Member(v) => v.interpret(env),
|
2024-02-29 17:51:38 -06:00
|
|
|
ExprKind::Index(v) => v.interpret(env),
|
2024-04-20 15:02:16 -05:00
|
|
|
ExprKind::Structor(v) => v.interpret(env),
|
2024-02-29 17:51:38 -06:00
|
|
|
ExprKind::Path(v) => v.interpret(env),
|
|
|
|
ExprKind::Literal(v) => v.interpret(env),
|
|
|
|
ExprKind::Array(v) => v.interpret(env),
|
|
|
|
ExprKind::ArrayRep(v) => v.interpret(env),
|
|
|
|
ExprKind::AddrOf(v) => v.interpret(env),
|
|
|
|
ExprKind::Block(v) => v.interpret(env),
|
|
|
|
ExprKind::Group(v) => v.interpret(env),
|
|
|
|
ExprKind::Tuple(v) => v.interpret(env),
|
|
|
|
ExprKind::While(v) => v.interpret(env),
|
|
|
|
ExprKind::If(v) => v.interpret(env),
|
|
|
|
ExprKind::For(v) => v.interpret(env),
|
2024-07-30 22:31:39 -05:00
|
|
|
ExprKind::Break(v) => v.interpret(env),
|
|
|
|
ExprKind::Return(v) => v.interpret(env),
|
2024-07-30 19:42:28 -05:00
|
|
|
ExprKind::Continue => Err(Error::Continue),
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-05-19 14:31:30 -05:00
|
|
|
|
2025-01-29 03:56:19 -06:00
|
|
|
impl Interpret for Quote {
|
|
|
|
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
// TODO: squoosh down into a ConValue?
|
|
|
|
Ok(ConValue::Quote(self.quote.clone()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-29 04:15:33 -06:00
|
|
|
impl Interpret for Let {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Let { mutable: _, name, ty: _, init } = self;
|
|
|
|
match init.as_ref().map(|i| i.interpret(env)).transpose()? {
|
|
|
|
Some(value) => {
|
|
|
|
for (path, value) in assignment::pattern_substitution(name, value)? {
|
|
|
|
match path.parts.as_slice() {
|
|
|
|
[PathPart::Ident(name)] => env.insert(*name, Some(value)),
|
|
|
|
_ => eprintln!("Bad assignment: {path} = {value}"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
for path in assignment::pattern_variables(name) {
|
|
|
|
match path.parts.as_slice() {
|
|
|
|
[PathPart::Ident(name)] => env.insert(*name, None),
|
|
|
|
_ => eprintln!("Bad assignment: {path}"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(ConValue::Empty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Interpret for Match {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { scrutinee, arms } = self;
|
|
|
|
let scrutinee = scrutinee.interpret(env)?;
|
|
|
|
'arm: for MatchArm(pat, expr) in arms {
|
|
|
|
if let Ok(substitution) = assignment::pattern_substitution(pat, scrutinee.clone()) {
|
|
|
|
let mut env = env.frame("match");
|
|
|
|
for (path, value) in substitution {
|
|
|
|
let [PathPart::Ident(name)] = path.parts.as_slice() else {
|
|
|
|
continue 'arm;
|
|
|
|
};
|
|
|
|
env.insert(*name, Some(value));
|
|
|
|
}
|
|
|
|
return expr.interpret(&mut env);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(Error::MatchNonexhaustive)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-28 06:23:37 -06:00
|
|
|
mod assignment {
|
|
|
|
/// Pattern matching engine for assignment
|
|
|
|
use super::*;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
type Namespace = HashMap<Sym, Option<ConValue>>;
|
|
|
|
|
2025-01-29 04:15:33 -06:00
|
|
|
/// Gets the path variables in the given Pattern
|
|
|
|
pub fn pattern_variables(pat: &Pattern) -> Vec<&Path> {
|
|
|
|
fn patvars<'p>(set: &mut Vec<&'p Path>, pat: &'p Pattern) {
|
|
|
|
match pat {
|
|
|
|
Pattern::Path(path) if path.is_sinkhole() => {}
|
|
|
|
Pattern::Path(path) => set.push(path),
|
|
|
|
Pattern::Literal(_) => {}
|
|
|
|
Pattern::Ref(_, pattern) => patvars(set, pattern),
|
|
|
|
Pattern::Tuple(patterns) | Pattern::Array(patterns) => {
|
|
|
|
patterns.iter().for_each(|pat| patvars(set, pat))
|
|
|
|
}
|
|
|
|
Pattern::Struct(_path, items) => {
|
|
|
|
items.iter().for_each(|(name, pat)| match pat {
|
|
|
|
Some(pat) => patvars(set, pat),
|
|
|
|
None => set.push(name),
|
|
|
|
});
|
|
|
|
}
|
2024-05-19 14:31:30 -05:00
|
|
|
}
|
|
|
|
}
|
2025-01-29 04:15:33 -06:00
|
|
|
let mut set = Vec::new();
|
|
|
|
patvars(&mut set, pat);
|
|
|
|
set
|
2025-01-28 06:23:37 -06:00
|
|
|
}
|
|
|
|
|
2025-01-29 04:15:33 -06:00
|
|
|
/// Appends a substitution to the provided table
|
|
|
|
pub fn append_sub<'pat>(
|
|
|
|
env: &mut HashMap<&'pat Path, ConValue>,
|
|
|
|
pat: &'pat Pattern,
|
|
|
|
value: ConValue,
|
|
|
|
) -> IResult<()> {
|
|
|
|
match pat {
|
|
|
|
Pattern::Path(path) if path.is_sinkhole() => Ok(()),
|
|
|
|
Pattern::Path(path) => {
|
|
|
|
env.insert(path, value);
|
|
|
|
Ok(())
|
|
|
|
}
|
2025-01-28 06:23:37 -06:00
|
|
|
|
2025-01-29 04:15:33 -06:00
|
|
|
Pattern::Literal(literal) => match (literal, value) {
|
|
|
|
(Literal::Bool(a), ConValue::Bool(b)) => *a == b,
|
|
|
|
(Literal::Char(a), ConValue::Char(b)) => *a == b,
|
|
|
|
(Literal::Int(a), ConValue::Int(b)) => *a as isize == b,
|
|
|
|
(Literal::Float(a), ConValue::Float(b)) => f64::from_bits(*a) == b,
|
|
|
|
(Literal::String(a), ConValue::String(b)) => *a == *b,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
.then_some(())
|
|
|
|
.ok_or(Error::NotAssignable),
|
2025-01-28 06:23:37 -06:00
|
|
|
|
2025-01-29 04:15:33 -06:00
|
|
|
Pattern::Ref(_, pattern) => match value {
|
|
|
|
ConValue::Ref(value) => append_sub(env, pattern, Rc::unwrap_or_clone(value)),
|
|
|
|
_ => Err(Error::NotAssignable),
|
|
|
|
},
|
|
|
|
|
|
|
|
Pattern::Tuple(patterns) => match value {
|
|
|
|
ConValue::Tuple(values) => {
|
|
|
|
if patterns.len() != values.len() {
|
|
|
|
return Err(Error::OobIndex(patterns.len(), values.len()));
|
|
|
|
};
|
|
|
|
for (pat, value) in patterns.iter().zip(Vec::from(values).into_iter()) {
|
|
|
|
append_sub(env, pat, value)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
_ => Err(Error::NotAssignable),
|
|
|
|
},
|
|
|
|
|
|
|
|
Pattern::Array(patterns) => match value {
|
|
|
|
ConValue::Array(values) => {
|
|
|
|
if patterns.len() != values.len() {
|
|
|
|
return Err(Error::OobIndex(patterns.len(), values.len()));
|
|
|
|
};
|
|
|
|
for (pat, value) in patterns.iter().zip(Vec::from(values).into_iter()) {
|
|
|
|
append_sub(env, pat, value)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
_ => Err(Error::NotAssignable),
|
|
|
|
},
|
|
|
|
|
|
|
|
Pattern::Struct(_path, patterns) => {
|
|
|
|
let ConValue::Struct(parts) = value else {
|
|
|
|
return Err(Error::TypeError);
|
|
|
|
};
|
|
|
|
let (_, mut values) = *parts;
|
|
|
|
if values.len() != patterns.len() {
|
|
|
|
return Err(Error::TypeError);
|
|
|
|
}
|
|
|
|
for (name, pat) in patterns {
|
|
|
|
let [.., PathPart::Ident(index)] = name.parts.as_slice() else {
|
|
|
|
Err(Error::TypeError)?
|
|
|
|
};
|
|
|
|
let value = values.remove(index).ok_or(Error::TypeError)?;
|
|
|
|
match pat {
|
|
|
|
Some(pat) => append_sub(env, pat, value)?,
|
|
|
|
None => {
|
|
|
|
env.insert(name, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2025-01-28 06:23:37 -06:00
|
|
|
}
|
|
|
|
|
2025-01-29 04:15:33 -06:00
|
|
|
/// Constructs a substitution from a pattern and a value
|
|
|
|
pub fn pattern_substitution(
|
|
|
|
pat: &Pattern,
|
2025-01-28 06:23:37 -06:00
|
|
|
value: ConValue,
|
2025-01-29 04:15:33 -06:00
|
|
|
) -> IResult<HashMap<&Path, ConValue>> {
|
|
|
|
let mut substitution = HashMap::new();
|
|
|
|
append_sub(&mut substitution, pat, value)?;
|
|
|
|
Ok(substitution)
|
|
|
|
}
|
2025-01-28 06:23:37 -06:00
|
|
|
|
2025-01-29 04:15:33 -06:00
|
|
|
pub(super) fn pat_assign(env: &mut Environment, pat: &Pattern, value: ConValue) -> IResult<()> {
|
|
|
|
let mut substitution = HashMap::new();
|
2025-01-31 03:34:45 -06:00
|
|
|
append_sub(&mut substitution, pat, value)
|
|
|
|
.map_err(|_| Error::PatFailed(pat.clone().into()))?;
|
2025-01-29 04:15:33 -06:00
|
|
|
for (path, value) in substitution {
|
|
|
|
assign_path(env, path, value)?;
|
2025-01-28 06:23:37 -06:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-01-29 04:15:33 -06:00
|
|
|
pub(super) fn assign(env: &mut Environment, pat: &ExprKind, value: ConValue) -> IResult<()> {
|
|
|
|
if let Ok(pat) = Pattern::try_from(pat.clone()) {
|
|
|
|
return pat_assign(env, &pat, value);
|
2025-01-28 06:23:37 -06:00
|
|
|
}
|
2025-01-29 04:15:33 -06:00
|
|
|
match pat {
|
|
|
|
ExprKind::Member(member) => *addrof_member(env, member)? = value,
|
|
|
|
ExprKind::Index(index) => *addrof_index(env, index)? = value,
|
|
|
|
_ => Err(Error::NotAssignable)?,
|
2025-01-28 06:23:37 -06:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2025-01-29 04:15:33 -06:00
|
|
|
fn assign_path(env: &mut Environment, path: &Path, value: ConValue) -> IResult<()> {
|
|
|
|
let Ok(addr) = addrof_path(env, &path.parts) else {
|
|
|
|
eprintln!("Cannot assign {value} to path {path}");
|
|
|
|
return Err(Error::NotAssignable);
|
2025-01-28 06:23:37 -06:00
|
|
|
};
|
2025-01-29 04:15:33 -06:00
|
|
|
*addr = Some(value);
|
2025-01-28 06:23:37 -06:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn addrof<'e>(
|
|
|
|
env: &'e mut Environment,
|
|
|
|
pat: &ExprKind,
|
|
|
|
) -> IResult<&'e mut ConValue> {
|
|
|
|
match pat {
|
|
|
|
ExprKind::Path(path) => addrof_path(env, &path.parts)?
|
|
|
|
.as_mut()
|
|
|
|
.ok_or(Error::NotInitialized("".into())),
|
|
|
|
ExprKind::Member(member) => addrof_member(env, member),
|
|
|
|
ExprKind::Index(index) => addrof_index(env, index),
|
|
|
|
ExprKind::Group(Group { expr }) => addrof(env, expr),
|
2025-01-29 04:15:33 -06:00
|
|
|
ExprKind::AddrOf(AddrOf { mutable: Mutability::Mut, expr }) => addrof(env, expr),
|
2025-01-28 06:23:37 -06:00
|
|
|
_ => Err(Error::TypeError),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn addrof_path<'e>(
|
|
|
|
env: &'e mut Environment,
|
|
|
|
path: &[PathPart],
|
|
|
|
) -> IResult<&'e mut Option<ConValue>> {
|
|
|
|
match path {
|
|
|
|
[PathPart::Ident(name)] => env.get_mut(*name),
|
|
|
|
[PathPart::Ident(name), rest @ ..] => match env.get_mut(*name)? {
|
|
|
|
Some(ConValue::Module(env)) => addrof_path_within_namespace(env, rest),
|
|
|
|
_ => Err(Error::NotIndexable),
|
|
|
|
},
|
|
|
|
_ => Err(Error::NotAssignable),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn addrof_member<'e>(env: &'e mut Environment, member: &Member) -> IResult<&'e mut ConValue> {
|
|
|
|
let Member { head, kind } = member;
|
|
|
|
let ExprKind::Path(path) = head.as_ref() else {
|
|
|
|
return Err(Error::TypeError);
|
|
|
|
};
|
|
|
|
let slot = addrof_path(env, &path.parts)?
|
|
|
|
.as_mut()
|
|
|
|
.ok_or(Error::NotAssignable)?;
|
|
|
|
Ok(match (slot, kind) {
|
|
|
|
(ConValue::Struct(s), MemberKind::Struct(id)) => {
|
|
|
|
s.1.get_mut(id).ok_or(Error::NotDefined(*id))?
|
|
|
|
}
|
|
|
|
(ConValue::Tuple(t), MemberKind::Tuple(Literal::Int(id))) => t
|
|
|
|
.get_mut(*id as usize)
|
|
|
|
.ok_or_else(|| Error::NotDefined(id.to_string().into()))?,
|
|
|
|
_ => Err(Error::TypeError)?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn addrof_index<'e>(env: &'e mut Environment, index: &Index) -> IResult<&'e mut ConValue> {
|
|
|
|
let Index { head, indices } = index;
|
|
|
|
let indices = indices
|
|
|
|
.iter()
|
|
|
|
.map(|index| index.interpret(env))
|
|
|
|
.collect::<IResult<Vec<_>>>()?;
|
|
|
|
let mut head = addrof(env, head)?;
|
|
|
|
for index in indices {
|
|
|
|
head = match (head, index) {
|
|
|
|
(ConValue::Array(a), ConValue::Int(i)) => {
|
|
|
|
let a_len = a.len();
|
|
|
|
a.get_mut(i as usize)
|
|
|
|
.ok_or(Error::OobIndex(i as usize, a_len))?
|
|
|
|
}
|
|
|
|
_ => Err(Error::NotIndexable)?,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(head)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn addrof_path_within_namespace<'e>(
|
|
|
|
env: &'e mut Namespace,
|
|
|
|
path: &[PathPart],
|
|
|
|
) -> IResult<&'e mut Option<ConValue>> {
|
|
|
|
match path {
|
|
|
|
[] => Err(Error::NotAssignable),
|
|
|
|
[PathPart::Ident(name)] => env.get_mut(name).ok_or(Error::NotDefined(*name)),
|
|
|
|
[PathPart::Ident(name), rest @ ..] => {
|
|
|
|
match env.get_mut(name).ok_or(Error::NotDefined(*name))? {
|
|
|
|
Some(ConValue::Module(env)) => addrof_path_within_namespace(env, rest),
|
|
|
|
_ => Err(Error::NotIndexable),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[PathPart::SelfKw, rest @ ..] => addrof_path_within_namespace(env, rest),
|
|
|
|
[PathPart::SelfTy, ..] => todo!("calc_address for `Self`"),
|
|
|
|
[PathPart::SuperKw, ..] => todo!("calc_address for `super`"),
|
2024-05-19 14:31:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-29 17:51:38 -06:00
|
|
|
impl Interpret for Assign {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
2024-05-19 14:31:30 -05:00
|
|
|
let Assign { parts } = self;
|
2024-04-13 03:33:26 -05:00
|
|
|
let (head, tail) = parts.borrow();
|
2024-05-19 14:31:30 -05:00
|
|
|
let init = tail.interpret(env)?;
|
2024-02-29 17:51:38 -06:00
|
|
|
// Resolve the head pattern
|
2025-01-28 06:23:37 -06:00
|
|
|
assignment::assign(env, head, init).map(|_| ConValue::Empty)
|
2024-05-19 14:31:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Modify {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Modify { kind: op, parts } = self;
|
|
|
|
let (head, tail) = parts.borrow();
|
2024-02-29 17:51:38 -06:00
|
|
|
// Get the initializer and the tail
|
|
|
|
let init = tail.interpret(env)?;
|
2024-05-19 14:31:30 -05:00
|
|
|
// Resolve the head pattern
|
2025-01-28 06:23:37 -06:00
|
|
|
let target = assignment::addrof(env, head)?;
|
2024-02-29 17:51:38 -06:00
|
|
|
|
|
|
|
match op {
|
2024-05-19 14:31:30 -05:00
|
|
|
ModifyKind::Add => target.add_assign(init),
|
|
|
|
ModifyKind::Sub => target.sub_assign(init),
|
|
|
|
ModifyKind::Mul => target.mul_assign(init),
|
|
|
|
ModifyKind::Div => target.div_assign(init),
|
|
|
|
ModifyKind::Rem => target.rem_assign(init),
|
|
|
|
ModifyKind::And => target.bitand_assign(init),
|
|
|
|
ModifyKind::Or => target.bitor_assign(init),
|
|
|
|
ModifyKind::Xor => target.bitxor_assign(init),
|
|
|
|
ModifyKind::Shl => target.shl_assign(init),
|
|
|
|
ModifyKind::Shr => target.shr_assign(init),
|
|
|
|
}?;
|
2024-02-29 17:51:38 -06:00
|
|
|
Ok(ConValue::Empty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Binary {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
2024-04-13 03:33:26 -05:00
|
|
|
let Binary { kind, parts } = self;
|
|
|
|
let (head, tail) = parts.borrow();
|
|
|
|
|
|
|
|
let head = head.interpret(env)?;
|
|
|
|
|
2024-02-29 17:51:38 -06:00
|
|
|
// Short-circuiting ops
|
2024-04-13 03:33:26 -05:00
|
|
|
match kind {
|
|
|
|
BinaryKind::LogAnd => {
|
|
|
|
return if head.truthy()? {
|
|
|
|
tail.interpret(env)
|
|
|
|
} else {
|
|
|
|
Ok(head)
|
|
|
|
}; // Short circuiting
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
2024-04-13 03:33:26 -05:00
|
|
|
BinaryKind::LogOr => {
|
|
|
|
return if !head.truthy()? {
|
|
|
|
tail.interpret(env)
|
|
|
|
} else {
|
|
|
|
Ok(head)
|
|
|
|
}; // Short circuiting
|
|
|
|
}
|
|
|
|
BinaryKind::LogXor => {
|
|
|
|
return Ok(ConValue::Bool(
|
|
|
|
head.truthy()? ^ tail.interpret(env)?.truthy()?,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
_ => {}
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
2024-04-13 03:33:26 -05:00
|
|
|
let tail = tail.interpret(env)?;
|
|
|
|
match kind {
|
2024-04-19 10:49:25 -05:00
|
|
|
BinaryKind::Lt => head.lt(&tail),
|
|
|
|
BinaryKind::LtEq => head.lt_eq(&tail),
|
|
|
|
BinaryKind::Equal => head.eq(&tail),
|
|
|
|
BinaryKind::NotEq => head.neq(&tail),
|
|
|
|
BinaryKind::GtEq => head.gt_eq(&tail),
|
|
|
|
BinaryKind::Gt => head.gt(&tail),
|
|
|
|
BinaryKind::RangeExc => head.range_exc(tail),
|
|
|
|
BinaryKind::RangeInc => head.range_inc(tail),
|
|
|
|
BinaryKind::BitAnd => head & tail,
|
|
|
|
BinaryKind::BitOr => head | tail,
|
|
|
|
BinaryKind::BitXor => head ^ tail,
|
|
|
|
BinaryKind::Shl => head << tail,
|
|
|
|
BinaryKind::Shr => head >> tail,
|
|
|
|
BinaryKind::Add => head + tail,
|
|
|
|
BinaryKind::Sub => head - tail,
|
|
|
|
BinaryKind::Mul => head * tail,
|
|
|
|
BinaryKind::Div => head / tail,
|
|
|
|
BinaryKind::Rem => head % tail,
|
2024-04-13 03:33:26 -05:00
|
|
|
BinaryKind::Call => match tail {
|
|
|
|
ConValue::Empty => head.call(env, &[]),
|
|
|
|
ConValue::Tuple(args) => head.call(env, &args),
|
|
|
|
_ => Err(Error::TypeError),
|
|
|
|
},
|
|
|
|
_ => Ok(head),
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
2024-04-19 10:49:25 -05:00
|
|
|
|
|
|
|
// // Temporarily disabled, to avoid function dispatch overhead while I screw around
|
|
|
|
// // Not like it helped much in the first place!
|
|
|
|
// match kind {
|
|
|
|
// BinaryKind::Mul => env.call("mul", &[head, tail]),
|
|
|
|
// BinaryKind::Div => env.call("div", &[head, tail]),
|
|
|
|
// BinaryKind::Rem => env.call("rem", &[head, tail]),
|
|
|
|
// BinaryKind::Add => env.call("add", &[head, tail]),
|
|
|
|
// BinaryKind::Sub => env.call("sub", &[head, tail]),
|
|
|
|
// BinaryKind::Shl => env.call("shl", &[head, tail]),
|
|
|
|
// BinaryKind::Shr => env.call("shr", &[head, tail]),
|
|
|
|
// BinaryKind::BitAnd => env.call("and", &[head, tail]),
|
|
|
|
// BinaryKind::BitOr => env.call("or", &[head, tail]),
|
|
|
|
// BinaryKind::BitXor => env.call("xor", &[head, tail]),
|
|
|
|
// BinaryKind::RangeExc => env.call("range_exc", &[head, tail]),
|
|
|
|
// BinaryKind::RangeInc => env.call("range_inc", &[head, tail]),
|
|
|
|
// BinaryKind::Lt => env.call("lt", &[head, tail]),
|
|
|
|
// BinaryKind::LtEq => env.call("lt_eq", &[head, tail]),
|
|
|
|
// BinaryKind::Equal => env.call("eq", &[head, tail]),
|
|
|
|
// BinaryKind::NotEq => env.call("neq", &[head, tail]),
|
|
|
|
// BinaryKind::GtEq => env.call("gt_eq", &[head, tail]),
|
|
|
|
// BinaryKind::Gt => env.call("gt", &[head, tail]),
|
|
|
|
// BinaryKind::Dot => todo!("search within a type's namespace!"),
|
|
|
|
// BinaryKind::Call => match tail {
|
|
|
|
// ConValue::Empty => head.call(env, &[]),
|
|
|
|
// ConValue::Tuple(args) => head.call(env, &args),
|
|
|
|
// _ => Err(Error::TypeError),
|
|
|
|
// },
|
|
|
|
// _ => Ok(head),
|
|
|
|
// }
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
2024-04-13 03:33:26 -05:00
|
|
|
|
|
|
|
impl Interpret for Unary {
|
2024-02-29 17:51:38 -06:00
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
2024-04-13 03:33:26 -05:00
|
|
|
let Unary { kind, tail } = self;
|
|
|
|
match kind {
|
2024-07-30 18:21:25 -05:00
|
|
|
UnaryKind::Loop => loop {
|
|
|
|
match tail.interpret(env) {
|
|
|
|
Err(Error::Break(value)) => return Ok(value),
|
|
|
|
Err(Error::Continue) => continue,
|
|
|
|
e => e?,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
UnaryKind::Deref => {
|
|
|
|
let operand = tail.interpret(env)?;
|
|
|
|
env.call("deref".into(), &[operand])
|
|
|
|
}
|
|
|
|
UnaryKind::Neg => {
|
|
|
|
let operand = tail.interpret(env)?;
|
|
|
|
env.call("neg".into(), &[operand])
|
|
|
|
}
|
|
|
|
UnaryKind::Not => {
|
|
|
|
let operand = tail.interpret(env)?;
|
|
|
|
env.call("not".into(), &[operand])
|
|
|
|
}
|
2024-04-13 03:33:26 -05:00
|
|
|
UnaryKind::At => {
|
2024-07-30 18:21:25 -05:00
|
|
|
let operand = tail.interpret(env)?;
|
2024-04-13 03:33:26 -05:00
|
|
|
println!("{operand}");
|
|
|
|
Ok(operand)
|
|
|
|
}
|
|
|
|
UnaryKind::Tilde => unimplemented!("Tilde operator"),
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-07-26 05:26:08 -05:00
|
|
|
|
|
|
|
fn cast(value: ConValue, ty: Sym) -> IResult<ConValue> {
|
|
|
|
let value = match value {
|
|
|
|
ConValue::Empty => 0,
|
|
|
|
ConValue::Int(i) => i as _,
|
|
|
|
ConValue::Bool(b) => b as _,
|
|
|
|
ConValue::Char(c) => c as _,
|
|
|
|
ConValue::Ref(v) => return cast((*v).clone(), ty),
|
2024-09-18 01:02:09 -05:00
|
|
|
// TODO: This, better
|
|
|
|
ConValue::Float(_) if ty.starts_with('f') => return Ok(value),
|
|
|
|
ConValue::Float(f) => f as _,
|
2024-07-26 05:26:08 -05:00
|
|
|
_ => Err(Error::TypeError)?,
|
|
|
|
};
|
|
|
|
Ok(match &*ty {
|
|
|
|
"u8" => ConValue::Int(value as u8 as _),
|
|
|
|
"i8" => ConValue::Int(value as i8 as _),
|
|
|
|
"u16" => ConValue::Int(value as u16 as _),
|
|
|
|
"i16" => ConValue::Int(value as i16 as _),
|
|
|
|
"u32" => ConValue::Int(value as u32 as _),
|
|
|
|
"i32" => ConValue::Int(value as i32 as _),
|
|
|
|
"u64" => ConValue::Int(value),
|
|
|
|
"i64" => ConValue::Int(value),
|
2024-09-18 01:02:09 -05:00
|
|
|
"f32" => ConValue::Float(value as f32 as _),
|
|
|
|
"f64" => ConValue::Float(value as f64 as _),
|
2024-07-26 05:26:08 -05:00
|
|
|
"char" => ConValue::Char(char::from_u32(value as _).unwrap_or('\u{fffd}')),
|
|
|
|
"bool" => ConValue::Bool(value < 0),
|
|
|
|
_ => Err(Error::NotDefined(ty))?,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Interpret for Cast {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Cast { head, ty } = self;
|
|
|
|
let value = head.interpret(env)?;
|
|
|
|
if TyKind::Empty == ty.kind {
|
|
|
|
return Ok(ConValue::Empty);
|
|
|
|
};
|
|
|
|
let TyKind::Path(Path { absolute: false, parts }) = &ty.kind else {
|
|
|
|
Err(Error::TypeError)?
|
|
|
|
};
|
|
|
|
match parts.as_slice() {
|
|
|
|
[PathPart::Ident(ty)] => cast(value, *ty),
|
|
|
|
_ => Err(Error::TypeError),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-19 13:55:28 -05:00
|
|
|
impl Interpret for Member {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Member { head, kind } = self;
|
|
|
|
let head = head.interpret(env)?;
|
|
|
|
match (head, kind) {
|
|
|
|
(ConValue::Tuple(v), MemberKind::Tuple(Literal::Int(id))) => v
|
|
|
|
.get(*id as usize)
|
|
|
|
.cloned()
|
|
|
|
.ok_or(Error::OobIndex(*id as usize, v.len())),
|
2025-01-10 06:51:08 -06:00
|
|
|
(ConValue::Struct(parts), MemberKind::Struct(name)) => {
|
|
|
|
parts.1.get(name).cloned().ok_or(Error::NotDefined(*name))
|
|
|
|
}
|
|
|
|
(ConValue::Struct(parts), MemberKind::Call(name, args)) => {
|
|
|
|
let mut values = vec![];
|
|
|
|
for arg in &args.exprs {
|
|
|
|
values.push(arg.interpret(env)?);
|
|
|
|
}
|
|
|
|
(parts.1)
|
|
|
|
.get(name)
|
|
|
|
.cloned()
|
|
|
|
.ok_or(Error::NotDefined(*name))?
|
|
|
|
.call(env, &values)
|
|
|
|
}
|
2024-05-19 13:55:28 -05:00
|
|
|
(head, MemberKind::Call(name, args)) => {
|
|
|
|
let mut values = vec![head];
|
|
|
|
for arg in &args.exprs {
|
|
|
|
values.push(arg.interpret(env)?);
|
|
|
|
}
|
2024-05-19 14:41:31 -05:00
|
|
|
env.call(*name, &values)
|
2024-05-19 13:55:28 -05:00
|
|
|
}
|
|
|
|
_ => Err(Error::TypeError)?,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-02-29 17:51:38 -06:00
|
|
|
impl Interpret for Index {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { head, indices } = self;
|
|
|
|
let mut head = head.interpret(env)?;
|
2024-04-13 03:33:26 -05:00
|
|
|
for index in indices {
|
|
|
|
head = head.index(&index.interpret(env)?)?;
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
Ok(head)
|
|
|
|
}
|
|
|
|
}
|
2024-04-20 15:02:16 -05:00
|
|
|
impl Interpret for Structor {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
2025-01-10 06:51:08 -06:00
|
|
|
let Self { to: Path { absolute: _, parts }, init } = self;
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
let name = match parts.last() {
|
|
|
|
Some(PathPart::Ident(name)) => *name,
|
|
|
|
Some(PathPart::SelfKw) => "self".into(),
|
|
|
|
Some(PathPart::SelfTy) => "Self".into(),
|
|
|
|
Some(PathPart::SuperKw) => "super".into(),
|
|
|
|
None => "".into(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut map = HashMap::new();
|
|
|
|
for Fielder { name, init } in init {
|
|
|
|
let value = match init {
|
|
|
|
Some(init) => init.interpret(env)?,
|
|
|
|
None => env.get(*name)?,
|
|
|
|
};
|
|
|
|
map.insert(*name, value);
|
|
|
|
}
|
2025-01-28 06:23:37 -06:00
|
|
|
Ok(ConValue::Struct(Box::new((name, map))))
|
2024-04-20 15:02:16 -05:00
|
|
|
}
|
|
|
|
}
|
2025-01-10 06:51:08 -06:00
|
|
|
|
2024-02-29 17:51:38 -06:00
|
|
|
impl Interpret for Path {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { absolute: _, parts } = self;
|
|
|
|
|
2025-01-28 06:23:37 -06:00
|
|
|
assignment::addrof_path(env, parts)
|
|
|
|
.cloned()
|
|
|
|
.transpose()
|
|
|
|
.ok_or_else(|| Error::NotInitialized(format!("{self}").into()))?
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Literal {
|
|
|
|
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
Ok(match self {
|
|
|
|
Literal::String(value) => ConValue::from(value.as_str()),
|
|
|
|
Literal::Char(value) => ConValue::Char(*value),
|
|
|
|
Literal::Bool(value) => ConValue::Bool(*value),
|
2024-09-19 13:20:19 -05:00
|
|
|
Literal::Float(value) => ConValue::Float(f64::from_bits(*value)),
|
2024-02-29 17:51:38 -06:00
|
|
|
Literal::Int(value) => ConValue::Int(*value as _),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Array {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { values } = self;
|
|
|
|
let mut out = vec![];
|
|
|
|
for expr in values {
|
|
|
|
out.push(expr.interpret(env)?)
|
|
|
|
}
|
2024-04-19 10:49:25 -05:00
|
|
|
Ok(ConValue::Array(out.into()))
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for ArrayRep {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { value, repeat } = self;
|
|
|
|
let repeat = match repeat.interpret(env)? {
|
|
|
|
ConValue::Int(v) => v,
|
|
|
|
_ => Err(Error::TypeError)?,
|
|
|
|
};
|
|
|
|
let value = value.interpret(env)?;
|
2024-04-19 10:49:25 -05:00
|
|
|
Ok(ConValue::Array(vec![value; repeat as usize].into()))
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for AddrOf {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
2025-01-29 03:31:24 -06:00
|
|
|
let Self { mutable: _, expr } = self;
|
2024-04-19 10:49:25 -05:00
|
|
|
match expr.as_ref() {
|
|
|
|
ExprKind::Index(_) => todo!("AddrOf array index"),
|
|
|
|
ExprKind::Path(_) => todo!("Path traversal in addrof"),
|
|
|
|
_ => Ok(ConValue::Ref(Rc::new(expr.interpret(env)?))),
|
|
|
|
}
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Block {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { stmts } = self;
|
|
|
|
let mut env = env.frame("block");
|
|
|
|
let mut out = ConValue::Empty;
|
|
|
|
for stmt in stmts {
|
|
|
|
out = stmt.interpret(&mut env)?;
|
|
|
|
}
|
|
|
|
Ok(out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Group {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { expr } = self;
|
|
|
|
expr.interpret(env)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Tuple {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { exprs } = self;
|
2024-04-19 10:49:25 -05:00
|
|
|
Ok(ConValue::Tuple(
|
|
|
|
exprs
|
|
|
|
.iter()
|
|
|
|
.try_fold(vec![], |mut out, element| {
|
|
|
|
out.push(element.interpret(env)?);
|
|
|
|
Ok(out)
|
|
|
|
})?
|
|
|
|
.into(),
|
|
|
|
))
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
2024-04-17 00:29:09 -05:00
|
|
|
impl Interpret for While {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { cond, pass, fail } = self;
|
|
|
|
loop {
|
|
|
|
if cond.interpret(env)?.truthy()? {
|
|
|
|
match pass.interpret(env) {
|
|
|
|
Err(Error::Break(value)) => return Ok(value),
|
|
|
|
Err(Error::Continue) => continue,
|
|
|
|
e => e?,
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
break fail.interpret(env);
|
|
|
|
}
|
|
|
|
}
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for If {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { cond, pass, fail } = self;
|
|
|
|
if cond.interpret(env)?.truthy()? {
|
|
|
|
pass.interpret(env)
|
|
|
|
} else {
|
|
|
|
fail.interpret(env)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for For {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
2024-05-19 14:41:31 -05:00
|
|
|
let Self { bind: name, cond, pass, fail } = self;
|
2025-01-28 06:25:04 -06:00
|
|
|
let cond = cond.interpret(env)?;
|
2024-02-29 17:51:38 -06:00
|
|
|
// TODO: A better iterator model
|
2025-01-28 06:25:04 -06:00
|
|
|
let mut bounds: Box<dyn Iterator<Item = ConValue>> = match &cond {
|
|
|
|
&ConValue::RangeExc(a, b) => Box::new((a..b).map(ConValue::Int)),
|
|
|
|
&ConValue::RangeInc(a, b) => Box::new((a..=b).map(ConValue::Int)),
|
|
|
|
ConValue::Array(a) => Box::new(a.iter().cloned()),
|
|
|
|
ConValue::String(s) => Box::new(s.chars().map(ConValue::Char)),
|
2024-02-29 17:51:38 -06:00
|
|
|
_ => Err(Error::TypeError)?,
|
|
|
|
};
|
2024-04-17 00:29:09 -05:00
|
|
|
loop {
|
2024-02-29 17:51:38 -06:00
|
|
|
let mut env = env.frame("loop variable");
|
2024-04-17 00:29:09 -05:00
|
|
|
if let Some(loop_var) = bounds.next() {
|
2025-01-28 06:25:04 -06:00
|
|
|
env.insert(*name, Some(loop_var));
|
2024-02-29 17:51:38 -06:00
|
|
|
match pass.interpret(&mut env) {
|
|
|
|
Err(Error::Break(value)) => return Ok(value),
|
|
|
|
Err(Error::Continue) => continue,
|
|
|
|
result => result?,
|
|
|
|
};
|
2024-04-17 00:29:09 -05:00
|
|
|
} else {
|
|
|
|
break fail.interpret(&mut env);
|
2024-02-29 17:51:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Else {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { body } = self;
|
|
|
|
match body {
|
|
|
|
Some(body) => body.interpret(env),
|
|
|
|
None => Ok(ConValue::Empty),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-07-30 22:31:39 -05:00
|
|
|
impl Interpret for Return {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { body } = self;
|
|
|
|
Err(Error::Return(
|
|
|
|
body.as_ref()
|
|
|
|
.map(|body| body.interpret(env))
|
|
|
|
.unwrap_or(Ok(ConValue::Empty))?,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Interpret for Break {
|
|
|
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
|
|
|
let Self { body } = self;
|
|
|
|
Err(Error::Break(
|
|
|
|
body.as_ref()
|
|
|
|
.map(|body| body.interpret(env))
|
|
|
|
.unwrap_or(Ok(ConValue::Empty))?,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|