Skip to content

Grammar railroad diagram #386

@mingodad

Description

@mingodad

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]+

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions