pyret-lang
pyret-lang copied to clipboard
Grammar railroad diagram
After massaging a bit src/js/base/pyret-grammar.bnf and add tokens from src/js/base/pyret-tokenizer.js and copying the resulting EBNF shown bellow on https://www.bottlecaps.de/rr/ui in the TAB Edit Grammar and then swithcing to the TAB View Diagram we have a full grammar railroad diagram.
/*
name::= PyretGrammar
*/
program::= prelude block
prelude::= (use_stmt)? (provide_stmt|import_stmt)*
use_stmt::= USE NAME import_source
import_stmt::= INCLUDE import_source
| INCLUDE FROM module_ref COLON (include_spec (COMMA include_spec)* (COMMA)?)? END
| IMPORT import_source AS NAME
| IMPORT comma_names FROM import_source
import_source::= import_special | import_name
import_special::= NAME PARENNOSPACE STRING (COMMA STRING)* RPAREN
import_name::= NAME
include_spec::= include_name_spec
| include_type_spec
| include_data_spec
| include_module_spec
include_name_spec::= name_spec
include_type_spec::= TYPE name_spec
include_data_spec::= DATA data_name_spec (hiding_spec)?
include_module_spec::= MODULE name_spec
provide_stmt::= provide_vals_stmt | provide_types_stmt | provide_block
provide_vals_stmt::= PROVIDE stmt END | PROVIDE (STAR|TIMES)
provide_types_stmt::= PROVIDE_TYPES record_ann | PROVIDE_TYPES (STAR|TIMES)
provide_block::= PROVIDECOLON (provide_spec (COMMA provide_spec)* (COMMA)?)? END
provide_block::= PROVIDE FROM module_ref COLON (provide_spec (COMMA provide_spec)* (COMMA)?)? END
provide_spec::= provide_name_spec
| provide_type_spec
| provide_data_spec
| provide_module_spec
name_spec::= (STAR|TIMES) (hiding_spec)? | module_ref | module_ref AS NAME
data_name_spec::= (STAR|TIMES) | module_ref
provide_name_spec::= name_spec
provide_type_spec::= TYPE name_spec
provide_data_spec::= DATA data_name_spec (hiding_spec)?
provide_module_spec::= MODULE name_spec
hiding_spec::= HIDING (PARENSPACE | PARENNOSPACE) ((NAME COMMA)* NAME)? RPAREN
module_ref::= (NAME DOT)* NAME
comma_names::= NAME (COMMA NAME)*
block::= stmt*
stmt::= type_expr | newtype_expr | spy_stmt
| let_expr | fun_expr | data_expr | when_expr
| var_expr | rec_expr | assign_expr | check_test | check_expr
| contract_stmt
spy_stmt::= SPY (binop_expr)? COLON (spy_contents)? END
spy_contents::= spy_field (COMMA spy_field)*
spy_field::= id_expr | NAME COLON binop_expr
type_expr::= TYPE NAME ty_params EQUALS ann
newtype_expr::= NEWTYPE NAME AS NAME
let_expr::= toplevel_binding EQUALS binop_expr
binding::= name_binding | tuple_binding
tuple_binding::= LBRACE (binding SEMI)* binding (SEMI)? RBRACE (AS name_binding)?
name_binding::= (SHADOW)? NAME (COLONCOLON ann)?
toplevel_binding::= binding
//# toplevel_binding::= (SHADOW)? NAME COLONCOLON noparen_arrow_ann
multi_let_expr::= LET let_binding (COMMA let_binding)* (BLOCK|COLON) block END
let_binding::= let_expr | var_expr
letrec_expr::= LETREC let_expr (COMMA let_expr)* (BLOCK|COLON) block END
type_bind::= NAME ty_params EQUALS ann
newtype_bind::= NEWTYPE NAME AS NAME
type_let_bind::= type_bind | newtype_bind
type_let_expr::= TYPE_LET type_let_bind (COMMA type_let_bind)* (BLOCK|COLON) block END
contract_stmt::= NAME COLONCOLON ty_params (ann | noparen_arrow_ann)
fun_expr::= FUN NAME fun_header (BLOCK|COLON) doc_string block where_clause END
fun_header::= ty_params args return_ann | ty_params bad_args return_ann
ty_params::= ((LANGLE|LT) comma_names (RANGLE|GT))?
args::= (PARENNOSPACE|PARENAFTERBRACE) (binding (COMMA binding)*)? RPAREN
bad_args::= PARENSPACE (binding (COMMA binding)*)? RPAREN
return_ann::= (THINARROW ann)?
doc_string::= (DOC STRING)?
where_clause::= (WHERE block)?
check_expr::= (CHECK|EXAMPLES) STRING COLON block END
| (CHECKCOLON|EXAMPLESCOLON) block END
check_test::= binop_expr check_op (PERCENT (PARENSPACE|PARENNOSPACE) binop_expr RPAREN)? binop_expr (BECAUSE binop_expr)?
| binop_expr check_op_postfix (BECAUSE binop_expr)?
| binop_expr
data_expr::= DATA NAME ty_params COLON (first_data_variant)? data_variant* data_sharing where_clause END
variant_constructor::= NAME variant_members
first_data_variant::= variant_constructor data_with | NAME data_with
data_variant::= BAR variant_constructor data_with | BAR NAME data_with
variant_members::= PARENNOSPACE (variant_member (COMMA variant_member)*)? RPAREN
variant_member::= (REF)? binding
data_with::= (WITH fields)?
data_sharing::= (SHARING fields)?
var_expr::= VAR toplevel_binding EQUALS binop_expr
rec_expr::= REC toplevel_binding EQUALS binop_expr
assign_expr::= NAME COLONEQUALS binop_expr
when_expr::= WHEN binop_expr (BLOCK|COLON) block END
binop_expr::= expr (binop expr)*
binop::= PLUS | DASH | TIMES | SLASH | LEQ | GEQ | EQUALEQUAL | SPACESHIP | EQUALTILDE
| NEQ | LT | GT | AND | OR | CARET
check_op::= IS | ISEQUALEQUAL | ISEQUALTILDE | ISSPACESHIP | ISROUGHLY
| ISNOT | ISNOTEQUALEQUAL | ISNOTEQUALTILDE | ISNOTSPACESHIP
| RAISES | RAISESOTHER
| SATISFIES | SATISFIESNOT
| RAISESSATISFIES | RAISESVIOLATES
check_op_postfix::= RAISESNOT
expr::= paren_expr | id_expr | prim_expr
| lambda_expr | method_expr | app_expr
| obj_expr | tuple_expr | tuple_get
| dot_expr
| template_expr
| bracket_expr //# NOTE(joe)::= experimental for access
| get_bang_expr | update_expr
| extend_expr
| if_expr | if_pipe_expr | cases_expr
| for_expr
| user_block_expr | inst_expr
| multi_let_expr | letrec_expr
| type_let_expr
| construct_expr
| table_select
| table_extend
| table_filter
| table_order
| table_extract
| table_update
| table_expr
| load_table_expr
| reactor_expr
template_expr ::= DOTDOTDOT
bad_expr::= UNTERMINATED_STRING | UNTERMINATED_BLOCK_COMMENT | BAD_OPER | BAD_NUMBER | UNKNOWN
//# paren_exprs must be preceded by a space, so as not be be confused with
//# function application
paren_expr::= (PARENSPACE|PARENAFTERBRACE) binop_expr RPAREN
id_expr::= NAME
prim_expr::= num_expr | frac_expr | rfrac_expr | bool_expr | string_expr
num_expr::= NUMBER
frac_expr::= RATIONAL
rfrac_expr::= ROUGHRATIONAL
bool_expr::= TRUE | FALSE
string_expr::= STRING
lambda_expr::= LAM fun_header (BLOCK|COLON) doc_string block where_clause END
| LBRACE fun_header (BLOCK|COLON) doc_string block where_clause RBRACE
method_expr::= METHOD fun_header (BLOCK|COLON) doc_string block where_clause END
app_expr::= expr app_args
//# These two productions are carefully rigged to *not* parse unary `f (x)`
//# otherwise, we'd admit ambiguous parses. Instead, parse_pyret detects these
//# two cases and produces a parse error, while well_formedness detects the unary
//# case and produces a well_formedness error with a similar message.
| expr PARENSPACE RPAREN
| expr PARENSPACE binop_expr COMMA binop_expr (COMMA binop_expr)* RPAREN
//# application must have the function expression immediately adjacent to
//# the argument list, so as not to be confused with parenthesized exprs
app_args::= PARENNOSPACE opt_comma_binops RPAREN
opt_comma_binops::= (comma_binops)?
comma_binops::= binop_expr (COMMA binop_expr)*
trailing_opt_comma_binops::= (comma_binops (COMMA)? | )
//# app_arg_elt::= binop_expr COMMA
//# at least one annotation must be provided
inst_expr::= expr LANGLE ann (COMMA ann)* (RANGLE|GT)
tuple_expr::= LBRACE tuple_fields RBRACE
tuple_fields::= binop_expr (SEMI binop_expr)* (SEMI)?
tuple_get::= expr DOT LBRACE NUMBER RBRACE
obj_expr::= LBRACE obj_fields RBRACE | LBRACE RBRACE
obj_fields::= obj_field (COMMA obj_field)* (COMMA)?
obj_field::= key COLON binop_expr
| REF key (COLONCOLON ann)? COLON binop_expr
| METHOD key fun_header (BLOCK|COLON) doc_string block where_clause END
fields::= field (COMMA field)* (COMMA)?
field::= key COLON binop_expr
| METHOD key fun_header (BLOCK|COLON) doc_string block where_clause END
key::= NAME
construct_expr::= LBRACK construct_modifier binop_expr COLON trailing_opt_comma_binops RBRACK
construct_modifier::= | LAZY
table_expr::= TABLE table_headers table_rows END
table_headers::= (list_table_header* table_header)?
list_table_header::= table_header COMMA
table_header::= NAME (COLONCOLON ann)?
table_rows::= (table_row* table_row)?
table_row::= ROW table_items
table_items::= (list_table_item* binop_expr)?
list_table_item::= binop_expr COMMA
//# NOTE(joe)::= just parsing as "fields" for now, and handling naming in
//# desugaring/well_formed, so that better error messages can be given
reactor_expr::= REACTOR COLON
fields
END
dot_expr::= expr DOT NAME
bracket_expr::= expr LBRACK binop_expr RBRACK
get_bang_expr::= expr BANG NAME
extend_expr::= expr DOT LBRACE fields RBRACE
update_expr::= expr BANG LBRACE fields RBRACE
if_expr::= IF binop_expr (BLOCK|COLON) block else_if* (ELSECOLON block)? END
else_if::= ELSEIF binop_expr COLON block
if_pipe_expr::= ASK (BLOCK|COLON) if_pipe_branch* (BAR OTHERWISECOLON block)? END
if_pipe_branch::= BAR binop_expr THENCOLON block
cases_binding::= (REF)? binding
cases_args::= PARENNOSPACE (cases_binding (COMMA cases_binding)*)? RPAREN
cases_expr::= CASES (PARENSPACE|PARENNOSPACE) ann RPAREN binop_expr (BLOCK|COLON) cases_branch* (BAR ELSE THICKARROW block)? END
cases_branch::= BAR NAME (cases_args)? THICKARROW block
for_bind::= binding FROM binop_expr
for_expr::= FOR expr PARENNOSPACE (for_bind (COMMA for_bind)*)? RPAREN return_ann (BLOCK|COLON) block END
column_order ::= NAME (ASCENDING|DESCENDING)
table_select ::= TABLE_SELECT NAME (COMMA NAME)* FROM expr END
table_filter ::= TABLE_FILTER expr (USING binding (COMMA binding)*)? COLON binop_expr END
table_order ::= TABLE_ORDER expr COLON column_order (COMMA column_order)* END
table_extract::= TABLE_EXTRACT NAME FROM expr END
table_update ::= TABLE_UPDATE expr (USING binding (COMMA binding)*)? COLON obj_fields END
table_extend ::= TABLE_EXTEND expr (USING binding (COMMA binding)*)? COLON table_extend_fields END
table_extend_fields::= list_table_extend_field* table_extend_field (COMMA)?
list_table_extend_field::= table_extend_field COMMA
table_extend_field::= key (COLONCOLON ann)? COLON binop_expr
//# Commenting this out until we know whether or not it makes sense
//# | REF key (COLONCOLON ann)? COLON binop_expr
| key (COLONCOLON ann)? COLON expr OF NAME
//# More informative to allow missing load_table_specs to parse and mark it as a
//# well_formedness error than to reject it at parse_time
load_table_expr::= LOAD_TABLE COLON table_headers (load_table_specs)? END
load_table_specs::= load_table_spec* load_table_spec
load_table_spec::= SOURCECOLON expr
| SANITIZE NAME USING expr
user_block_expr::= BLOCK block END
ann::= name_ann | record_ann | arrow_ann | app_ann | pred_ann | dot_ann | tuple_ann
name_ann::= NAME
comma_ann_field::= ann_field (COMMA ann_field)*
trailing_opt_comma_ann_field::= (comma_ann_field (COMMA)? | )
record_ann::= LBRACE trailing_opt_comma_ann_field RBRACE
ann_field::= NAME COLONCOLON ann
tuple_ann::= LBRACE ann (SEMI ann)* (SEMI)? RBRACE
noparen_arrow_ann::= (arrow_ann_args)? THINARROW ann
arrow_ann_args::= comma_anns | (PARENSPACE|PARENNOSPACE|PARENAFTERBRACE) comma_ann_field RPAREN
arrow_ann::= (PARENSPACE|PARENNOSPACE|PARENAFTERBRACE) (arrow_ann_args)? THINARROW ann RPAREN
app_ann::= (name_ann|dot_ann) LANGLE comma_anns (RANGLE|GT)
comma_anns::= ann (COMMA ann)*
pred_ann::= ann PERCENT (PARENSPACE|PARENNOSPACE) id_expr RPAREN
dot_ann ::= NAME DOT NAME
// Tokens
AND ::= "and"
AS ::= "as"
ASCENDING ::= "ascending"
ASK ::= "ask"
BY ::= "by"
CASES ::= "cases"
CHECK ::= "check"
DATA ::= "data"
DESCENDING ::= "descending"
DO ::= "do"
RAISESNOT ::= "does-not-raise"
ELSE ::= "else"
ELSEIF ::= "else if"
END ::= "end"
EXAMPLES ::= "examples"
TABLE_EXTEND ::= "extend"
TABLE_EXTRACT ::= "extract"
FALSE ::= "false"
FOR ::= "for"
FROM ::= "from"
FUN ::= "fun"
HIDING ::= "hiding"
IF ::= "if"
IMPORT ::= "import"
INCLUDE ::= "include"
IS ::= "is"
ISEQUALEQUAL ::= "is=="
ISEQUALTILDE ::= "is=~"
ISNOT ::= "is-not"
ISNOTEQUALEQUAL ::= "is-not=="
ISNOTEQUALTILDE ::= "is-not=~"
ISNOTSPACESHIP ::= "is-not<=>"
ISROUGHLY ::= "is-roughly"
ISSPACESHIP ::= "is<=>"
BECAUSE ::= "because"
LAM ::= "lam"
LAZY ::= "lazy"
LET ::= "let"
LETREC ::= "letrec"
LOAD_TABLE ::= "load-table"
METHOD ::= "method"
MODULE ::= "module"
NEWTYPE ::= "newtype"
OF ::= "of"
OR ::= "or"
PROVIDE ::= "provide"
PROVIDE_TYPES ::= "provide-types"
RAISES ::= "raises"
RAISESOTHER ::= "raises-other-than"
RAISESSATISFIES ::= "raises-satisfies"
RAISESVIOLATES ::= "raises-violates"
REACTOR ::= "reactor"
REC ::= "rec"
REF ::= "ref"
SANITIZE ::= "sanitize"
SATISFIES ::= "satisfies"
TABLE_SELECT ::= "select"
SHADOW ::= "shadow"
TABLE_FILTER ::= "sieve"
SPY ::= "spy"
TABLE_ORDER ::= "order"
TABLE_UPDATE ::= "transform"
TRUE ::= "true"
TYPE ::= "type"
TYPE_LET ::= "type-let"
USING ::= "using"
USE ::= "use"
VAR ::= "var"
SATISFIESNOT ::= "violates"
WHEN ::= "when"
BLOCK ::= "block:"
CHECKCOLON ::= "check:"
DOC ::= "doc:"
ELSECOLON ::= "else:"
EXAMPLESCOLON ::= "examples:"
OTHERWISECOLON ::= "otherwise:"
PROVIDECOLON ::= "provide:"
ROW ::= "row:"
SHARING ::= "sharing:"
SOURCECOLON ::= "source:"
TABLE ::= "table:"
THENCOLON ::= "then:"
WHERE ::= "where:"
WITH ::= "with:"
LBRACK ::= "["
RBRACK ::= "]"
LBRACE ::= "{"
RBRACE ::= "}"
LPAREN ::= "("
RPAREN ::= ")"
SEMI ::= ";"
BACKSLASH ::= "\\"
DOTDOTDOT ::= "..."
DOT ::= "."
BANG ::= "!"
PERCENT ::= "%"
COMMA ::= ","
THINARROW ::= "->"
COLONEQUALS ::= ":="
COLON ::= ":"
BAR ::= "|"
EQUALS ::= "="
LANGLE ::= "<"
STAR ::= "*"
RANGLE ::= ">"
CARET ::= "^"
PLUS ::= "+"
DASH ::= "-"
TIMES ::= "*"
SLASH ::= "/"
SPACESHIP ::= "<=>"
LEQ ::= "<="
GEQ ::= ">="
EQUALEQUAL ::= "=="
EQUALTILDE ::= "=~"
NEQ ::= "<>"
LT ::= "<"
GT ::= ">"
THICKARROW ::= "=>"
COLONCOLON ::= "::"