* Fix#690: Apply clang-format consistently with CI
Applied clang-format-19 to all source files to enforce consistent
formatting according to the existing .clang-format configuration.
Added auto-clang-format GitHub Actions workflow (from
cpp-best-practices/cmake_template) that runs on pull requests to
automatically format and commit any style violations going forward.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix#677: Add strong typedefs via 'using Type = BaseType' syntax
Strong typedefs create distinct types backed by Dynamic_Object, so
'using Meters = int' makes Meters a type that is not interchangeable
with int or other typedefs of int. The constructor Meters(val) wraps
the base value, and function dispatch enforces the type distinction.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: add to_underlying function for strong typedefs
Registers a to_underlying() function for each strong typedef that
returns the wrapped base value from the Dynamic_Object's __value attr.
Requested by @lefticus in PR #680 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: expose strongly-typed operators for strong typedefs
Register forwarding binary operators at typedef creation time via a
custom Proxy_Function_Base subclass (Strong_Typedef_Binary_Op). Each
operator unwraps __value from both operands, dispatches on the
underlying types, and re-wraps arithmetic results in the typedef.
Comparison operators return the raw bool.
- Arithmetic: +, -, *, /, % → Meters + Meters -> Meters
- Comparison: <, >, <=, >=, ==, != → Meters < Meters -> bool
- Operators that don't exist on the base type error at call time
(e.g. StrongString * StrongString -> error)
- Users can extend typedefs with their own operations using
to_underlying() for unwrapping
Tests cover int-based arithmetic, string-based concatenation, string
multiplication error, comparison ops, type safety of results, and
user-defined operator extensions.
Requested by @lefticus in PR #680 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: conditionally register operators based on underlying type support
Only register strong typedef operators that actually exist for the
underlying type. Previously all operators were added unconditionally,
causing confusing reflection entries (e.g. * for StrongString) that
would fail at runtime. Now each operator is probed via call_match
against default-constructed base type values before registration.
Also adds bitwise/shift operators (&, |, ^, <<, >>) for types that
support them, and expands test coverage for unsupported operator
rejection.
Requested by @lefticus in PR #680 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: register all operators unconditionally and add compound assignment operators
Remove conditional operator registration (op_exists_for_base_type check)
since users could add underlying operators later, and the runtime check was
expensive. Operators that fail on the underlying type now error at call time
instead of being absent. Add compound assignment operators (*=, +=, -=, /=,
%=, <<=, >>=, &=, |=, ^=) via Strong_Typedef_Compound_Assign_Op which
computes the base operation and stores the result back in __value.
Requested by @lefticus in PR #680 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Merge upstream/develop into fix/issue-677-add-strong-typedefs
Resolve merge conflicts with ChaiScript:develop. Upstream added
nested namespace support (#675), grammar railroad diagrams (#673),
and WASM exception support (#689). Conflicts in chaiscript_common.hpp,
chaiscript_eval.hpp, and chaiscript_parser.hpp resolved by keeping
both Using and Namespace_Block AST node types.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: add strong typedef documentation to cheatsheet
Add a new "Strong Typedefs" section to the cheatsheet covering:
- Basic usage with `using Type = BaseType` syntax
- Arithmetic and comparison operator forwarding
- String-based strong typedefs
- Accessing the underlying value via to_underlying
- Extending strong typedefs with custom operations
Requested by @lefticus in PR #680 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#19: Add strongly-typed enum support to ChaiScript
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>
* Address review: simplify enum implementation
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>
* Address review: rename to_int to to_underlying, add switch tests
Requested by @lefticus in PR #679 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: enum class syntax, constructor, configurable underlying type
- 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>
* Address review: support enum struct syntax alongside enum class
Requested by @lefticus in PR #679 review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Address review: update EBNF grammar and cheatsheet with enum documentation
Add enum production rules to the EBNF grammar. Add comprehensive enum
section to the cheatsheet covering syntax, explicit values, underlying
type specification, construction, to_underlying, comparison, type-safe
dispatch, and switch usage. Document that the underlying type must be a
numeric type (string cannot be used) and list all available types.
Requested by @lefticus in PR #679 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#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>
The forward declarations of AST_Node_Trace and eval_error at the top of
chaiscript_common.hpp introduced these types as incomplete before the standard
library headers were fully processed. On clang/libc++ in C++20 mode, this
caused compilation errors because std::vector<AST_Node_Trace> was instantiated
while the type was still incomplete. Since the full definitions of both types
appear later in the same file (and nothing between the forward declarations
and the definitions references them), these forward declarations are unnecessary
and removing them prevents the incomplete type issue.
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>
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.