grammar Squaak::Grammar is PCT::Grammar;

rule TOP { {*} #= open <stat_or_def>* [ $ || <.panic: 'Syntax error'> ] {*} #= close }

rule stat_or_def { | <statement> {*} #= statement | <sub_definition> {*} #= sub_definition }

rule statement { | <if_statement> {*} #= if_statement | <while_statement> {*} #= while_statement | <for_statement> {*} #= for_statement | <try_statement> {*} #= try_statement | <throw_statement> {*} #= throw_statement | <return_statement> {*} #= return_statement | <sub_call> {*} #= sub_call | <assignment> {*} #= assignment | <variable_declaration> {*} #= variable_declaration | <do_block> {*} #= do_block }

rule if_statement { 'if' <expression> 'then' <block> ['else' <else=block>]? 'end' {*} }

rule while_statement { 'while' <expression> 'do' <block> 'end' {*} }

rule for_statement { 'for' <for_init> ',' <expression> [',' <step=expression>]? 'do' <statement>* 'end' {*} }

rule for_init { 'var' <identifier> '=' <expression> {*} }

rule try_statement { 'try' <try=block> 'catch' <exception> <catch=block> 'end' {*} }

rule exception { <identifier> {*} }

rule throw_statement { 'throw' <expression> {*} }

rule return_statement { 'return' <expression> {*} }

rule block { {*} #= open <statement>* {*} #= close }

rule do_block { 'do' <block> 'end' {*} }

rule assignment { <primary> '=' <expression> {*} }

rule sub_definition { 'sub' <identifier> <parameters> <statement>* 'end' {*} }

rule parameters { '(' [ <identifier> [',' <identifier>]* ]? ')' {*} }

rule variable_declaration { 'var' <identifier> ['=' <expression>]? {*} }

rule sub_call { <primary> <arguments> {*} }

rule arguments { '(' [ <expression> [',' <expression>]* ]? ')' {*} }

rule primary { <identifier> <postfix_expression>* {*} }

rule postfix_expression { | <key> {*} #= key | <member> {*} #= member | <index> {*} #= index }

rule key { '{' <expression> '}' {*} }

rule member { '.' <identifier> {*} }

rule index { '[' <expression> ']' {*} }

rule term { | <float_constant> {*} #= float_constant | <integer_constant> {*} #= integer_constant | <string_constant> {*} #= string_constant | <hash_constructor> {*} #= hash_constructor | <array_constructor> {*} #= array_constructor | <sub_call> {*} #= sub_call | <primary> {*} #= primary | '(' <expression> ')' {*} #= expression }

rule hash_constructor { '{' [ <named_field> [',' <named_field>]* ]? '}' {*} }

rule named_field { <string_constant> '=>' <expression> {*} }

rule array_constructor { '[' [ <expression> [',' <expression>]* ]? ']' {*} }

token identifier { <!keyword> <ident> {*} }

token integer_constant { \d+ {*} }

token float_constant { [ | \d+ '.' \d* | \d* '.' \d+ ] {*} }

token string_constant { \" <string_literal: '"'> \" {*} }

token keyword { ['and'|'catch' |'do' |'else' |'end' |'for'|'if' |'not' |'or' |'return'|'sub'|'throw'|'try' |'var'|'while']>> }

rule expression is optable { ... }

proto 'infix:or' is precedence('1') is pasttype('unless') { ... } proto 'infix:and' is tighter('infix:or') is pasttype('if') { ... }

proto 'infix:<' is tighter('infix:and') { ... } proto 'infix:<=' is equiv('infix:<') { ... } proto 'infix:>' is equiv('infix:<') { ... } proto 'infix:>=' is equiv('infix:<') { ... } proto 'infix:==' is equiv('infix:<') { ... } proto 'infix:!=' is equiv('infix:<') { ... }

proto 'infix:+' is tighter('infix:<') is pirop('n_add') { ... } proto 'infix:-' is equiv('infix:+') is pirop('n_sub') { ... }

proto 'infix:..' is equiv('infix:+') is pirop('n_concat') { ... }

proto 'infix:*' is tighter('infix:+') is pirop('n_mul') { ... } proto 'infix:%' is equiv('infix:*') is pirop('n_mod') { ... } proto 'infix:/' is equiv('infix:*') is pirop('n_div') { ... }

proto 'prefix:not' is tighter('infix:*') is pirop('n_not') { ... } proto 'prefix:-' is tighter('prefix:not') is pirop('n_neg') { ... }

proto 'term:' is tighter('prefix:-') is parsed(&term) { ... }

## this <ws> rule treats # as "comment to eol" ## you may want to replace it with something appropriate token ws { <!ww> [ '#' \N* \n? | \s+ ]* }


parrot