cl-interpret: Environment/stack overhaul + Ref patterns
This commit is contained in:
@@ -8,6 +8,14 @@
|
||||
use super::*;
|
||||
use cl_ast::{ast_visitor::Visit, *};
|
||||
use std::borrow::Borrow;
|
||||
|
||||
macro trace($($t:tt)*) {{
|
||||
#[cfg(debug_assertions)]
|
||||
if std::env::var("CONLANG_TRACE").is_ok() {
|
||||
eprintln!($($t)*)
|
||||
}
|
||||
}}
|
||||
|
||||
/// A work-in-progress tree walk interpreter for Conlang
|
||||
pub trait Interpret {
|
||||
/// Interprets this thing in the given [`Environment`].
|
||||
@@ -18,6 +26,7 @@ pub trait Interpret {
|
||||
|
||||
impl Interpret for File {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
trace!("// Running {}", self.name);
|
||||
/// Sorts items
|
||||
#[derive(Debug, Default)]
|
||||
struct ItemSorter<'ast>(pub [Vec<&'ast Item>; 8]);
|
||||
@@ -45,6 +54,7 @@ impl Interpret for File {
|
||||
Ok(ConValue::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for Item {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
match &self.kind {
|
||||
@@ -60,139 +70,157 @@ impl Interpret for Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for Alias {
|
||||
fn interpret(&self, _env: &mut Environment) -> IResult<ConValue> {
|
||||
println!("TODO: {self}");
|
||||
trace!("// TODO: {self}");
|
||||
Ok(ConValue::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for Const {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Const { name, ty: _, init } = self;
|
||||
trace!("// Defining const {name}");
|
||||
|
||||
let init = init.as_ref().interpret(env)?;
|
||||
env.insert(*name, Some(init));
|
||||
env.insert(*name, init);
|
||||
Ok(ConValue::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for Static {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Static { mutable: _, name, ty: _, init } = self;
|
||||
trace!("// Defining static {name}");
|
||||
|
||||
let init = init.as_ref().interpret(env)?;
|
||||
env.insert(*name, Some(init));
|
||||
env.insert(*name, init);
|
||||
Ok(ConValue::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for Module {
|
||||
// TODO: Keep modules around somehow, rather than putting them on the stack
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Self { name, file } = self;
|
||||
env.push_frame(name.to_ref(), Default::default());
|
||||
trace!("// Defining module {name}");
|
||||
|
||||
let mut scope = env.frame(name.to_ref());
|
||||
|
||||
let out = match file {
|
||||
Some(file) => file.interpret(env),
|
||||
Some(file) => file.interpret(&mut scope),
|
||||
None => {
|
||||
eprintln!("Module {name} specified, but not imported.");
|
||||
Ok(ConValue::Empty)
|
||||
}
|
||||
};
|
||||
|
||||
let (frame, _) = env
|
||||
.pop_frame()
|
||||
let frame = scope
|
||||
.pop_values()
|
||||
.expect("Environment frames must be balanced");
|
||||
env.insert(*name, Some(ConValue::Module(frame.into())));
|
||||
env.insert(*name, ConValue::Module(frame.into()));
|
||||
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for Function {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
trace!("// Defining fn {}", self.name);
|
||||
|
||||
// register the function in the current environment
|
||||
env.insert_fn(self);
|
||||
Ok(ConValue::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for Struct {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Self { name, gens: _, kind } = self;
|
||||
trace!("// Defining struct {name}");
|
||||
|
||||
let mut frame = env.frame(name.to_ref());
|
||||
|
||||
match kind {
|
||||
StructKind::Empty => {}
|
||||
StructKind::Empty => {
|
||||
frame.insert_tup_constructor("call".into(), 0);
|
||||
frame.insert("__nmemb".into(), ConValue::Int(0));
|
||||
}
|
||||
StructKind::Tuple(args) => {
|
||||
// Constructs the AST from scratch. TODO: This, better.
|
||||
let constructor = Function {
|
||||
name: *name,
|
||||
gens: Default::default(),
|
||||
sign: TyFn {
|
||||
args: TyKind::Tuple(TyTuple {
|
||||
types: args.iter().map(|ty| ty.kind.clone()).collect(),
|
||||
})
|
||||
.into(),
|
||||
rety: Some(
|
||||
Ty {
|
||||
span: cl_structures::span::Span::dummy(),
|
||||
kind: TyKind::Path(Path::from(*name)),
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
},
|
||||
bind: Pattern::Tuple(
|
||||
args.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, _)| Pattern::Name(idx.to_string().into()))
|
||||
.collect(),
|
||||
),
|
||||
body: None,
|
||||
};
|
||||
let constructor = crate::function::Function::new_constructor(constructor);
|
||||
env.insert(*name, Some(constructor.into()));
|
||||
frame.insert_tup_constructor("call".into(), args.len());
|
||||
frame.insert("__nmemb".into(), ConValue::Int(args.len() as _));
|
||||
}
|
||||
StructKind::Struct(members) => {
|
||||
// TODO: more precise type checking of structs
|
||||
for (idx, StructMember { vis: _, name: nm, ty: _ }) in members.iter().enumerate() {
|
||||
trace!("// Defining {name}::{nm}");
|
||||
frame.insert(*nm, ConValue::Int(idx as _));
|
||||
}
|
||||
frame.insert("__nmemb".into(), ConValue::Int(members.len() as _));
|
||||
}
|
||||
StructKind::Struct(_) => eprintln!("TODO: {self}"),
|
||||
}
|
||||
|
||||
let frame = frame
|
||||
.pop_values()
|
||||
.expect("Environment frames must be balanced");
|
||||
|
||||
env.insert(*name, ConValue::Module(Box::new(frame)));
|
||||
Ok(ConValue::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for Enum {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Self { name, gens: _, variants } = self;
|
||||
env.push_frame(name.to_ref(), Default::default());
|
||||
trace!("// Defining enum {name}");
|
||||
|
||||
let mut scope = env.frame(name.to_ref());
|
||||
for (idx, Variant { name, kind, body }) in variants.iter().enumerate() {
|
||||
match (kind, body) {
|
||||
(StructKind::Empty, None) => env.insert(*name, Some(ConValue::Int(idx as _))),
|
||||
(StructKind::Empty, None) => scope.insert(*name, ConValue::Int(idx as _)),
|
||||
(StructKind::Empty, Some(idx)) => {
|
||||
let idx = idx.interpret(env)?;
|
||||
env.insert(*name, Some(idx))
|
||||
let idx = idx.interpret(&mut scope)?;
|
||||
scope.insert(*name, idx)
|
||||
}
|
||||
(StructKind::Tuple(args), None) => {
|
||||
scope.insert_tup_constructor(*name, args.len());
|
||||
}
|
||||
(StructKind::Tuple(_), None) => {}
|
||||
(StructKind::Struct(_), None) => {}
|
||||
_ => eprintln!("Well-formedness error in {self}"),
|
||||
}
|
||||
}
|
||||
let (frame, _) = env
|
||||
.pop_frame()
|
||||
let frame = scope
|
||||
.pop_values()
|
||||
.expect("Frame stack should remain balanced.");
|
||||
env.insert(*name, Some(ConValue::Module(Box::new(frame))));
|
||||
env.insert(*name, ConValue::Module(Box::new(frame)));
|
||||
Ok(ConValue::Empty)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for Impl {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Self { target: ImplKind::Type(Ty { span, kind: TyKind::Path(name) }), body } = self
|
||||
let Self {
|
||||
gens: _,
|
||||
target: ImplKind::Type(Ty { span, kind: TyKind::Path(name), .. }),
|
||||
body,
|
||||
} = self
|
||||
else {
|
||||
eprintln!("TODO: impl X for Ty");
|
||||
trace!("TODO: impl X for Ty");
|
||||
return Ok(ConValue::Empty);
|
||||
};
|
||||
env.push_frame("impl", Default::default());
|
||||
body.interpret(env)?;
|
||||
let mut frame = env.frame("impl");
|
||||
body.interpret(&mut frame)?;
|
||||
|
||||
let (frame, _) = env
|
||||
.pop_frame()
|
||||
let frame = frame
|
||||
.pop_values()
|
||||
.expect("Environment frames must be balanced");
|
||||
match assignment::addrof_path(env, name.parts.as_slice())
|
||||
.map_err(|err| err.with_span(*span))?
|
||||
{
|
||||
Some(ConValue::Module(m)) => m.extend(frame),
|
||||
Some(other) => eprintln!("TODO: impl for {other}"),
|
||||
None => {}
|
||||
ConValue::Module(m) => m.extend(frame),
|
||||
other => eprintln!("TODO: impl for {other}"),
|
||||
}
|
||||
Ok(ConValue::Empty)
|
||||
}
|
||||
@@ -226,9 +254,8 @@ impl Interpret for UseTree {
|
||||
let Ok(ConValue::Module(m)) = env.get(*name) else {
|
||||
Err(Error::TypeError())?
|
||||
};
|
||||
env.push_frame(name.to_ref(), *m);
|
||||
let out = get_bindings(tree, env, bindings);
|
||||
env.pop_frame();
|
||||
let mut scope = env.with_frame(name.to_ref(), *m);
|
||||
let out = get_bindings(tree, &mut scope, bindings);
|
||||
return out;
|
||||
}
|
||||
UseTree::Alias(name, alias) => {
|
||||
@@ -238,11 +265,10 @@ impl Interpret for UseTree {
|
||||
bindings.insert(*name, env.get(*name)?);
|
||||
}
|
||||
UseTree::Glob => {
|
||||
trace!("TODO: Improve glob imports");
|
||||
if let Some((frame, name)) = env.pop_frame() {
|
||||
for (k, v) in &frame {
|
||||
if let Some(v) = v {
|
||||
bindings.insert(*k, v.clone());
|
||||
}
|
||||
bindings.insert(*k, v.clone());
|
||||
}
|
||||
env.push_frame(name, frame);
|
||||
}
|
||||
@@ -258,7 +284,7 @@ impl Interpret for UseTree {
|
||||
get_bindings(self, env, &mut bindings)?;
|
||||
|
||||
for (name, value) in bindings {
|
||||
env.insert(name, Some(value));
|
||||
env.insert(name, value);
|
||||
}
|
||||
|
||||
Ok(ConValue::Empty)
|
||||
@@ -343,16 +369,19 @@ impl Interpret for Let {
|
||||
let Let { mutable: _, name, ty: _, init } = self;
|
||||
match init.as_ref().map(|i| i.interpret(env)).transpose()? {
|
||||
Some(value) => {
|
||||
if let Ok(sub) = pattern::substitution(name, value) {
|
||||
for (name, value) in sub {
|
||||
env.insert(*name, Some(value));
|
||||
match pattern::substitution(env, name, value) {
|
||||
Ok(sub) => {
|
||||
for (name, value) in sub {
|
||||
env.insert(name, value);
|
||||
}
|
||||
return Ok(ConValue::Bool(true));
|
||||
}
|
||||
return Ok(ConValue::Bool(true));
|
||||
Err(_e) => trace!("{_e}"),
|
||||
};
|
||||
}
|
||||
None => {
|
||||
for name in pattern::variables(name) {
|
||||
env.insert(*name, None);
|
||||
env.insert(*name, ConValue::Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,10 +394,10 @@ impl Interpret for Match {
|
||||
let Self { scrutinee, arms } = self;
|
||||
let scrutinee = scrutinee.interpret(env)?;
|
||||
for MatchArm(pat, expr) in arms {
|
||||
if let Ok(substitution) = pattern::substitution(pat, scrutinee.clone()) {
|
||||
if let Ok(substitution) = pattern::substitution(env, pat, scrutinee.clone()) {
|
||||
let mut env = env.frame("match");
|
||||
for (name, value) in substitution {
|
||||
env.insert(*name, Some(value));
|
||||
env.insert(name, value);
|
||||
}
|
||||
return expr.interpret(&mut env);
|
||||
}
|
||||
@@ -377,21 +406,21 @@ impl Interpret for Match {
|
||||
}
|
||||
}
|
||||
|
||||
mod assignment {
|
||||
pub(crate) mod assignment {
|
||||
/// Pattern matching engine for assignment
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
type Namespace = HashMap<Sym, Option<ConValue>>;
|
||||
type Namespace = HashMap<Sym, ConValue>;
|
||||
|
||||
pub(super) fn pat_assign(env: &mut Environment, pat: &Pattern, value: ConValue) -> IResult<()> {
|
||||
for (name, value) in
|
||||
pattern::substitution(pat, value).map_err(|_| Error::PatFailed(pat.clone().into()))?
|
||||
for (name, value) in pattern::substitution(env, pat, value)
|
||||
.map_err(|_| Error::PatFailed(pat.clone().into()))?
|
||||
{
|
||||
match env.get_mut(*name)? {
|
||||
&mut Some(ConValue::Ref(id)) => {
|
||||
*(env.get_id_mut(id).ok_or(Error::StackOverflow(id))?) = Some(value);
|
||||
match env.get_mut(name)? {
|
||||
&mut ConValue::Ref(id) => {
|
||||
*(env.get_id_mut(id).ok_or(Error::StackOverflow(id))?) = value;
|
||||
}
|
||||
other => *other = Some(value),
|
||||
other => *other = value,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -404,11 +433,9 @@ mod assignment {
|
||||
match &pat.kind {
|
||||
ExprKind::Member(member) => *addrof_member(env, member)? = value,
|
||||
ExprKind::Index(index) => *addrof_index(env, index)? = value,
|
||||
ExprKind::Path(path) => *addrof_path(env, &path.parts)? = Some(value),
|
||||
ExprKind::Path(path) => *addrof_path(env, &path.parts)? = value,
|
||||
ExprKind::Unary(Unary { kind: UnaryKind::Deref, tail }) => match addrof(env, tail)? {
|
||||
&mut ConValue::Ref(r) => {
|
||||
*env.get_id_mut(r).ok_or(Error::StackOverflow(r))? = Some(value)
|
||||
}
|
||||
&mut ConValue::Ref(r) => *env.get_id_mut(r).ok_or(Error::StackOverflow(r))? = value,
|
||||
_ => Err(Error::NotAssignable())?,
|
||||
},
|
||||
_ => Err(Error::NotAssignable())?,
|
||||
@@ -418,18 +445,12 @@ mod assignment {
|
||||
|
||||
pub(super) fn addrof<'e>(env: &'e mut Environment, pat: &Expr) -> IResult<&'e mut ConValue> {
|
||||
match &pat.kind {
|
||||
ExprKind::Path(path) => addrof_path(env, &path.parts)?
|
||||
.as_mut()
|
||||
.ok_or(Error::NotInitialized("".into())),
|
||||
ExprKind::Path(path) => addrof_path(env, &path.parts),
|
||||
ExprKind::Member(member) => addrof_member(env, member),
|
||||
ExprKind::Index(index) => addrof_index(env, index),
|
||||
ExprKind::Group(Group { expr }) => addrof(env, expr),
|
||||
ExprKind::Unary(Unary { kind: UnaryKind::Deref, tail }) => match *addrof(env, tail)? {
|
||||
ConValue::Ref(place) => env
|
||||
.get_id_mut(place)
|
||||
.ok_or(Error::NotIndexable())?
|
||||
.as_mut()
|
||||
.ok_or(Error::NotAssignable()),
|
||||
ConValue::Ref(place) => env.get_id_mut(place).ok_or(Error::NotIndexable()),
|
||||
_ => Err(Error::TypeError()),
|
||||
},
|
||||
_ => Err(Error::TypeError()),
|
||||
@@ -439,11 +460,11 @@ mod assignment {
|
||||
pub fn addrof_path<'e>(
|
||||
env: &'e mut Environment,
|
||||
path: &[PathPart],
|
||||
) -> IResult<&'e mut Option<ConValue>> {
|
||||
) -> IResult<&'e mut ConValue> {
|
||||
match path {
|
||||
[PathPart::Ident(name)] => env.get_mut(*name),
|
||||
[PathPart::Ident(name), rest @ ..] => match env.get_mut(*name)? {
|
||||
Some(ConValue::Module(env)) => project_path_in_namespace(env, rest),
|
||||
ConValue::Module(env) => project_path_in_namespace(env, rest),
|
||||
_ => Err(Error::NotIndexable()),
|
||||
},
|
||||
_ => Err(Error::NotAssignable()),
|
||||
@@ -468,6 +489,11 @@ mod assignment {
|
||||
.collect::<IResult<Vec<_>>>()?;
|
||||
|
||||
let mut head = addrof(env, head)?;
|
||||
// match head {
|
||||
// ConValue::Slice(id, len) | ConValue::Array(id, len) => {
|
||||
|
||||
// }
|
||||
// }
|
||||
for index in indices {
|
||||
head = project_index(head, &index)?;
|
||||
}
|
||||
@@ -499,30 +525,22 @@ mod assignment {
|
||||
|
||||
/// Performs index "projection" from a ConValue to a particular element
|
||||
pub fn project_index<'v>(
|
||||
value: &'v mut ConValue,
|
||||
index: &ConValue,
|
||||
_value: &'v mut ConValue,
|
||||
_index: &ConValue,
|
||||
) -> IResult<&'v mut ConValue> {
|
||||
match (value, 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))
|
||||
}
|
||||
(ConValue::Slice(_, _), _) => Err(Error::TypeError()),
|
||||
_ => Err(Error::NotIndexable()),
|
||||
}
|
||||
Err(Error::NotIndexable())
|
||||
}
|
||||
|
||||
pub fn project_path_in_namespace<'e>(
|
||||
env: &'e mut Namespace,
|
||||
path: &[PathPart],
|
||||
) -> IResult<&'e mut Option<ConValue>> {
|
||||
) -> IResult<&'e mut 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)) => project_path_in_namespace(env, rest),
|
||||
ConValue::Module(env) => project_path_in_namespace(env, rest),
|
||||
_ => Err(Error::NotIndexable()),
|
||||
}
|
||||
}
|
||||
@@ -725,36 +743,39 @@ impl Interpret for Member {
|
||||
if let Ok(member) = assignment::addrof_member(env, self) {
|
||||
return Ok(member.clone());
|
||||
}
|
||||
let mut values = vec![];
|
||||
|
||||
// Evaluate if this can be Self'd
|
||||
let value = match (&head.kind, kind) {
|
||||
let addr = match (&head.kind, kind) {
|
||||
(ExprKind::Path(p), MemberKind::Call(..)) => {
|
||||
p.as_sym().map(|name| Ok(ConValue::Ref(env.id_of(name)?))) // "borrow" it
|
||||
p.as_sym()
|
||||
.and_then(|name| Some(ConValue::Ref(env.id_of(name).ok()?))) // "borrow" it
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let mut value = head.interpret(env)?;
|
||||
|
||||
// Perform alternate member access
|
||||
match (value.unwrap_or_else(|| head.interpret(env))?, kind) {
|
||||
match (&value, &kind) {
|
||||
(ConValue::Struct(parts), MemberKind::Call(name, args))
|
||||
if parts.1.contains_key(name) =>
|
||||
{
|
||||
let mut values = vec![];
|
||||
let f = parts.1.get(name).cloned().expect("function exists");
|
||||
values.push(addr.unwrap_or(value));
|
||||
for arg in &args.exprs {
|
||||
values.push(arg.interpret(env)?);
|
||||
}
|
||||
(parts.1)
|
||||
.get(name)
|
||||
.cloned()
|
||||
.ok_or(Error::NotDefined(*name))?
|
||||
.call(env, &values)
|
||||
f.call(env, &values)
|
||||
}
|
||||
(head, MemberKind::Call(name, args)) => {
|
||||
let mut values = vec![head];
|
||||
(_, MemberKind::Call(name, args)) => {
|
||||
values.push(addr.unwrap_or(value));
|
||||
for arg in &args.exprs {
|
||||
values.push(arg.interpret(env)?);
|
||||
}
|
||||
env.call(*name, &values)
|
||||
}
|
||||
(mut head, kind) => assignment::project_memberkind(&mut head, kind).cloned(),
|
||||
(_, kind) => assignment::project_memberkind(&mut value, kind).cloned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -774,12 +795,13 @@ impl Interpret for Structor {
|
||||
use std::collections::HashMap;
|
||||
|
||||
// Look up struct/enum-struct definition
|
||||
// use that definition to place the struct parts
|
||||
|
||||
let name = match parts.last() {
|
||||
Some(PathPart::Ident(name)) => *name,
|
||||
Some(PathPart::SelfTy) => "Self".into(),
|
||||
Some(PathPart::SuperKw) => "super".into(),
|
||||
None => "".into(),
|
||||
Some(PathPart::Ident(name)) => name.to_ref(),
|
||||
Some(PathPart::SelfTy) => "Self",
|
||||
Some(PathPart::SuperKw) => "super",
|
||||
None => "",
|
||||
};
|
||||
|
||||
let mut map = HashMap::new();
|
||||
@@ -798,10 +820,7 @@ impl Interpret for Path {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Self { absolute: _, parts } = self;
|
||||
|
||||
assignment::addrof_path(env, parts)
|
||||
.cloned()
|
||||
.transpose()
|
||||
.ok_or_else(|| Error::NotInitialized(format!("{self}").into()))?
|
||||
assignment::addrof_path(env, parts).cloned()
|
||||
}
|
||||
}
|
||||
impl Interpret for Literal {
|
||||
@@ -829,7 +848,15 @@ impl Interpret for ArrayRep {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Self { value, repeat } = self;
|
||||
let value = value.interpret(env)?;
|
||||
Ok(ConValue::Array(vec![value; *repeat].into()))
|
||||
let ConValue::Int(repeat) = repeat.interpret(env)? else {
|
||||
Err(Error::TypeError())?
|
||||
};
|
||||
if repeat < 0 {
|
||||
// TODO: a special error just for you
|
||||
Err(Error::NotIndexable())?
|
||||
}
|
||||
|
||||
Ok(ConValue::Array(vec![value; repeat as usize].into()))
|
||||
}
|
||||
}
|
||||
impl Interpret for AddrOf {
|
||||
@@ -844,7 +871,7 @@ impl Interpret for AddrOf {
|
||||
_ => {
|
||||
let value = expr.interpret(env)?;
|
||||
let temp = env.stack_alloc(value)?;
|
||||
Ok(ConValue::Ref(env::Place::Local(temp)))
|
||||
Ok(ConValue::Ref(temp))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -928,14 +955,17 @@ impl Interpret for For {
|
||||
_ => Err(Error::NotIterable())?,
|
||||
},
|
||||
ConValue::Array(a) => Box::new(a.iter().cloned()),
|
||||
&ConValue::Slice(head, len) => Box::new((head..head + len).map(ConValue::Ref)),
|
||||
// In the production compiler this may be fully unrolled
|
||||
ConValue::Tuple(t) => Box::new(t.iter().cloned()),
|
||||
ConValue::String(s) => Box::new(s.chars().map(ConValue::Char)),
|
||||
_ => Err(Error::TypeError())?,
|
||||
};
|
||||
loop {
|
||||
let mut env = env.frame("loop variable");
|
||||
if let Some(value) = bounds.next() {
|
||||
for (name, value) in pattern::substitution(bind, value)? {
|
||||
env.insert(*name, Some(value));
|
||||
for (name, value) in pattern::substitution(&env, bind, value)? {
|
||||
env.insert(name, value);
|
||||
}
|
||||
match pass.interpret(&mut env) {
|
||||
Err(Error { kind: ErrorKind::Break(value), .. }) => break Ok(value),
|
||||
|
||||
Reference in New Issue
Block a user