From adb1169288f0022e192035cae349b857aa8fed06 Mon Sep 17 00:00:00 2001 From: Kai Schmidt Date: Sat, 29 Jun 2024 10:52:33 -0700 Subject: [PATCH] fix preevaluation of macros that generate bindings --- src/assembly.rs | 10 ++++++---- src/compile/binding.rs | 38 ++++++++++++++++++++++++++++++++++++ src/compile/mod.rs | 44 +++++++----------------------------------- tests/macros.ua | 7 +++++++ 4 files changed, 58 insertions(+), 41 deletions(-) diff --git a/src/assembly.rs b/src/assembly.rs index f2fd4a81..8ef845ca 100644 --- a/src/assembly.rs +++ b/src/assembly.rs @@ -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] } diff --git a/src/compile/binding.rs b/src/compile/binding.rs index 686afdf0..65f45b2a 100644 --- a/src/compile/binding.rs +++ b/src/compile/binding.rs @@ -394,6 +394,44 @@ impl Compiler { } Ok(()) } + pub(super) fn module( + &mut self, + m: Sp, + prev_com: Option, + ) -> 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, diff --git a/src/compile/mod.rs b/src/compile/mod.rs index 6ffbfcf1..97eac490 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -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) { @@ -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(_))) @@ -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(); @@ -806,40 +810,6 @@ code: pathdiff::diff_paths(&target, base).unwrap_or(target) } } - fn module(&mut self, m: Sp, prev_com: Option) -> 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>, call: bool) -> UiuaResult> { let words = unsplit_words(split_words(words)) .into_iter() diff --git a/tests/macros.ua b/tests/macros.ua index 1dd68c64..ad234baa 100644 --- a/tests/macros.ua +++ b/tests/macros.ua @@ -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