-
Notifications
You must be signed in to change notification settings - Fork 38
Description
Asking copilot with Opus-4.5 to extract an EBNF for railroad diagram from lily source gave the one shown bellow (after small manual fixes).
I hope it can help document/develop/debug.
Notes from Opus-4.5:
Key Grammar Notes
Based on my analysis of the parser code, here are the important characteristics:
Keywords: The language has these keywords: if, elif, else, while, do, for, match, case, with, try, except, raise, return, break, continue, var, constant, define, class, enum, scoped, forward, import, public, protected, private, static, as, in, by
Block Syntax: Uses { } braces with a required : before the opening brace for control structures
Generics: Single uppercase letters A-Z in order
Special Tokens:
<[ and ]> for tuples
=> for hash key-value pairs and function return types
... for varargs and ranges
.@(type) for typecasts
|> for pipe operator
Match Expressions: Can be used as both statements and expressions
Properties: Class properties are prefixed with @
Keyword Arguments: Use :name syntax in function calls
//
// EBNF to be viewd at
// https://www.bottlecaps.de/rr/ui
//
// Copy and paste this at one of the urls shown above in the 'Edit Grammar' tab
// then click the 'View Diagram' tab.
//
/* Lily Language Grammar - Extracted from lily_parser.c */
/* Syntax compatible with https://www.bottlecaps.de/rr/ui */
/* ==================== Top Level ==================== */
program ::= statement*
statement ::= expression_statement
| var_declaration
| constant_declaration
| define_declaration
| class_declaration
| enum_declaration
| scoped_enum_declaration
| if_statement
| while_statement
| do_while_statement
| for_statement
| match_statement
| with_statement
| try_statement
| import_statement
| return_statement
| raise_statement
| break_statement
| continue_statement
| forward_declaration
| anonymous_block
| docblock statement
anonymous_block ::= '{' statement* '}'
/* ==================== Declarations ==================== */
var_declaration ::= 'var' var_decl_item (',' var_decl_item)*
var_decl_item ::= (identifier | property_word) (':' type)? '=' expression
constant_declaration ::= 'constant' const_decl_item (',' const_decl_item)*
const_decl_item ::= identifier '=' literal_value
literal_value ::= integer_literal
| double_literal
| string_literal
| bytestring_literal
| 'true'
| 'false'
/* ==================== Function Definition ==================== */
define_declaration ::= scope_modifier? 'static'? 'define' identifier
generic_params? ('(' parameters ')')? (':' return_type)?
'{' statement* '}'
forward_declaration ::= 'forward' (forward_class | forward_define)
forward_class ::= 'class' identifier generic_params? '{'
(forward_methods | '...') '}'
forward_methods ::= forward_method+
forward_method ::= scope_modifier 'static'? 'define' identifier
generic_params? ('(' parameters ')')? (':' return_type)?
'{' '...' '}'
forward_define ::= scope_modifier? 'static'? 'define' identifier
generic_params? ('(' parameters ')')? (':' return_type)?
'{' '...' '}'
scope_modifier ::= 'public' | 'protected' | 'private'
parameters ::= parameter (',' parameter)*
parameter ::= keyword_arg_marker? identifier ':' type ('=' expression)?
| keyword_arg_marker? scope_modifier 'var' property_word ':' type ('=' expression)?
keyword_arg_marker ::= ':' identifier
| ':_'
return_type ::= type | 'self'
generic_params ::= '[' generic_name (',' generic_name)* ']'
generic_name ::= [A-Z]
/* ==================== Class Declaration ==================== */
class_declaration ::= scope_modifier? 'class' identifier generic_params?
('(' class_parameters ')')? ('<' parent_class ('(' arguments ')')?)?
'{' class_body '}'
class_parameters ::= class_parameter (',' class_parameter)*
class_parameter ::= keyword_arg_marker? identifier ':' type ('=' expression)?
| keyword_arg_marker? scope_modifier 'var' property_word ':' type ('=' expression)?
parent_class ::= qualified_name
class_body ::= class_member*
class_member ::= docblock? scope_modifier (method_declaration | property_declaration)
method_declaration ::= 'static'? 'define' identifier generic_params?
('(' parameters ')')? (':' return_type)?
'{' statement* '}'
property_declaration ::= 'var' property_word ':' type '=' expression
/* ==================== Enum Declaration ==================== */
enum_declaration ::= 'enum' identifier generic_params? ('<' 'Integer')?
'{' variant_list enum_methods? '}'
scoped_enum_declaration ::= 'scoped' 'enum' identifier generic_params? ('<' 'Integer')?
'{' variant_list enum_methods? '}'
variant_list ::= variant (',' variant)* ','?
variant ::= identifier ('(' variant_types ')')?
| identifier ('=' integer_literal)?
variant_types ::= type (',' type)*
enum_methods ::= (docblock? 'define' identifier generic_params?
('(' parameters ')')? (':' return_type)?
'{' statement* '}')*
/* ==================== Control Flow ==================== */
if_statement ::= 'if' expression ':' '{' statement* '}'
('elif' expression ':' statement*)*
('else' ':' statement*)?
while_statement ::= 'while' expression ':' '{' statement* '}'
do_while_statement ::= 'do' ':' '{' statement* '}' 'while' expression
for_statement ::= 'for' for_vars 'in' for_source ':' '{' statement* '}'
for_vars ::= identifier (',' identifier)?
for_source ::= expression ('...' expression ('by' expression)?)?
match_statement ::= 'match' expression ':' '{' case_clause+ else_clause? '}'
case_clause ::= 'case' case_pattern (',' case_pattern)* ':' statement*
case_pattern ::= qualified_name ('(' decomposition_vars ')')?
decomposition_vars ::= decomposition_var (',' decomposition_var)*
decomposition_var ::= identifier | '_'
else_clause ::= 'else' ':' statement*
with_statement ::= 'with' expression 'as' case_pattern ':' '{' statement* '}'
('else' ':' '{' statement* '}')?
try_statement ::= 'try' ':' '{' statement* '}' except_clause+
except_clause ::= 'except' exception_type ('as' identifier)? ':' statement*
exception_type ::= qualified_name
/* ==================== Jump Statements ==================== */
return_statement ::= 'return' expression?
raise_statement ::= 'raise' expression
break_statement ::= 'break'
continue_statement ::= 'continue'
/* ==================== Import ==================== */
import_statement ::= 'import' import_spec (',' import_spec)*
import_spec ::= ('(' import_symbols ')')? import_path ('as' identifier)?
import_symbols ::= identifier (',' identifier)*
import_path ::= identifier | string_literal
/* ==================== Types ==================== */
type ::= simple_type
| generic_type
| function_type
simple_type ::= qualified_name
generic_type ::= qualified_name '[' type (',' type)* ']'
function_type ::= 'Function' '(' function_type_params? ('=>' type)? ')'
function_type_params ::= function_type_param (',' function_type_param)*
function_type_param ::= '*'? type '...'?
qualified_name ::= identifier ('.' identifier)*
/* ==================== Expressions ==================== */
expression_statement ::= expression
expression ::= ternary_expression
ternary_expression ::= '(' expression '?' expression ':' expression ')'
| binary_expression
binary_expression ::= unary_expression (binary_operator unary_expression)*
binary_operator ::= '||' | '&&' | '|' | '^' | '&'
| '==' | '!=' | '<' | '<=' | '>' | '>='
| '<<' | '>>'
| '+' | '-'
| '*' | '/' | '%'
| '|>'
unary_expression ::= unary_operator unary_expression
| postfix_expression
unary_operator ::= '!' | '-' | '~'
postfix_expression ::= primary_expression postfix_operation*
postfix_operation ::= call_operation
| subscript_operation
| member_access
| typecast_operation
call_operation ::= '(' arguments? ')'
arguments ::= argument (',' argument)*
argument ::= (':' identifier)? expression
subscript_operation ::= '[' expression ']'
member_access ::= '.' identifier
typecast_operation ::= '.@(' type ')'
primary_expression ::= identifier
| property_word
| literal
| self_expression
| lambda_expression
| list_expression
| hash_expression
| tuple_expression
| grouped_expression
| match_expression
| variant_shorthand
self_expression ::= 'self'
lambda_expression ::= '(|' lambda_params? '|' expression ')'
| '(||' expression ')'
lambda_params ::= lambda_param (',' lambda_param)*
lambda_param ::= identifier (':' type)?
list_expression ::= '[' list_items? ']'
list_items ::= expression (',' expression)* ','?
hash_expression ::= '[' hash_item (',' hash_item)* ','? ']'
hash_item ::= expression '=>' expression
tuple_expression ::= '<[' tuple_items? ']>'
tuple_items ::= expression (',' expression)* ','?
grouped_expression ::= '(' expression ')'
match_expression ::= 'match' expression ':' '{' match_expr_cases '}'
match_expr_cases ::= match_expr_case+
match_expr_case ::= 'case' identifier ('(' decomposition_vars ')')? ':' expression
| 'else' ':' expression
variant_shorthand ::= '.' identifier
/* ==================== Literals ==================== */
literal ::= integer_literal
| double_literal
| string_literal
| bytestring_literal
| byte_literal
| boolean_literal
| unit_literal
| magic_constant
boolean_literal ::= 'true' | 'false'
unit_literal ::= 'unit'
magic_constant ::= '__line__' | '__file__' | '__function__' | '__dir__'
/* ==================== Lexical Elements ==================== */
identifier ::= letter (letter | digit | '_')*
property_word ::= '@' identifier
integer_literal ::= digit+
| '0x' hex_digit+
| '0c' octal_digit+
| '0b' binary_digit+
double_literal ::= digit+ '.' digit+ exponent?
exponent ::= ('e' | 'E') ('+' | '-')? digit+
string_literal ::= '"' string_char* '"'
bytestring_literal ::= 'B"' string_char* '"'
byte_literal ::= "'" byte_char "'"
docblock ::= '#[' docblock_content* ']#'
docblock_content ::= [^#] | '#' [^#x5D]
string_char ::= [^"\] | escape_sequence
escape_sequence ::= '\' [nrt"0\]
| '\x' hex_digit hex_digit
byte_char ::= [^'\] | escape_sequence
letter ::= [a-zA-Z_]
digit ::= [0-9]
hex_digit ::= [0-9a-fA-F]
octal_digit ::= [0-7]
binary_digit ::= [01]
/* ==================== Comments ==================== */
comment ::= '#' [^#\n] [^\n]*
| '##' [^\n]*
whitespace ::= [ \t\n\r]+