- Change syntax from `enum` to `enum class` (only strongly-typed enums)
- Support optional underlying type: `enum class Flags : char { ... }`
(defaults to `int` when omitted)
- Replace `from_int` with a constructor named after the enum type,
accessed as `Color::Color(1)` — the underlying type is no longer
hardcoded to int
- Use Boxed_Number for type-generic value storage and comparison
- to_underlying now returns the actual underlying type
Note: `Color(1)` syntax is not possible because ChaiScript's global
objects shadow functions with the same name; `Color::Color(1)` is the
C++-consistent alternative.
Requested by @lefticus in PR #679 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Merge upstream/develop (including namespace support from #552, WASM
support from #678, and grammar diagrams from #628) and adapt enum
implementation for compatibility with the :: dot-access semantics.
Enum values are now stored as attributes on a container Dynamic_Object,
aligning with how namespaces store members. The from_int() factory
method replaces direct constructor syntax since a name cannot be both
a global object (for :: access) and a callable constructor.
Requested by @lefticus in PR #679 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix#552: Support nested namespaces via dotted names
Namespaces can now be nested using dotted name syntax, both from C++
(register_namespace(gen, "constants.si")) and from script
(namespace("constants.si")). Parent namespaces are auto-registered when
absent, and child namespaces are automatically nested into their parent
on import. This allows clean hierarchical organization like
constants.si.mu_B instead of flat names like constants_si.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: use :: instead of . as nested namespace separator
Switch from dotted names (e.g. "constants.si") to C++-style ::
separator (e.g. "constants::si") for nested namespace declarations,
both in the C++ API (register_namespace) and in script (namespace()).
The original implementation used . because namespace members are
accessed via dot notation at runtime (constants.si.mu_B), making the
declaration separator match the access syntax. However, :: is more
consistent with C++ namespace conventions and aligns with ChaiScript's
existing use of :: for method (def Class::method) and attribute
(attr Class::attr) declarations.
Member access in scripts remains dot-based (constants.si.mu_B) since
that is ChaiScript's member access operator.
Requested by @lefticus in PR #675 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: C++-style namespace scoping and block declarations
Add :: scope resolution operator for member access (ns::func works
like ns.func). Add block namespace declarations:
namespace x::y { def func() { ... } }
Functions and variables declared inside a namespace block are added
as members of the namespace, accessible via :: or dot notation.
Namespaces can be reopened to add more members, matching C++ behavior.
Requested by @lefticus in PR #675 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: extract shared make_proxy_function from Def_AST_Node
Namespace_Block_AST_Node was duplicating the entire proxy function
creation logic from Def_AST_Node::eval_internal. Extract a static
make_proxy_function helper so both nodes share the same code path,
eliminating fragile duplication that would drift if Def handling changes.
Requested by @lefticus in PR #675 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: reject non-declaration statements inside namespace blocks
Only def, var, auto, and global declarations are now allowed inside
namespace { } blocks. Arbitrary expressions, assignments, and function
calls are rejected with an eval_error. Added compiled tests verifying
that expressions, function calls, and assignments are rejected.
Requested by @lefticus in PR #675 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: remove -j parameter from unix builds
Ninja handles parallelism intelligently on its own; the explicit -j flag
was causing memory pressure on sanitizer builds. Windows (non-Ninja)
build retains -j.
Requested by @lefticus in PR #675 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>
When all typed catch blocks failed to match a thrown exception's type,
handle_exception() would silently discard the exception and return a
default-constructed Boxed_Value instead of propagating it. This meant
code like `try { throw(42) } catch(string e) { }` would swallow the
int exception rather than letting it propagate to an outer handler.
The fix adds an explicit re-throw when no catch block matches, and
restructures eval_internal() with a nested try/catch to ensure the
finally block still executes before the unhandled exception propagates.
Co-authored-by: leftibot <leftibot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove Enum_Access AST node type — reuse Id_AST_Node for enum value
lookups by combining "EnumName::ValueName" at parse time. Replace
std::set with std::vector for valid value tracking (enums are small).
Net removal of ~18 lines.
Requested by @lefticus in PR #679 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds the ability to define enums inside ChaiScript with syntax:
enum Color { Red, Green, Blue }
enum Priority { Low = 10, Medium = 20, High = 30 }
Enum values are strongly typed Dynamic_Objects accessed via :: syntax
(e.g. Color::Red). A validating constructor from int is registered that
rejects values outside the defined range. Functions declared with an enum
parameter type (e.g. def fun(Color val)) correctly reject plain integers,
enforcing type safety at the dispatch level.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The assign_remainder (%=) case in Boxed_Number::go was missing the
check_divide_by_zero guard, causing a hardware SIGFPE on integer
modulo by zero. Also moved a misplaced check_divide_by_zero from
assign_bitwise_and (&=) where it was erroneous. Additionally, the
catch block in Equation_AST_Node::eval_internal was masking the
arithmetic_error exception as a generic "unsupported operation" error;
arithmetic_error is now re-thrown to provide the correct error message.
Co-authored-by: leftibot <leftibot@users.noreply.github.com>
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>
* Fix#201: Add class inheritance support with Derived : Base syntax
Classes can now inherit methods and attributes from a base class using
C++-style syntax: `class Derived : Base { ... }`. Base class methods and
attributes are automatically available on derived objects. Derived classes
can override base methods by defining a method with the same name.
Inheritance relationships are tracked to support proper type matching
in the dispatch system.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: use implicit derived-to-base matching instead of copying base class functions
Instead of copying all base class methods/attributes into derived classes,
make the type matching system recognize inheritance relationships. Base class
methods now naturally match derived objects through dynamic_object_typename_match,
and dispatch ordering ensures derived overrides are preferred over base methods.
This is simpler (net -25 lines) and avoids duplicating function registrations.
Requested by @lefticus in PR #641 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add tests for passing derived objects to functions expecting Base
Tests cover: free functions calling base methods on derived objects,
polymorphic dispatch through containers, base attribute access on
derived objects, and multi-level inheritance (GrandChild : Derived : Base).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add typed parameter tests for class inheritance
Use typed function signatures (e.g., `def call_do_something(Base obj)`)
instead of untyped parameters to test that derived objects are accepted
by functions expecting a base type, with correct polymorphic dispatch.
Requested by @lefticus in PR #641 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>
Add Function_Push_Pop to Switch_AST_Node case comparison to properly
manage the lifetime of temporaries created during type conversions.
Make Binary_Operator_AST_Node::do_oper static and public so it can be
reused by Switch_AST_Node for case equality checks, ensuring consistent
lifetime management across all operator invocations.
Original-PR: #422
Co-Authored-By: dinghram <don.inghram@gmail.com>
Using GCC 13.3.0 I get warnings like the following:
```
In file included from .../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_optimizer.hpp:10,
from .../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_parser.hpp:26,
from .../ChaiScript/static_libs/chaiscript_parser.cpp:1:
.../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp: In instantiation of ‘chaiscript::Boxed_Value chaiscript::eval::Global_Decl_AST_Node<T>::eval_internal(const chaiscript::detail::Dispatch_State&) const [with T = chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail>]’:
.../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:503:19: required from here
.../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:504:28: warning: possibly dangling reference to a temporary [-Wdangling-reference]
504 | const std::string &idname = [&]() -> const std::string & {
| ^~~~~~
.../ChaiScript/static_libs/../include/chaiscript/language/chaiscript_eval.hpp:510:10: note: the temporary was destroyed at the end of the full expression ‘<lambda closure object>chaiscript::eval::Global_Decl_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail> >::eval_internal(const chaiscript::detail::Dispatch_State&) const::<lambda()>{((const chaiscript::eval::Global_Decl_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail> >*)this)}.chaiscript::eval::Global_Decl_AST_Node<chaiscript::eval::Tracer<chaiscript::eval::Noop_Tracer_Detail> >::eval_internal(const chaiscript::detail::Dispatch_State&) const::<lambda()>()’
504 | const std::string &idname = [&]() -> const std::string & {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
505 | if (this->children[0]->identifier == AST_Node_Type::Reference) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
506 | return this->children[0]->children[0]->text;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
507 | } else {
| ~~~~~~~~
508 | return this->children[0]->text;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
509 | }
| ~
510 | }();
| ~^~
```
Fix this by replacing the lambda with a simple ternary operator
expression.
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
There are two warnings when compiling with GCC 7.4.1 or clang 5.0.1.
1. warning: explicit by-copy capture of ‘this’ redundant with by-copy capture default
2. warning: typedef ... locally defined but not used [-Wunused-local-typedefs]
This change removes [2] and it compacts the lambda capture clause in [1].
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.