feat: TODO
This commit is contained in:
@@ -39,10 +39,10 @@ ir! {
|
||||
Str,
|
||||
Var,
|
||||
Path,
|
||||
Arg,
|
||||
Arg(()),
|
||||
PrimOp(PrimOpId),
|
||||
StackRef(StackIdx),
|
||||
ExprRef(ExprId),
|
||||
StackRef(StackIdx),
|
||||
FuncRef(ExprId),
|
||||
Thunk(ExprId),
|
||||
}
|
||||
@@ -52,7 +52,7 @@ ir! {
|
||||
pub enum LookupResult {
|
||||
Stack(StackIdx),
|
||||
/// The variable was found and resolved to a specific expression.
|
||||
PrimOp(ExprId),
|
||||
Expr(ExprId),
|
||||
/// The variable could not be resolved statically, likely due to a `with` expression.
|
||||
/// The lookup must be performed dynamically at evaluation time.
|
||||
Unknown,
|
||||
@@ -69,20 +69,22 @@ pub trait ResolveContext {
|
||||
fn new_func(&mut self, body: ExprId, param: Param);
|
||||
|
||||
/// Triggers the resolution of a given expression.
|
||||
fn resolve(&mut self, expr: ExprId) -> Result<()>;
|
||||
fn resolve(&mut self, expr: ExprId) -> Result<ExprId>;
|
||||
|
||||
/// Looks up a variable by name in the current scope.
|
||||
fn lookup(&mut self, name: &str) -> LookupResult;
|
||||
fn lookup(&mut self, name: SymId) -> LookupResult;
|
||||
|
||||
fn lookup_arg(&mut self) -> StackIdx;
|
||||
fn get_sym(&self, id: SymId) -> &str;
|
||||
|
||||
fn lookup_arg(&mut self) -> ExprId;
|
||||
|
||||
/// Enters a `with` scope for the duration of a closure.
|
||||
fn with_with_env<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> (bool, T);
|
||||
fn with_with_env(&mut self, f: impl FnOnce(&mut Self) -> Result<()>) -> Result<bool>;
|
||||
|
||||
/// Enters a `let` scope with a given set of bindings for the duration of a closure.
|
||||
fn with_let_env<T>(
|
||||
&mut self,
|
||||
bindings: HashMap<String, ExprId>,
|
||||
bindings: HashMap<SymId, ExprId>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T;
|
||||
|
||||
@@ -90,7 +92,8 @@ pub trait ResolveContext {
|
||||
fn with_closure_env<T>(
|
||||
&mut self,
|
||||
func: ExprId,
|
||||
ident: Option<String>,
|
||||
arg: ExprId,
|
||||
ident: Option<SymId>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T;
|
||||
}
|
||||
@@ -123,26 +126,23 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for hir::Hir {
|
||||
Var(x) => x.resolve(ctx),
|
||||
Path(x) => x.resolve(ctx),
|
||||
Let(x) => x.resolve(ctx),
|
||||
Thunk(x) => {
|
||||
ctx.resolve(x)?;
|
||||
Ok(Lir::Thunk(x))
|
||||
}
|
||||
Arg(_) => Ok(Lir::StackRef(ctx.lookup_arg())),
|
||||
Thunk(x) => ctx.resolve(x).map(Lir::Thunk),
|
||||
Arg(_) => Ok(Lir::ExprRef(ctx.lookup_arg())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves an `AttrSet` by resolving all key and value expressions.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for AttrSet {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
for (_, &v) in self.stcs.iter() {
|
||||
ctx.resolve(v)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
for (_, v) in self.stcs.iter_mut() {
|
||||
*v = ctx.resolve(*v)?;
|
||||
}
|
||||
for &(k, _) in self.dyns.iter() {
|
||||
ctx.resolve(k)?;
|
||||
for (k, _) in self.dyns.iter_mut() {
|
||||
*k = ctx.resolve(*k)?;
|
||||
}
|
||||
for &(_, v) in self.dyns.iter() {
|
||||
ctx.resolve(v)?;
|
||||
for (_, v) in self.dyns.iter_mut() {
|
||||
*v = ctx.resolve(*v)?;
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
@@ -150,9 +150,9 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for AttrSet {
|
||||
|
||||
/// Resolves a `List` by resolving each of its items.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for List {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
for &item in self.items.iter() {
|
||||
ctx.resolve(item)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
for item in self.items.iter_mut() {
|
||||
*item = ctx.resolve(*item)?;
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
@@ -160,11 +160,11 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for List {
|
||||
|
||||
/// Resolves a `HasAttr` expression by resolving the LHS and any dynamic attributes in the path.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for HasAttr {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.lhs)?;
|
||||
for attr in self.rhs.iter() {
|
||||
if let &Attr::Dynamic(expr) = attr {
|
||||
ctx.resolve(expr)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
self.lhs = ctx.resolve(self.lhs)?;
|
||||
for attr in self.rhs.iter_mut() {
|
||||
if let &mut Attr::Dynamic(expr) = attr {
|
||||
*attr = ctx.resolve(expr).map(Attr::Dynamic)?
|
||||
}
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
@@ -173,17 +173,17 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for HasAttr {
|
||||
|
||||
/// Resolves a `BinOp` by resolving its left and right hand sides.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for BinOp {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.lhs)?;
|
||||
ctx.resolve(self.rhs)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
self.lhs = ctx.resolve(self.lhs)?;
|
||||
self.rhs = ctx.resolve(self.rhs)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves a `UnOp` by resolving its right hand side.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for UnOp {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.rhs)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
self.rhs = ctx.resolve(self.rhs)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
@@ -191,15 +191,15 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for UnOp {
|
||||
/// Resolves a `Select` by resolving the expression being selected from, any dynamic
|
||||
/// attributes in the path, and the default value if it exists.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Select {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.expr)?;
|
||||
for attr in self.attrpath.iter() {
|
||||
if let &Attr::Dynamic(expr) = attr {
|
||||
ctx.resolve(expr)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
self.expr = ctx.resolve(self.expr)?;
|
||||
for attr in self.attrpath.iter_mut() {
|
||||
if let &mut Attr::Dynamic(expr) = attr {
|
||||
*attr = ctx.resolve(expr).map(Attr::Dynamic)?
|
||||
}
|
||||
}
|
||||
if let Some(expr) = self.default {
|
||||
ctx.resolve(expr)?;
|
||||
if let Some(expr) = &mut self.default {
|
||||
*expr = ctx.resolve(*expr)?;
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
@@ -207,10 +207,10 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for Select {
|
||||
|
||||
/// Resolves an `If` expression by resolving the condition, consequence, and alternative.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for If {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.cond)?;
|
||||
ctx.resolve(self.consq)?;
|
||||
ctx.resolve(self.alter)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
self.cond = ctx.resolve(self.cond)?;
|
||||
self.consq = ctx.resolve(self.consq)?;
|
||||
self.alter = ctx.resolve(self.alter)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
@@ -218,9 +218,10 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for If {
|
||||
/// Resolves a `Func` by resolving its body within a new parameter scope.
|
||||
/// It then registers the function with the context.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Func {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.with_closure_env(self.body, self.param.ident.clone(), |ctx| {
|
||||
ctx.resolve(self.body)
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.with_closure_env(self.body, self.arg, self.param.ident, |ctx| {
|
||||
self.body = ctx.resolve(self.body)?;
|
||||
Ok(())
|
||||
})?;
|
||||
ctx.new_func(self.body, self.param);
|
||||
Ok(Lir::FuncRef(self.body))
|
||||
@@ -228,9 +229,9 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for Func {
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Call {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.func)?;
|
||||
ctx.resolve(self.arg)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
self.func = ctx.resolve(self.func)?;
|
||||
self.func = ctx.resolve(self.arg)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
@@ -238,10 +239,12 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for Call {
|
||||
/// Resolves a `With` expression by resolving the namespace and the body.
|
||||
/// The body is resolved within a special "with" scope.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for With {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.namespace)?;
|
||||
let (env_used, res) = ctx.with_with_env(|ctx| ctx.resolve(self.expr));
|
||||
res?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
self.namespace = ctx.resolve(self.namespace)?;
|
||||
let env_used = ctx.with_with_env(|ctx| {
|
||||
self.expr = ctx.resolve(self.expr)?;
|
||||
Ok(())
|
||||
})?;
|
||||
// Optimization: if the `with` environment was not actually used by any variable
|
||||
// lookup in the body, we can elide the `With` node entirely.
|
||||
if env_used {
|
||||
@@ -254,18 +257,18 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for With {
|
||||
|
||||
/// Resolves an `Assert` by resolving the assertion condition and the body.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Assert {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.assertion)?;
|
||||
ctx.resolve(self.expr)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
self.assertion = ctx.resolve(self.assertion)?;
|
||||
self.expr = ctx.resolve(self.expr)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves a `ConcatStrings` by resolving each part.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for ConcatStrings {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
for &part in self.parts.iter() {
|
||||
ctx.resolve(part)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
for part in self.parts.iter_mut() {
|
||||
*part = ctx.resolve(*part)?;
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
@@ -275,13 +278,13 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for ConcatStrings {
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Var {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
use LookupResult::*;
|
||||
match ctx.lookup(&self.sym) {
|
||||
match ctx.lookup(self.sym) {
|
||||
Expr(id) => Ok(Lir::ExprRef(id)),
|
||||
Stack(idx) => Ok(Lir::StackRef(idx)),
|
||||
PrimOp(id) => Ok(Lir::ExprRef(id)),
|
||||
Unknown => Ok(self.to_lir()),
|
||||
NotFound => Err(Error::resolution_error(format!(
|
||||
"undefined variable '{}'",
|
||||
format_symbol(&self.sym)
|
||||
format_symbol(ctx.get_sym(self.sym))
|
||||
))),
|
||||
}
|
||||
}
|
||||
@@ -289,8 +292,8 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for Var {
|
||||
|
||||
/// Resolves a `Path` by resolving the underlying expression that defines the path's content.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Path {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.expr)?;
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
self.expr = ctx.resolve(self.expr)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
@@ -298,12 +301,13 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for Path {
|
||||
/// Resolves a `Let` expression by creating a new scope for the bindings, resolving
|
||||
/// the bindings and the body, and then returning a reference to the body.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for hir::Let {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
fn resolve(mut self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.with_let_env(self.bindings.clone(), |ctx| {
|
||||
for &id in self.bindings.values() {
|
||||
ctx.resolve(id)?;
|
||||
for id in self.bindings.values_mut() {
|
||||
*id = ctx.resolve(*id)?;
|
||||
}
|
||||
ctx.resolve(self.body)
|
||||
self.body = ctx.resolve(self.body)?;
|
||||
Ok(())
|
||||
})?;
|
||||
// The `let` expression itself evaluates to its body.
|
||||
Ok(Lir::ExprRef(self.body))
|
||||
|
||||
Reference in New Issue
Block a user