Theoretical language contract
Code & Symbols grammar
One grammar, mode-conditional terminals. Terminal alternatives are not permission to mix source modes. This specifies the draft, not the current historical parser.
(* Smallsome 3.0 shared grammar, draft revision 2, October 10, 2026.
Authoritative semantics and complete Cymple 2.0 foundation: CYMPLE3.md.
One grammar/AST/backend, two selected lexical modes; no mixed spellings.
Terminal alternatives below are MODE-CONDITIONAL, not source aliases:
first spelling is Code, second is Symbols. Shared literal terminals are
valid in both. Strings/comments are scanned separately, never substituted.
Context distinguishes Symbols function/spawn, for/while, bool/success.
Unicode presentation selectors are accepted only as specified in CYMPLE3.md.
EBNF describes the full draft, NOT the implemented Ozon parser subset.
*)
program = { NEWLINE | top_level } ;
top_level = function_declaration | struct_declaration | extern_block
| module_import | entry_point | statement ;
suite = NEWLINE , INDENT , statement_block , DEDENT ;
statement_block = statement , { NEWLINE | statement } ;
statement = simple_statement , NEWLINE
| if_statement | while_loop | for_loop | match_statement
| borrow_statement | quantum_operation | guru_block
| event_clause | block_comment ;
simple_statement = variable_declaration | constant_declaration | assignment
| return_statement | print_statement | task_spawn
| channel_send | throw_statement | rethrow_statement
| stop_statement | timer_statement | colour_statement
| progress_statement | expression_statement | line_comment ;
type_spec = scalar_type | collection_type | handle_type
| STRUCT , identifier ;
scalar_type = NUM | WORD | TEXT | BOOL ;
collection_type = BYTES | LIST , [ "of" , type_spec ]
| MAP , [ "of" , type_spec ] ;
handle_type = BLOCK | FILE | NET
| CHANNEL , [ "of" , type_spec ] , [ ":" , direction ] ;
direction = "send" | "receive" ;
return_type = type_spec | "void"
| "(" , type_spec , "," , type_spec , { "," , type_spec } , ")" ;
variable_declaration = binding , { "," , binding } ,
[ ASSIGN , expression_list ] ;
binding = type_spec , identifier , [ "[" , integer_literal , "]" ] ;
constant_declaration = CONST , [ type_spec ] , identifier , ASSIGN , expression ;
assignment = lvalue , { "," , lvalue } , ASSIGN , expression_list ;
lvalue = identifier , { "[" , expression , "]" | "." , member_name } ;
struct_declaration = STRUCT , identifier , NEWLINE , INDENT ,
field_declaration , { field_declaration } , DEDENT ;
field_declaration = binding , NEWLINE ;
function_declaration = FN , identifier , "(" , [ parameter_list ] , ")" ,
[ "->" , return_type ] , suite ;
parameter_list = parameter , { "," , parameter } ;
parameter = identifier , ":" , type_spec ;
entry_point = "on" , ( "start" | "frame" ) , suite ;
return_statement = RETURN , [ expression_list ] ;
print_statement = PRINT , expression ;
expression_statement = expression ;
if_statement = IF , expression , suite , [ ELSE , suite ] ;
while_loop = WHILE , expression , suite ;
for_loop = FOR , identifier , "in" , ( range_expr | expression ) ,
[ STEP , expression ] , suite ;
range_expr = expression , ".." , expression ;
match_statement = MATCH , expression , NEWLINE , INDENT ,
match_arm , { match_arm } , DEDENT ;
match_arm = CASE , pattern , [ IF , expression ] , suite ;
pattern = "_" | literal | signed_number_pattern | range_expr | identifier | struct_pattern ;
signed_number_pattern = "-" , number_literal ;
struct_pattern = identifier , "(" , [ field_patterns ] , ")" ;
field_patterns = field_pattern , { "," , field_pattern } ;
field_pattern = member_name , ":" , pattern ;
borrow_statement = BORROW , expression , AS , [ "mut" ] , identifier , suite ;
task_spawn = SPAWN , [ "detach" ] , function_call ;
channel_create = NEWCHANNEL , type_spec , [ ":" , integer_literal ] ;
channel_send = SEND , expression , "," , expression ;
channel_receive = RECEIVE , postfix ;
quantum_operation = ( RACE | COLLECT ) , binding , ASSIGN , task_array ,
NEWLINE , INDENT , quantum_clause ,
{ quantum_clause } , DEDENT ;
task_array = "[" , function_call , { "," , function_call } , "]" ;
quantum_clause = TIMEOUT , duration , suite
| PROGRESS_EVENT , pattern , [ "every" , integer_literal ] , suite
| SUCCESS_EVENT , pattern , suite
| ERROR_EVENT , pattern , suite
| STOPPED_EVENT , pattern , suite ;
event_clause = ( SUCCESS_EVENT | ERROR_EVENT | STOPPED_EVENT ) , pattern , suite
| PROGRESS_EVENT , pattern , [ "every" , integer_literal ] , suite ;
progress_statement = "progress" , expression ;
stop_statement = STOP ;
timer_statement = ( AFTER | EVERY_TIMER ) , duration , "," , identifier ;
duration = number_literal , [ time_unit ] | "(" , expression , ")" ;
time_unit = "us" | "ms" | "s" | "m" | "h" ;
guru_block = GURU , identifier , suite ;
throw_statement = THROW , identifier , "(" , expression , ")" ,
[ ERROR_CODE , integer_literal ] ;
rethrow_statement = RETHROW , identifier ;
module_import = ( IMPORT | PLUGIN ) , string_literal , NEWLINE ;
extern_block = EXTERN , string_literal , NEWLINE , INDENT ,
extern_declaration , { extern_declaration } , DEDENT ;
extern_declaration = FN , identifier , "(" , [ parameter_list ] , ")" ,
[ "->" , return_type ] , NEWLINE ;
colour_statement = COLOUR , identifier ;
expression_list = expression , { "," , expression } ;
expression = logical_or ;
logical_or = logical_and , { "||" , logical_and } ;
logical_and = bit_or , { "&&" , bit_or } ;
bit_or = bit_xor , { "|" , bit_xor } ;
bit_xor = bit_and , { "^" , bit_and } ;
bit_and = equality , { "&" , equality } ;
equality = comparison , [ ( "==" | NOT_EQUAL ) , comparison ] ;
comparison = shift , [ ( "<" | ">" | "<=" | ">=" ) , shift ] ;
shift = additive , { ( "<<" | ">>" ) , additive } ;
additive = multiplicative , { ( "+" | "-" ) , multiplicative } ;
multiplicative = unary , { ( "*" | "/" | "%" ) , unary } ;
unary = ( "!" | "-" ) , unary | postfix ;
postfix = primary , { "[" , expression , "]" | "." , member_name
| "(" , [ argument_list ] , ")" } ;
primary = literal | identifier | channel_create | channel_receive | INPUT
| array_literal | map_literal | "(" , expression , ")" ;
function_call = call_target , "(" , [ argument_list ] , ")" ;
call_target = identifier , { "." , member_name } ;
argument_list = argument , { "," , argument } ;
argument = [ member_name , ":" ] , expression ;
array_literal = "[" , [ expression_list ] , "]" ;
map_literal = "{" , [ map_entry , { "," , map_entry } ] , "}" ;
map_entry = string_literal , ":" , expression ;
literal = number_literal | string_literal | TRUE | FALSE | "null" ;
number_literal = decimal | hexadecimal ;
integer_literal = digit , { digit } | hexadecimal ;
decimal = digit , { digit } , [ "." , digit , { digit } ] ,
[ ( "e" | "E" ) , [ "+" | "-" ] , digit , { digit } ] ;
hexadecimal = "0x" , hex_digit , { hex_digit } ;
string_literal = '"' , { string_character | escape_sequence
| interpolation | "{{" | "}}" } , '"' ;
interpolation = "{" , expression , "}" ;
escape_sequence = "\" , ( '"' | "\" | "n" | "t"
| "u{" , hex_digit , { hex_digit } , "}" ) ;
(* The backslash terminal above is one literal backslash, not an EBNF escape. *)
string_character = ? Unicode scalar except quote, backslash, braces or newline ? ;
identifier = letter , { letter | digit | "_" } ;
member_name = identifier | ? ASCII word reserved as a type in the selected mode ? ;
letter = "a".."z" | "A".."Z" ;
digit = "0".."9" ;
hex_digit = digit | "a".."f" | "A".."F" ;
line_comment = COMMENT , comment_text ;
block_comment = COMMENT , NEWLINE , comment_block_text ;
comment_text = ? scalars through, but not including, newline ? ;
comment_block_text = ? uninterpreted deeper-indented lines, no executable layout tokens ? ;
INDENT = ? increase by one configured indentation level ? ;
DEDENT = ? return to a preceding indentation level ? ;
NEWLINE = ? LF or CRLF outside bracket continuation; virtual newline at EOF ? ;
(* Mode-conditional terminals; not an invitation to mix alternatives. *)
ASSIGN = "=" | "←" ;
CONST = "const" | "📘" ;
RETURN = "return" | "↩" ;
IF = "if" | "❓" ;
ELSE = "else" | "⤵️" ;
FOR = "for" | "🔁" ;
WHILE = "while" | "🔁" ;
STEP = "step" | "⏩" ;
MATCH = "match" | "🔀" ;
CASE = "case" | "➜" ;
COMMENT = "#" | "📝" ;
PRINT = "print" | "💬" ;
INPUT = "input" | "🔽" ;
NUM = "num" | "🔢" ;
WORD = "word" ; (* shared, explicit machine arithmetic, never a num alias *)
TEXT = "text" | "🔤" ;
BOOL = "bool" | "✅" ;
TRUE = "true" | "✅" ;
FALSE = "false" | "✗" ;
LIST = "list" | "📋" ;
MAP = "map" | "🗺️" ;
BYTES = "bytes" | "🔣" ;
STRUCT = "struct" | "🧱" ;
BLOCK = "block" | "💾" ;
CHANNEL = "channel" | "📡" ;
FILE = "file" | "📄" ;
NET = "net" | "🌐" ;
FN = "fn" | "🧵" ;
SPAWN = "spawn" | "🧵" ;
NEWCHANNEL = "newchannel" | "🛰️" ;
SEND = "send" | "🚀" ;
RECEIVE = "receive" | "🎯" ;
RACE = "race" | "🌀⚡" ;
COLLECT = "collect" | "🌀📦" ;
SUCCESS_EVENT = "on success" | "✅" ;
ERROR_EVENT = "on error" | "❌" ;
PROGRESS_EVENT = "on progress" | "⏩" ;
STOPPED_EVENT = "on stopped" | "⏹️" ;
TIMEOUT = "on timeout" | "⏱️" ;
AFTER = "after" | "⏱️▶" ;
EVERY_TIMER = "every" | "⏱️🔁" ;
STOP = "stop" | "🛑" ;
BORROW = "borrow" | "🔗" ;
AS = "as" | "->" ;
EXTERN = "extern" | "🔌" ;
GURU = "guru" | "🧘" ;
THROW = "throw" | "❌" ;
ERROR_CODE = "code" | "->" ;
RETHROW = "rethrow" | "💀" ;
NOT_EQUAL = "!=" | "≠" ;
IMPORT = "import" | "🧩" ;
PLUGIN = "plugin" | "🛠️" ;
COLOUR = "colour" | "🎨:" ;
(* Contextual lexical rules:
Compound Code event terminals permit horizontal whitespace between words.
Symbols function vs spawn: a function signature followed by suite declares
a function; call without suite spawns. Ordinary calls have no task prefix.
Symbols loop followed by IDENT "in" is FOR; otherwise WHILE.
Symbols success vs boolean declaration: clause has pattern then suite;
declaration has binding then ASSIGN/expression or NEWLINE.
Symbols error followed by named call is THROW; pattern plus suite is ERROR.
Symbols optional selectors, literals and comments follow CYMPLE3.md.
Semantic constraints not expressible in this EBNF:
no nested declarations; at most one Guru/clause per kind;
Guru/events lead the function scope; progress outside an event receiver
is invalid; Race has no progress; stop only inside a quantum clause;
STEP only on ranges; channel directions are validated; no null messages;
typed returns/unpacking arity checked; no repeated type prefixes at uses;
imports/plugins/FFI at top level; target events cannot coexist with main.
One declared quantum binding receives the operation's value/outcomes.
Multi-binding initialization consumes matching tuple results, e.g.
newchannel returns distinct sender/receiver endpoints.
Comment-only lines emit no executable indentation. A function with no
executable statements requires an explicit RETURN, not just a comment.
Primitive type context disambiguates WORD literals. Reserved binding names
are the union of both lexical modes. Conditions must be non-null bool;
chained comparisons need explicitly valid parentheses. Quantum tasks have
homogeneous non-void return types; Result(T) is sealed intrinsic metadata.
Multi-binding assignment requires a matching tuple, not a broadcast value.
Optional typed CONST annotations are checked against their initializer.
*)