mirror of
https://github.com/ChaiScript/ChaiScript.git
synced 2026-04-30 19:09:26 +08:00
* 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>
190 lines
6.2 KiB
EBNF
190 lines
6.2 KiB
EBNF
/*
|
|
* ChaiScript Grammar — EBNF for Railroad Diagram Generation
|
|
*
|
|
* View as navigable railroad diagrams at:
|
|
* https://www.bottlecaps.de/rr/ui (IPv6)
|
|
* https://rr.red-dove.com/ui (IPv4)
|
|
*
|
|
* Copy and paste this file into the 'Edit Grammar' tab, then
|
|
* click 'View Diagram'.
|
|
*
|
|
* This grammar uses the notation accepted by
|
|
* https://github.com/GuntherRademacher/rr :
|
|
* - "::=" as rule separator
|
|
* - no semicolon at end of rule
|
|
* - "?" "+" "*" for repetition
|
|
* - C comments
|
|
*/
|
|
|
|
/* ---- Top-level ---- */
|
|
|
|
statements ::= ( def | try | if | while | class | enum
|
|
| for | switch | return | break | continue
|
|
| equation | block | eol )+
|
|
|
|
/* ---- Functions ---- */
|
|
|
|
def ::= "def" id ( "::" id )? "(" decl_arg_list ")" eol*
|
|
( ":" guard )? eol* block
|
|
|
|
lambda ::= "fun" ( "[" id_arg_list "]" )? "(" decl_arg_list ")" eol* block
|
|
|
|
guard ::= operator
|
|
|
|
/* ---- Exception handling ---- */
|
|
|
|
try ::= "try" eol* block catch* finally?
|
|
catch ::= "catch" ( "(" arg ")" )? eol* block
|
|
finally ::= "finally" eol* block
|
|
|
|
/* ---- Control flow ---- */
|
|
|
|
if ::= "if" "(" equation ( eol equation )? ")" eol* block
|
|
( "else" ( if | eol* block ) )*
|
|
|
|
while ::= "while" "(" operator ")" eol* block
|
|
|
|
for ::= "for" "(" ( for_guards | equation ":" equation ) ")" eol* block
|
|
for_guards ::= equation eol equation eol equation
|
|
|
|
switch ::= "switch" "(" operator ")" eol* "{" ( case | default )+ "}"
|
|
case ::= "case" "(" operator ")" eol* block
|
|
default ::= "default" eol* block
|
|
|
|
/* ---- Classes ---- */
|
|
|
|
class ::= "class" id ( ":" id )? eol* class_block
|
|
class_block ::= "{" class_statements* "}"
|
|
class_statements ::= def | var_decl | eol
|
|
|
|
/* ---- Enums ---- */
|
|
|
|
enum ::= "enum" ( "class" | "struct" ) id ( ":" underlying_type )?
|
|
"{" enum_entries? "}"
|
|
|
|
enum_entries ::= enum_entry ( "," enum_entry )*
|
|
|
|
enum_entry ::= id ( "=" integer )?
|
|
|
|
underlying_type ::= id
|
|
|
|
|
|
/* ---- Blocks & flow keywords ---- */
|
|
|
|
block ::= "{" statements* "}"
|
|
return ::= "return" operator?
|
|
break ::= "break"
|
|
continue ::= "continue"
|
|
|
|
/* ---- Line termination ---- */
|
|
|
|
eol ::= "\n" | "\r\n" | ";"
|
|
|
|
/* ---- Equations & operators ---- */
|
|
|
|
equation ::= operator ( ( "=" | ":=" | "+=" | "-=" | "*=" | "/="
|
|
| "%=" | "<<=" | ">>=" | "&=" | "^=" | "|=" )
|
|
equation )?
|
|
|
|
operator ::= prefix
|
|
| value
|
|
| operator binary_operator operator
|
|
| operator "?" operator ":" operator
|
|
|
|
prefix ::= ( "++" | "--" | "-" | "+" | "!" | "~" ) operator
|
|
|
|
binary_operator ::= "||" | "&&"
|
|
| "|" | "^" | "&"
|
|
| "==" | "!="
|
|
| "<" | "<=" | ">" | ">="
|
|
| "<<" | ">>"
|
|
| "+" | "-"
|
|
| "*" | "/" | "%"
|
|
|
|
/* ---- Values & access ---- */
|
|
|
|
value ::= var_decl | dot_fun_array | prefix
|
|
|
|
dot_fun_array ::= ( lambda | num | quoted_string
|
|
| single_quoted_string | raw_string
|
|
| paren_expression | inline_container
|
|
| id )
|
|
( fun_call | array_call | dot_access )*
|
|
|
|
fun_call ::= "(" arg_list ")"
|
|
array_call ::= "[" operator "]"
|
|
dot_access ::= "." id
|
|
|
|
/* ---- Variable declarations ---- */
|
|
|
|
var_decl ::= ( "auto" | "var" | "const" ) ( reference | id )
|
|
| "global" ( reference | id )
|
|
| "attr" id ( "::" id )?
|
|
|
|
reference ::= "&" id
|
|
|
|
/* ---- Parenthesised & inline containers ---- */
|
|
|
|
paren_expression ::= "(" operator ")"
|
|
|
|
inline_container ::= "[" container_arg_list "]"
|
|
container_arg_list ::= value_range
|
|
| map_pair ( "," map_pair )*
|
|
| operator ( "," operator )*
|
|
|
|
value_range ::= operator ".." operator
|
|
map_pair ::= operator ":" operator
|
|
|
|
/* ---- String literals ---- */
|
|
|
|
quoted_string ::= '"' ( char | escape | interpolation )* '"'
|
|
single_quoted_string ::= "'" ( char | escape ) "'"
|
|
raw_string ::= 'R"' delimiter? "(" char* ")" delimiter? '"'
|
|
delimiter ::= [a-zA-Z0-9_]+
|
|
interpolation ::= "${" equation "}"
|
|
|
|
/* ---- Escape sequences ---- */
|
|
|
|
escape ::= "\" ( "'" | '"' | "?" | "\" | "a" | "b"
|
|
| "f" | "n" | "r" | "t" | "v" | "$"
|
|
| "0"
|
|
| "x" hex_digit+
|
|
| "u" hex_digit hex_digit hex_digit hex_digit
|
|
| "U" hex_digit hex_digit hex_digit hex_digit
|
|
hex_digit hex_digit hex_digit hex_digit
|
|
| octal_digit+ )
|
|
|
|
/* ---- Argument lists ---- */
|
|
|
|
id_arg_list ::= id ( "," id )*
|
|
decl_arg_list ::= ( arg ( "," arg )* )?
|
|
arg_list ::= ( equation ( "," equation )* )?
|
|
arg ::= id id?
|
|
|
|
/* ---- Identifiers ---- */
|
|
|
|
id ::= ( [a-zA-Z_] [a-zA-Z0-9_]* )
|
|
| ( "`" [^`]+ "`" )
|
|
| "true" | "false"
|
|
| "Infinity" | "NaN"
|
|
| "_"
|
|
| "__LINE__" | "__FILE__" | "__FUNC__" | "__CLASS__"
|
|
|
|
/* ---- Numeric literals ---- */
|
|
|
|
num ::= hex | binary | float | integer
|
|
|
|
hex ::= "0" ( "x" | "X" ) [0-9a-fA-F]+ int_suffix*
|
|
binary ::= "0" ( "b" | "B" ) [01]+ int_suffix*
|
|
float ::= [0-9]+ "." [0-9]+ ( ( "e" | "E" ) ( "+" | "-" )? [0-9]+ )? float_suffix?
|
|
integer ::= [0-9]+ int_suffix*
|
|
|
|
int_suffix ::= "l" | "L" | "ll" | "LL" | "u" | "U"
|
|
float_suffix ::= "l" | "L" | "f" | "F"
|
|
|
|
/* ---- Character classes ---- */
|
|
|
|
octal_digit ::= [0-7]
|
|
hex_digit ::= [0-9a-fA-F]
|
|
char ::= [^"\]
|