This appendix collects the grammar of Teascript in one place, written in the notation defined in Notation and Conventions. It consolidates the productions given throughout this specification; each chapter remains the authority for the meaning of the constructs.
The grammar has two parts. The lexical grammar has characters as its alphabet and defines the tokens; the syntactic grammar has tokens as its alphabet and defines the structure of programs. Expressions are written here as a stratified grammar, one production per precedence level, which is equivalent to the precedence table of Expressions.
EBNF
(* ======================================================================== *)
(* LEXICAL GRAMMAR *)
(* ======================================================================== *)
(* ---- Source text ---- *)
token_stream ::= ( whitespace | comment | token )* <eof>
token ::= keyword | symbol | <name> | <number> | <string> | <interpolation>
whitespace ::= ' ' | '\t' | '\v' | '\f' | line_break
line_break ::= '\r\n' | '\n\r' | '\n' | '\r'
comment ::= line_comment | block_comment
line_comment ::= '//' [^\n]*
block_comment ::= '/*' ( block_comment | any )* '*/' (* comments nest *)
(* ---- Keywords and symbols ---- *)
keyword ::= 'and' | 'as' | 'break' | 'case' | 'class' | 'const'
| 'continue' | 'default' | 'do' | 'else' | 'export' | 'false'
| 'for' | 'from' | 'function' | 'if' | 'import' | 'in' | 'is'
| 'new' | 'nil' | 'not' | 'operator' | 'or' | 'return' | 'self'
| 'static' | 'super' | 'switch' | 'true' | 'var' | 'while'
symbol ::= '(' | ')' | '[' | ']' | '{' | '}'
| ',' | ';' | ':' | '.' | '?' | '=>'
| '+' | '-' | '*' | '/' | '%' | '**'
| '&' | '|' | '^' | '~' | '<<' | '>>'
| '==' | '!=' | '<' | '<=' | '>' | '>=' | '!'
| '..' | '...'
| assign_op
assign_op ::= '=' | '+=' | '-=' | '*=' | '/=' | '%=' | '**='
| '&=' | '|=' | '^=' | '<<=' | '>>='
(* ---- Identifiers ---- *)
<name> ::= ? name that is not a keyword ?
name ::= name_start name_part*
name_start ::= [A-Za-z_]
name_part ::= [A-Za-z0-9_]
(* ---- Numbers ---- *)
<number> ::= integer | float
integer ::= digits | '0' [xX] hex_digits
float ::= digits '.' digits exponent?
| digits exponent
| '0' [xX] hex_digits '.' hex_digits hex_exponent?
| '0' [xX] hex_digits ( '.' hex_digits )? hex_exponent
exponent ::= [eE] [+-]? digits
hex_exponent ::= [pP] [+-]? digits
digits ::= [0-9] ( '_'? [0-9] )*
hex_digits ::= [0-9A-Fa-f] ( '_'? [0-9A-Fa-f] )*
(* ---- Strings ---- *)
q ::= "'" | '"' | '`' (* the three delimiters are equivalent *)
(* A string without interpolation is a single <string> token. A string with
interpolations is scanned as <interpolation> ... <string> tokens: the '}'
that closes an interpolation is found by counting braces. *)
<string> ::= q string_item* q (* plain string *)
| '}' string_item* q (* last piece of an interpolated string *)
| q q q long_char* q q q (* long string; q is the same character *)
<interpolation> ::= q string_item* '${' (* first piece *)
| '}' string_item* '${' (* middle piece *)
string_item ::= string_char | escape
string_char ::= ? any byte except the delimiter, '\', a line break, and the start '${' of an interpolation ?
long_char ::= ? any byte except the delimiter character; no escapes and no interpolation ?
escape ::= '\' ( q | '\' | '$' | '0' | 'a' | 'b' | 't' | 'n' | 'v' | 'f' | 'r' | 'e'
| 'x' hex_digit hex_digit
| 'u' hex_digit hex_digit hex_digit hex_digit
| 'U' hex_digit hex_digit hex_digit hex_digit
hex_digit hex_digit hex_digit hex_digit
| [1-9] [0-9]? [0-9]? ) (* decimal value at most 255 *)
hex_digit ::= [0-9A-Fa-f]
(* ======================================================================== *)
(* SYNTACTIC GRAMMAR *)
(* ======================================================================== *)
(* ---- Programs ---- *)
chunk ::= declaration* <eof>
eval_chunk ::= expression <eof> (* evaluation of one expression *)
declaration ::= class_declaration
| function_declaration
| variable_declaration
| statement
block ::= '{' declaration* '}'
(* ---- Declarations ---- *)
variable_declaration ::= ( 'var' | 'const' ) declarators
declarators ::= <name> '=' expression ( ',' <name> '=' expression )*
| <name> ( ',' <name> )* ( '=' expression_list )?
| rest_binding ( ',' rest_binding )+ '=' expression (* exactly one '...' *)
rest_binding ::= '...'? <name>
expression_list ::= expression ( ',' expression )*
function_declaration ::= 'function' <name> '(' parameters? ')' block
| 'function' <name> ( '.' <name> )+ '(' parameters? ')' block
| 'function' <name> ( '.' <name> )* ':' <name> '(' parameters? ')' block
parameters ::= parameter ( ',' parameter )*
parameter ::= <name>
| <name> '=' expression
| '...' <name>
class_declaration ::= 'class' <name> ( ':' expression )? '{' member* '}'
member ::= 'new' '(' parameters? ')' block (* constructor *)
| 'function' <name> '(' parameters? ')' block (* method *)
| 'static' <name> '(' parameters? ')' block (* static method *)
| 'operator' operator_symbol '(' parameters? ')' block (* operator method *)
| <name> block (* getter *)
| <name> '=' '(' parameters? ')' block (* setter *)
operator_symbol ::= '+' | '-' | '*' | '/' | '%' | '**'
| '&' | '|' | '~' | '^' | '<<' | '>>'
| '<' | '<=' | '>' | '>=' | '=='
| '[' ']' | '[' ']' '='
(* ---- Statements ---- *)
statement ::= ';'
| block
| if_statement
| switch_statement
| while_statement
| do_statement
| for_statement
| for_in_statement
| break_statement
| continue_statement
| return_statement
| import_statement
| from_statement
| export_statement
| multiple_assignment
| expression_statement
if_statement ::= 'if' expression block ( 'else' ( if_statement | block ) )?
switch_statement ::= 'switch' expression case_clause* default_clause?
case_clause ::= 'case' expression ( ',' expression )* block
default_clause ::= 'default' block
while_statement ::= 'while' expression? block
do_statement ::= 'do' block 'while' expression
for_statement ::= 'for' for_init ';' expression ';' expression block
for_init ::= ( 'var' | 'const' ) <name> ( '=' expression )?
| expression
for_in_statement ::= 'for' ( 'var' | 'const' ) <name> ( ',' <name> )* 'in' expression block
break_statement ::= 'break'
continue_statement ::= 'continue'
return_statement ::= 'return' expression?
multiple_assignment ::= <name> ( ',' <name> )+ '=' expression_list
expression_statement ::= expression
(* ---- Modules ---- *)
import_statement ::= 'import' logical_import ( ',' logical_import )*
| 'import' path_import ( ',' path_import )*
logical_import ::= <name> ( 'as' <name> )?
path_import ::= path ( 'as' <name> )?
from_statement ::= 'from' module_ref 'import' import_item ( ',' import_item )*
module_ref ::= <name> | path
import_item ::= <name> ( 'as' <name> )?
path ::= <string>
| <interpolation> expression ( <interpolation> expression )* <string>
export_statement ::= 'export' ( variable_declaration | function_declaration | class_declaration )
| 'export' '{' <name> ( ',' <name> )* '}'
(* ---- Expressions, from lowest to highest precedence ---- *)
expression ::= assignment | conditional
assignment ::= target assign_op expression (* right-associative *)
target ::= <name>
| postfix '.' <name>
| postfix '[' expression ']'
conditional ::= logical_or ( '?' expression ':' expression )? (* right-associative *)
logical_or ::= logical_and ( 'or' logical_and )*
logical_and ::= equality ( 'and' equality )*
equality ::= class_test ( ( '==' | '!=' ) class_test )*
class_test ::= comparison ( ( 'is' | 'is' 'not' | 'not' 'in' ) comparison )*
comparison ::= bitwise_or ( ( '<' | '<=' | '>' | '>=' | 'in' ) bitwise_or )*
bitwise_or ::= bitwise_xor ( '|' bitwise_xor )*
bitwise_xor ::= bitwise_and ( '^' bitwise_and )*
bitwise_and ::= shift ( '&' shift )*
shift ::= range ( ( '<<' | '>>' ) range )*
range ::= additive ( '..' additive ( '..' expression )? )? (* ranges do not chain *)
additive ::= multiplicative ( ( '+' | '-' ) multiplicative )*
multiplicative ::= power ( ( '*' | '/' | '%' ) power )*
power ::= unary ( '**' unary )* (* left-associative *)
unary ::= ( 'not' | '!' | '-' | '~' ) unary
| postfix
postfix ::= primary ( call | member | subscript )*
call ::= '(' arguments? ')'
member ::= '.' ( <name> | 'new' )
subscript ::= '[' index ']'
index ::= expression
| expression ':'
| expression ':' expression
| expression ':' expression ':' expression
| expression ':' ':' expression
arguments ::= argument ( ',' argument )*
argument ::= expression | '...' expression
primary ::= 'nil' | 'true' | 'false'
| <number>
| string_expression
| <name>
| 'self'
| super_expression
| list_literal
| map_literal
| function_expression
| '(' expression ')'
string_expression ::= <string>
| <interpolation> expression ( <interpolation> expression )* <string>
super_expression ::= 'super' ( call | '.' <name> call? )?
list_literal ::= '[' ( list_item ( ',' list_item )* ','? )? ']'
list_item ::= expression | '...' expression
map_literal ::= '{' ( map_entry ( ',' map_entry )* ','? )? '}'
map_entry ::= <name> '=' expression
| '[' expression ']' '=' expression
function_expression ::= 'function' '(' parameters? ')' block
| '(' parameters? ')' '=>' ( expression | block )