7.4

1 Formal grammar

The DSSL2 language has a number of statement and expression forms, which are described in more depth below. Here they are summarized in Extended Backus-Naur Form.

Non-terminal symbols are written in ⟨italic_with_pointies⟩, whereas terminal symbols are in colored typewriter. Conventions include:

The grammar begins by saying that a program is a sequence of zero or more statements, where a statement is either a simple statement followed by a newline, or a compound statement.

program

 

=

 

{ statement }*

 

 

statement

 

=

 

simple NEWLINE

 

|

 

compound

 

 

expr

 

=

 

number

 

|

 

string

 

|

 

True

 

|

 

False

 

|

 

None

 

|

 

lvalue

 

|

 

expr if expr else expr

 

|

 

expr ( { expr },* )

 

|

 

lambda { name },* : simple

 

|

 

λ { name },* : simple

 

|

 

struct_name { { name : expr },* }

 

|

 

[ { expr },* ]

 

|

 

[ expr ; expr ]

 

|

 

[ expr for [ name , ] name in expr [ if expr ] ]

 

|

 

expr binop expr

 

|

 

unop expr

 

 

simple

 

=

 

assert expr opt_timeout

 

|

 

assert_error expr [ , expr ] opt_timeout

 

|

 

break

 

|

 

continue

 

|

 

lvalue = expr

 

|

 

expr

 

|

 

import mod_spec

 

|

 

let name opt_ctc [ = expr ]

 

|

 

pass

 

|

 

return [ expr ]

 

|

 

simple ; simple

 

 

lvalue

 

=

 

name

 

|

 

expr . name

 

|

 

expr [ expr ]

 

 

compound

 

=

 

class name opt_cvars opt_implements : class_block

 

|

 

def name opt_cvars ( { name opt_ctc },* ) opt_res_ctc : block

 

|

 

if expr : block { elif expr : block }* [ else : block ]

 

|

 

interface name opt_cvars : interface_block

 

|

 

for [ name , ] name in expr : block

 

|

 

struct name : struct_block

 

|

 

test [ expr ] : block

 

|

 

time [ expr ] : block

 

|

 

while expr : block

 

 

block

 

=

 

simple NEWLINE

 

|

 

NEWLINE INDENT { statement }+ DEDENT

 

 

class_block

 

=

 

NEWLINE INDENT { field_def }* { meth_proto : block }+ DEDENT

 

 

interface_block

 

=

 

pass

 

|

 

NEWLINE INDENT { meth_proto NEWLINE }+ DEDENT

 

 

struct_block

 

=

 

pass

 

|

 

NEWLINE INDENT { field_def }+ DEDENT

 

 

meth_proto

 

=

 

def name opt_cvars ( name { , name opt_ctc }* ) opt_res_ctc

 

 

field_def

 

=

 

let name opt_ctc NEWLINE

 

 

opt_timeout

 

=

 

[ , time < expr ]

 

 

opt_implements

 

=

 

[ ( { name },* ) ]

 

 

opt_ctc

 

=

 

[ : ctc ]

 

 

opt_res_ctc

 

=

 

[ -> ctc ]

 

 

opt_cvars

 

=

 

[ [ { name },* ] ]

 

 

ctc

 

=

 

expr

 

 

mod_spec

 

=

 

mod_name

 

|

 

mod_string

 

 

binops are, from tightest to loosest precedence:

unops are ~, +, -, and not.