Two bugs combined to cause the crash:
1. The optimized for loop (chaiscript_optimizer.hpp) stored the loop
counter as a stack-local `int` and exposed it to ChaiScript via
`var(&i)`, creating a reference-type Boxed_Value pointing to the
stack frame.
2. The `:=` operator's `Data::operator=` performed a shallow clone of
the Any (copying the reference_wrapper, not the value), so
`ret := i` made `ret` alias the stack-local `int`. When the
optimized loop's frame unwound, `ret` held a dangling pointer.
Fix 1: The optimizer now heap-allocates the loop counter via
`Boxed_Value(start_int)` and obtains a reference to the
heap-allocated int for the native C++ loop. The Boxed_Value's
shared_ptr ensures the storage outlives any copies.
Fix 2: The `:=` operator now deep-copies arithmetic values via
`Boxed_Number::clone` instead of the shallow `assign()`, ensuring
value semantics. This also fixes a pre-existing aliasing bug where
`a := b; ++b` would incorrectly mutate `a`.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix#17: Add const local variable support to ChaiScript
Adds `const var`, `const auto`, and `const` as variable declaration
syntax that creates immutable local variables. A const_override flag
on Boxed_Value enables script-level constness without changing the
C++ type system integration. The parser, optimizer, and evaluator
are extended with Const_Var_Decl and Const_Assign_Decl AST nodes
that mirror their non-const counterparts but mark the value as const
after initialization.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: remove const_override, set const flag directly on Type_Info
Replace the m_const_override bool on Boxed_Value::Data with a
Type_Info::make_const() method that sets the const bit in m_flags
directly. This ensures constness is visible everywhere consistently,
including places that check get_type_info().is_const() directly.
Requested by @lefticus in PR #643 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: leftibot <leftibot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
I initially tried to use the existing .clang-format file,
but it does not match the code style (at least with clang-format 11)
and the formatting is not consistent across files.
Therefore, I decided to rewrite the .clang-format with some personal
preferences.
Used command
find . -iname "*.hpp" -o -iname "*.cpp" | xargs clang-format -i -style=file
This modifies no logic, it simply adds the keyword `noexcept`
I believe this is 100% correct. It calls methods that are not
guaranteed to be `noexcept`, such as `operator[]` but have
no logically way of throwing.
This will allow the user to add hooks in for debugging / execution
tracing / throttling / etc for each node execution
The cost is *almost* 0 if no tracing is enabled.