mighty

The mighty programming language, compiler and tools (WIP)
Log | Files | Refs

language2.bnf (4217B)



# Mighty language2 sketch grammar

program         ::= { nl | top nl }
nl              ::= NEWLINE { NEWLINE }

top             ::= namespace | use | decl
namespace       ::= "ns" path
use             ::= "use" path
decl            ::= [ "pub" ] ( struct | function | operator )

struct          ::= "struct" Type [ generics ] "::" block(member)
member          ::= field | decl
field           ::= type names
names           ::= name { "," name }

function        ::= { pre nl } signature { where_part } body
pre             ::= "pre" expr
where_part      ::= [ nl ] where
where           ::= "where" constraint      # may mention contextual `result`
signature       ::= type name [ generics ] "(" [ params ] ")"
params          ::= param { "," param }
param           ::= type [ name ]
body            ::= [ nl ] "=" ( expr | nl expr ) | "::" block(stmt)

operator        ::= "op" op [ generics ] "(" params ")" "->" type body

stmt            ::= binding | ret | expr
binding         ::= type name "=" expr
ret             ::= "ret" expr

generics        ::= "[" typevar { "," typevar } "]"
typevar         ::= Type
constraint      ::= expr | type_constraint
type_constraint ::= Type ":" trait { "+" trait }
trait           ::= Type

type            ::= primary_type { type_suffix }
primary_type    ::= path [ type_args ] | "(" types ")"
type_args       ::= "[" type { "," type } "]"
types           ::= type { "," type }
type_suffix     ::= "[]"                    # slice/dynamic array
                  | "[" int_lit "]"         # fixed array
                  | "?"                      # option: T?
                  | "!" type                 # result: T!E

path            ::= name { "." name }

expr            ::= conditional
conditional     ::= pipe [ "if" expr "else" expr ]
pipe            ::= scan { "|" ( map | expr ) }
map             ::= "@" "(" expr ")"        # each: `.` is the current element
scan            ::= [ op "\\" ] reduce       # +\xs, *\xs
reduce          ::= [ op "/" ] logic          # +/xs, */xs, max/xs

logic           ::= compare { ( "and" | "or" ) compare }
compare         ::= range { cmp range }
range           ::= add [ ".." [ add ] ]
add             ::= mul { ( "+" | "-" ) mul }
mul             ::= pow { ( "*" | "/" ) pow }
pow             ::= unary { "^" unary }
unary           ::= [ "-" | "#" ] postfix    # #xs is length/count

postfix         ::= atom { call | selector | "." name }
call            ::= "(" [ args ] ")"
args            ::= expr { "," expr }
selector        ::= "[" [ items ] "]"        # index, gather, mask, or filter expr

atom            ::= literal | path | subject | array | record | "(" expr ")"
subject         ::= "." [ name ]             # current subject/self/element
array           ::= "[" [ items ] "]"
items           ::= expr { "," expr }
record          ::= path "(" [ fields ] ")"
fields          ::= field_value { "," field_value }
field_value     ::= name ":" expr

literal         ::= int_lit | float_lit | string | "true" | "false" | "nil"
op              ::= "+" | "*" | "&" | "|" | "min" | "max" | name
cmp             ::= "==" | "!=" | "<" | "<=" | ">" | ">="

block(x)        ::= INDENT { nl | x nl } DEDENT

# Lexical sketch: name is an identifier, Type is a capitalized identifier.
# Comments run from // to end of line.

# Selector semantics:
# xs[i]          scalar index
# xs[[0, 2]]     gather by int[] indices
# xs[mask]       compress by bool[] mask
# xs[.valid]     filter by expression evaluated per element

# Array literals use commas: [1, 2, 3], [true, false, true].

# Named record literals use Type(field: value): Vec2(x: 1.0, y: 2.0).

# Ranges are half-open. Negative indices are relative to the end.
# xs[0..-1] selects from the first element up to, not including, the last.

# Reductions over empty collections are invalid unless the operator has a
# defined identity. max/ and min/ require non-empty collections.

# Values are passed by copy semantically. An implementation may pass by
# read-only reference when that is observationally identical.

# `.` semantics:
# In methods, `.` is the receiver. In free functions, `.` is the first argument.
# In selectors and @(...), `.` is the current element.