Skip to content

Commit a189af7

Browse files
author
Krusty/Benediction
committed
[copilot edited] fix issue #53
1 parent 1d9170c commit a189af7

2 files changed

Lines changed: 125 additions & 20 deletions

File tree

cpclib-tokens/src/symbols/table.rs

Lines changed: 92 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::collections::HashSet;
22
use std::ops::{Deref, DerefMut};
3-
use std::sync::LazyLock;
43
use std::sync::atomic::{AtomicI32, Ordering};
54

65
use ahash::AHashMap as HashMap;
@@ -11,7 +10,6 @@ use cpclib_common::smol_str::ToSmolStr;
1110
use cpclib_common::strsim;
1211
use delegate::delegate;
1312
use evalexpr::{ContextWithMutableVariables, HashMapContext, build_operator_tree};
14-
use regex::Regex;
1513

1614
use crate::symbols::{
1715
PhysicalAddress, Struct, Symbol, SymbolError, SymbolFor, Value, ValueAndSource, ValueMacro
@@ -186,6 +184,54 @@ struct ModuleSymbolTableIterator<'t> {
186184
current: std::collections::hash_map::Iter<'t, Symbol, ValueAndSource>
187185
}
188186

187+
struct BalancedBracedSegmentsIter<'a> {
188+
iter: std::str::CharIndices<'a>,
189+
start: Option<usize>,
190+
depth: usize
191+
}
192+
193+
impl<'a> BalancedBracedSegmentsIter<'a> {
194+
fn new(text: &'a str) -> Self {
195+
Self {
196+
iter: text.char_indices(),
197+
start: None,
198+
depth: 0
199+
}
200+
}
201+
}
202+
203+
impl Iterator for BalancedBracedSegmentsIter<'_> {
204+
type Item = (usize, usize);
205+
206+
fn next(&mut self) -> Option<Self::Item> {
207+
for (idx, ch) in &mut self.iter {
208+
match ch {
209+
'{' => {
210+
if self.depth == 0 {
211+
self.start = Some(idx);
212+
}
213+
self.depth += 1;
214+
},
215+
'}' => {
216+
if self.depth == 0 {
217+
continue;
218+
}
219+
220+
self.depth -= 1;
221+
if self.depth == 0 {
222+
if let Some(begin) = self.start.take() {
223+
return Some((begin, idx + 1));
224+
}
225+
}
226+
},
227+
_ => {}
228+
}
229+
}
230+
231+
None
232+
}
233+
}
234+
189235
impl<'t> ModuleSymbolTableIterator<'t> {
190236
fn new(table: &'t ModuleSymbolTable) -> Self {
191237
Self {
@@ -288,6 +334,14 @@ impl Clone for SymbolsTable {
288334
/// Local/global label handling code
289335
#[allow(dead_code)]
290336
impl SymbolsTable {
337+
/// Return top-level balanced `{...}` byte ranges found in `text` as an iterator.
338+
///
339+
/// Returned tuples are `(start, end)` where `end` is exclusive.
340+
/// Example: `A{{x} + 1}B{y}` => ranges for `{{x} + 1}` and `{y}`.
341+
fn collect_balanced_braced_segments(text: &str) -> BalancedBracedSegmentsIter<'_> {
342+
BalancedBracedSegmentsIter::new(text)
343+
}
344+
291345
pub fn enter_function(&mut self) {
292346
self.functions_stack.enter_function();
293347
}
@@ -349,47 +403,65 @@ impl SymbolsTable {
349403
// dbg!("Input", &symbol);
350404

351405
// handle the labels build with patterns
352-
// Get the replacement strings
353-
static RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\{+[^\}]+\}+").unwrap());
354-
let mut replace = HashSet::new();
355-
for cap in RE.captures_iter(&symbol) {
356-
if cap[0] != symbol {
357-
replace.insert(cap[0].to_owned());
358-
}
359-
}
406+
let input_symbol = symbol.clone();
407+
let mut output_symbol = String::with_capacity(input_symbol.len());
408+
let mut cursor = 0usize;
409+
let mut has_replacement = false;
360410

361-
// make the replacement
362-
for model in replace.iter() {
363-
let local_expr = &model[1..model.len() - 1]; // remove {}
411+
for (start, end) in Self::collect_balanced_braced_segments(&input_symbol)
412+
.filter(|(start, end)| !(*start == 0 && *end == input_symbol.len()))
413+
{
414+
has_replacement = true;
415+
output_symbol.push_str(&input_symbol[cursor..start]);
416+
let local_expr = &input_symbol[start + 1..end - 1]; // remove {}
364417

365418
let local_value = match self.any_value::<&str>(local_expr)?.map(|vl| vl.value()) {
366419
Some(Value::String(s)) => s.to_string(),
367420
Some(Value::Expr(e)) => e.to_string(),
368421
Some(Value::Counter(e)) => e.to_string(),
369422
_ => {
370-
let tree = build_operator_tree(local_expr)
423+
// Expand nested `{symbol}` placeholders before evaluating arithmetic.
424+
let local_expr_for_eval = self
425+
.extend_local_and_patterns_for_symbol::<&str>(local_expr)?
426+
.value()
427+
.to_owned();
428+
429+
let tree = build_operator_tree(&local_expr_for_eval)
371430
.expect("Expression should be valid here. There is a bug in the assembler");
372431

373432
// Fill the variable values to allow an evaluation
374433
let mut context = HashMapContext::new();
375434
for variable in tree.iter_variable_identifiers() {
376-
let variable_value = self
377-
.any_value::<&str>(variable)?
378-
.ok_or_else(|| SymbolError::WrongSymbol(variable.into()))?;
435+
let variable_value = if let Some(value) = self.any_value::<&str>(variable)? {
436+
value
437+
}
438+
else {
439+
let braced = format!("{{{variable}}}");
440+
self.any_value::<&str>(&braced)?
441+
.ok_or_else(|| SymbolError::WrongSymbol(variable.into()))?
442+
};
379443
context
380-
.set_value(variable.to_owned(), variable_value.clone().into())
444+
.set_value(variable.to_owned(), variable_value.into())
381445
.unwrap();
382446
}
383447

384448
// evaluate the expression
385449
let res = tree
386450
.eval_with_context(&context)
387-
.map_err(|_e| SymbolError::CannotModify(local_expr.into()))?;
451+
.map_err(|_e| SymbolError::CannotModify(local_expr_for_eval.into()))?;
388452

389453
res.to_string()
390454
}
391455
};
392-
symbol = symbol.replace(model, &local_value);
456+
457+
output_symbol.push_str(&local_value);
458+
cursor = end;
459+
}
460+
461+
// make the replacement
462+
if has_replacement {
463+
output_symbol.push_str(&input_symbol[cursor..]);
464+
symbol = output_symbol;
393465
}
394466

395467
// Local symbols are expensed with their global symbol

cpclib-tokens/src/symbols/values.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,33 @@ impl From<Value> for evalexpr::Value {
232232
}
233233
}
234234

235+
impl From<&Value> for evalexpr::Value {
236+
fn from(val: &Value) -> Self {
237+
match val {
238+
Value::Expr(e) => {
239+
match e {
240+
ExprResult::Float(f) => evalexpr::Value::Float((*f).into()),
241+
ExprResult::Value(v) => evalexpr::Value::Int(*v as _),
242+
ExprResult::Char(c) => evalexpr::Value::Int(*c as _),
243+
ExprResult::Bool(b) => evalexpr::Value::Boolean(*b),
244+
ExprResult::String(s) => evalexpr::Value::String(s.to_string()),
245+
ExprResult::List(_l) => unimplemented!(),
246+
ExprResult::Matrix {
247+
width: _,
248+
height: _,
249+
content: _
250+
} => unimplemented!()
251+
}
252+
},
253+
Value::String(s) => evalexpr::Value::String(s.to_string()),
254+
Value::Address(v) => evalexpr::Value::Int(v.address() as _),
255+
Value::Macro(m) => evalexpr::Value::String(m.name.to_string()),
256+
Value::Struct(s) => evalexpr::Value::String(s.name.to_string()),
257+
Value::Counter(c) => evalexpr::Value::Int(*c as _)
258+
}
259+
}
260+
}
261+
235262
#[derive(Copy, Clone)]
236263
pub enum SymbolFor {
237264
Number,
@@ -418,6 +445,12 @@ impl From<ValueAndSource> for evalexpr::Value {
418445
}
419446
}
420447

448+
impl From<&ValueAndSource> for evalexpr::Value {
449+
fn from(val: &ValueAndSource) -> Self {
450+
(&val.value).into()
451+
}
452+
}
453+
421454
impl From<expression::ExprResult> for ValueAndSource {
422455
fn from(value: expression::ExprResult) -> Self {
423456
let value: Value = value.into();

0 commit comments

Comments
 (0)