Skip to content

Commit

Permalink
fix preevaluation of macros that generate bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
kaikalii committed Jun 29, 2024
1 parent c4e5bf5 commit adb1169
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 41 deletions.
10 changes: 6 additions & 4 deletions src/assembly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,15 @@ impl Assembly {
let end = slice.end();
assert!(
slice.start <= self.instrs.len(),
"Func slice start {} out of bounds",
slice.start
"Func slice start {} out of bounds of {} instrs",
slice.start,
self.instrs.len()
);
assert!(
slice.end() <= self.instrs.len(),
"Func slice end {} out of bounds",
end
"Func slice end {} out of bounds of {} instrs",
end,
self.instrs.len()
);
&self.instrs[slice.start..end]
}
Expand Down
38 changes: 38 additions & 0 deletions src/compile/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,44 @@ impl Compiler {
}
Ok(())
}
pub(super) fn module(
&mut self,
m: Sp<ScopedModule>,
prev_com: Option<EcoString>,
) -> UiuaResult {
let m = m.value;
let scope_kind = match m.kind {
ModuleKind::Named(_) => ScopeKind::Module,
ModuleKind::Test => ScopeKind::Test,
};
let in_test = matches!(m.kind, ModuleKind::Test);
let module = self.in_scope(scope_kind, |env| env.items(m.items, in_test))?;
match m.kind {
ModuleKind::Named(name) => {
let global_index = self.next_global;
self.next_global += 1;
let local = LocalName {
index: global_index,
public: true,
};
let comment = prev_com
.or_else(|| module.comment.clone())
.map(|text| DocComment::from(text.as_str()));
self.asm.add_global_at(
local,
BindingKind::Module(module),
Some(name.span.clone()),
comment,
);
self.scope.names.insert(name.value.clone(), local);
self.code_meta
.global_references
.insert(name.clone(), local.index);
}
ModuleKind::Test => {}
}
Ok(())
}
pub(super) fn import(
&mut self,
import: crate::ast::Import,
Expand Down
44 changes: 7 additions & 37 deletions src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,9 @@ code:
});
// Compile the words
let instr_count_before = self.asm.instrs.len();
let binding_count_before = self.asm.bindings.len();
let instrs = self.compile_words(line, true)?;
let binding_count_after = self.asm.bindings.len();
let (mut instrs, pre_eval_errors) = self.pre_eval_instrs(instrs);
let mut line_eval_errored = false;
match instrs_signature(&instrs) {
Expand All @@ -567,10 +569,12 @@ code:
*height = (*height + sig.outputs).saturating_sub(sig.args);
}
// Try to evaluate at comptime
// This can be done when there are at least as many push instructions
// preceding the current line as there are arguments to the line
// This can be done when:
// - there are at least as many push instructions preceding the current line as there are arguments to the line
// - the words create no bindings
if !instrs.is_empty()
&& instr_count_before >= sig.args
&& binding_count_before == binding_count_after
&& (self.asm.instrs.iter().take(instr_count_before).rev())
.take(sig.args)
.all(|instr| matches!(instr, Instr::Push(_)))
Expand Down Expand Up @@ -642,7 +646,7 @@ code:
if len > 1 {
(self.asm.instrs).push(Instr::Comment(format!("({id}").into()));
}
let start = if len == 0 { 0 } else { self.asm.instrs.len() };
let start = self.asm.instrs.len();
let mut hasher = DefaultHasher::new();
instrs.hash(&mut hasher);
let hash = hasher.finish();
Expand Down Expand Up @@ -806,40 +810,6 @@ code:
pathdiff::diff_paths(&target, base).unwrap_or(target)
}
}
fn module(&mut self, m: Sp<ScopedModule>, prev_com: Option<EcoString>) -> UiuaResult {
let m = m.value;
let scope_kind = match m.kind {
ModuleKind::Named(_) => ScopeKind::Module,
ModuleKind::Test => ScopeKind::Test,
};
let in_test = matches!(m.kind, ModuleKind::Test);
let module = self.in_scope(scope_kind, |env| env.items(m.items, in_test))?;
match m.kind {
ModuleKind::Named(name) => {
let global_index = self.next_global;
self.next_global += 1;
let local = LocalName {
index: global_index,
public: true,
};
let comment = prev_com
.or_else(|| module.comment.clone())
.map(|text| DocComment::from(text.as_str()));
self.asm.add_global_at(
local,
BindingKind::Module(module),
Some(name.span.clone()),
comment,
);
self.scope.names.insert(name.value.clone(), local);
self.code_meta
.global_references
.insert(name.clone(), local.index);
}
ModuleKind::Test => {}
}
Ok(())
}
fn compile_words(&mut self, words: Vec<Sp<Word>>, call: bool) -> UiuaResult<EcoVec<Instr>> {
let words = unsplit_words(split_words(words))
.into_iter()
Expand Down
7 changes: 7 additions & 0 deletions tests/macros.ua
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,10 @@ E! ←^ $"_" e ◌

F! ←^ {"+" "1"}◌
⍤⟜≍: [2 3 4] ≡F!∘ [1 2 3]

Struct‼ ←^ $"---_\n_---" ⊙(
/$"_\n_"⊂□$"New ← {_}"≡⋅@⊙⟜⍚$"_ ← °□⊡_":°⊏⊜□⊸≠@ °$"[_]"
)°{⊙∘}

Struct‼Person[Name Age][] # Ensure that a word on the same line as binding generation works
◌◌Person~New "janMakoso" 15

0 comments on commit adb1169

Please sign in to comment.