Jyro Language Grammar
Formal grammar specification for the Jyro scripting language, expressed in Extended Backus-Naur Form (EBNF).
Notation
| Symbol | Meaning |
|---|---|
= | Definition |
; | End of rule |
\| | Alternative |
, | Concatenation |
{ ... } | Repetition (zero or more) |
[ ... ] | Optional (zero or one) |
( ... ) | Grouping |
" ... " | Terminal string |
' ... ' | Terminal string (alternate quoting) |
(* ... *) | Comment |
1. Lexical grammar
1.1 Whitespace and comments
whitespace = ? any Unicode whitespace character ? ;
line_comment = "#" , { ? any character except newline ? } ;
ws = { whitespace | line_comment } ;
1.2 Identifiers
letter = "A" | "B" | ... | "Z" | "a" | "b" | ... | "z" ;
digit = "0" | "1" | ... | "9" ;
identifier_start = letter | "_" ;
identifier_char = letter | digit | "_" ;
identifier = identifier_start , { identifier_char } ; (* must not be a keyword *)
1.3 Keywords
The following words are reserved and cannot be used as identifiers:
var if then elseif else end
switch do case default while for
foreach in return fail break continue
and or not is true false
null number string boolean object array
to downto by
1.4 Literals
Number literals
hex_digit = digit | "A" | "B" | "C" | "D" | "E" | "F"
| "a" | "b" | "c" | "d" | "e" | "f" ;
binary_digit = "0" | "1" ;
decimal_literal = [ "-" ] , digit , { digit } , [ "." , digit , { digit } ] ;
hex_literal = [ "-" ] , "0x" , hex_digit , { hex_digit } ;
binary_literal = [ "-" ] , "0b" , binary_digit , { binary_digit } ;
number_literal = hex_literal | binary_literal | decimal_literal ;
String literals
escape_sequence = "\" , ( "n" | "r" | "t" | "\" | '"' | "'" | "0"
| "u" , hex_digit , hex_digit , hex_digit , hex_digit ) ;
double_string = '"' , { escape_sequence | ? any character except '"' and '\' ? } , '"' ;
single_string = "'" , { escape_sequence | ? any character except "'" and '\' ? } , "'" ;
string_literal = double_string | single_string ;
Boolean and null literals
boolean_literal = "true" | "false" ;
null_literal = "null" ;
literal = number_literal | string_literal | boolean_literal | null_literal ;
1.5 Operators and punctuation
Arithmetic operators
| Operator | Description |
|---|---|
+ | Addition |
- | Subtraction |
* | Multiplication |
/ | Division |
% | Modulo |
Comparison operators
| Operator | Description |
|---|---|
== | Equal |
!= | Not equal |
< | Less than |
<= | Less than or equal |
> | Greater than |
>= | Greater than or equal |
Logical operators
| Operator | Description |
|---|---|
and | Logical AND |
or | Logical OR |
not | Logical NOT |
Assignment operators
| Operator | Description |
|---|---|
= | Assign |
+= | Add and assign |
-= | Subtract and assign |
*= | Multiply and assign |
/= | Divide and assign |
%= | Modulo and assign |
Other operators
| Operator | Description |
|---|---|
?? | Null coalescing |
? : | Ternary conditional |
is | Type check |
is not | Negated type check |
++ | Increment (prefix or postfix) |
-- | Decrement (prefix or postfix) |
. | Property access |
[ ] | Index access |
( ) | Function call / grouping |
=> | Lambda arrow |
Punctuation
| Symbol | Usage |
|---|---|
( | Open parenthesis |
) | Close parenthesis |
[ | Open bracket |
] | Close bracket |
{ | Open brace |
} | Close brace |
, | Separator |
: | Type annotation / object pair |
2. Syntactic grammar
2.1 Program structure
program = ws , { statement } , EOF ;
block = { statement } ;
2.2 Statements
statement = var_decl
| if_stmt
| while_stmt
| for_stmt
| foreach_stmt
| switch_stmt
| return_stmt
| fail_stmt
| break_stmt
| continue_stmt
| assignment_stmt
| expr_stmt ;
Variable declaration
type_keyword = "number" | "string" | "boolean" | "object" | "array" ;
var_decl = "var" , identifier , [ ":" , type_keyword ] , [ "=" , expression ] ;
Assignment
assign_op = "=" | "+=" | "-=" | "*=" | "/=" | "%=" ;
assign_target = identifier | property_access | index_access ;
assignment_stmt = assign_target , assign_op , expression ;
If statement
if_stmt = "if" , expression , "then" , block ,
{ "elseif" , expression , "then" , block } ,
[ "else" , block ] ,
"end" ;
While loop
while_stmt = "while" , expression , "do" , block , "end" ;
For loop
for_direction = "to" | "downto" ;
for_stmt = "for" , identifier , "in" , expression ,
for_direction , expression ,
[ "by" , expression ] ,
"do" , block , "end" ;
ForEach loop
foreach_stmt = "foreach" , identifier , "in" , expression ,
"do" , block , "end" ;
Switch statement
case_values = expression , { "," , expression } ;
switch_case = "case" , case_values , "then" , block ;
default_case = "default" , "then" , block ;
switch_stmt = "switch" , expression , "do" ,
{ switch_case } ,
[ default_case ] ,
"end" ;
Return statement
return_stmt = "return" , [ expression ] ; (* expression must begin on same line *)
Fail statement
fail_stmt = "fail" , [ expression ] ; (* expression must begin on same line *)
Break and continue
break_stmt = "break" ;
continue_stmt = "continue" ;
Expression statement
expr_stmt = expression ;
2.3 Expressions
Expressions are listed below in order of increasing precedence. Each level binds tighter than the one above it.
expression = ternary_expr ;
Precedence 1: ternary conditional (lowest)
ternary_expr = coalesce_expr , [ "?" , expression , ":" , expression ] ;
Precedence 2: null coalescing (right-associative)
coalesce_expr = or_expr , { "??" , or_expr } ; (* right-associative *)
Precedence 3: logical OR
or_expr = and_expr , { "or" , and_expr } ;
Precedence 4: logical AND
and_expr = not_expr , { "and" , not_expr } ;
Precedence 5: logical NOT (prefix unary)
not_expr = "not" , not_expr
| type_check_expr ;
Precedence 6: type check
type_check_expr = equality_expr , [ "is" , [ "not" ] , type_keyword ] ;
Precedence 7: equality
equality_op = "==" | "!=" ;
equality_expr = relational_expr , { equality_op , relational_expr } ;
Precedence 8: relational
relational_op = "<" | "<=" | ">" | ">=" ;
relational_expr = additive_expr , { relational_op , additive_expr } ;
Precedence 9: additive
additive_op = "+" | "-" ;
additive_expr = multiplicative_expr , { additive_op , multiplicative_expr } ;
Precedence 10: multiplicative
multiplicative_op = "*" | "/" | "%" ;
multiplicative_expr = unary_expr , { multiplicative_op , unary_expr } ;
Precedence 11: unary prefix
unary_expr = "++" , postfix_expr (* prefix increment *)
| "--" , postfix_expr (* prefix decrement *)
| "-" , unary_expr (* numeric negation *)
| postfix_expr ;
Precedence 12: postfix
postfix_expr = primary_expr , { postfix_op } ;
postfix_op = "(" , [ expression , { "," , expression } ] , ")" (* function call *)
| "." , identifier (* property access *)
| "[" , expression , "]" (* index access *)
| "++" (* postfix increment *)
| "--" ; (* postfix decrement *)
Note: Function calls are only valid when the base expression is an identifier. The call Name(args) invokes the function Name.
Precedence 13: primary (highest)
primary_expr = lambda_expr
| null_literal
| boolean_literal
| number_literal
| string_literal
| array_literal
| object_literal
| grouped_expr
| identifier ;
Composite literals
array_literal = "[" , [ expression , { "," , expression } ] , "]" ;
object_key = identifier | string_literal ;
object_property = object_key , ":" , expression ;
object_literal = "{" , [ object_property , { "," , object_property } ] , "}" ;
Lambda expressions
lambda_params = "(" , [ identifier , { "," , identifier } ] , ")"
| identifier ;
lambda_expr = lambda_params , "=>" , expression ;
Grouped expression
grouped_expr = "(" , expression , ")" ;
3. Operator precedence summary
From lowest to highest precedence:
| Prec. | Operator(s) | Associativity | Description |
|---|---|---|---|
| 1 | ? : | Right | Ternary conditional |
| 2 | ?? | Right | Null coalescing |
| 3 | or | Left | Logical OR |
| 4 | and | Left | Logical AND |
| 5 | not | Prefix | Logical NOT |
| 6 | is , is not | Postfix | Type check |
| 7 | == , != | Left | Equality |
| 8 | < , <= , > , >= | Left | Relational |
| 9 | + , - | Left | Additive |
| 10 | * , / , % | Left | Multiplicative |
| 11 | - , ++ , -- | Prefix | Unary prefix |
| 12 | () , . , [] , ++ , -- | Left/Postfix | Postfix / access |
4. Type system
Jyro supports the following runtime types. Type keywords are used in variable declarations and is expressions.
| Type Keyword | Values |
|---|---|
number | IEEE 754 double-precision floating point |
string | Unicode character sequence |
boolean | true or false |
object | Key-value map with string keys |
array | Ordered, indexable collection of values |
null | The singleton null value |
5. Grammar Notes
-
Semicolons: Jyro does not use semicolons. Statements are separated by whitespace.
-
Block delimiters: All compound statements use keyword pairs (
then/end,do/end). -
Same-line constraint: For
returnandfailstatements, the optional expression must begin on the same line as the keyword. A newline after the keyword is interpreted as a barereturnorfail. -
Object property keys: Object literal keys may be unquoted identifiers (including keywords like
andortrue) or quoted strings. -
Assignment targets: Only identifiers, property access expressions, and index access expressions are valid on the left-hand side of an assignment.
-
For loop semantics: The
tokeyword indicates ascending iteration;downtoindicates descending. The optionalbyclause specifies the step value. -
Switch fallthrough: There is no fallthrough between cases. Each
caseblock is implicitly terminated by the nextcase,default, or the closingendof theswitchstatement. -
Comments: Only single-line comments are supported, beginning with
#.