This is the context free grammar for Droid , expressed in Extended Backus–Naur Form (EBNF ).
Quoted strings match the contained literal text, as do words. <x>
matches if the rule of the the corresponding name matches. <x> ::=
defines a non-terminal (rule) to whatever comes after the ::=.
Parenthesis group, pipes denote alternatives, brackets denote an optional sub-rule and curly braces mean that the contained rule must occur zero or more times in succession. Text contained between a pair of question marks are informal sub-rules.
<module> ::= [ ";" ] [ package <lower> { "." <lower> } [ ";" ] ] { using [ <lower> { "." <lower> } "." ] <upper> { "," <upper> } [ ";" ] } { ( <interface> | <enum> | <class> | <object> ) [ ";" ] } <interface> ::= <doc> [ using ] interface <upper> <generic> <implement> <where> do <method-heads> end <enum> ::= <doc> [ using ] enum <upper> <generic> <implement> <where> do <upper> [ <parameters> ] { [ ";" ] <upper> [ <parameters> ] } [ methods <methods> ] end <class> ::= <doc> [ using ] class <upper> <generic> <parameters> <implement> <where> [ do <exp-block> [ methods <methods> ] end ] <object> ::= <doc> [ using ] object <upper> <implement> <where> do <exp-block> [ methods <methods> ] end
<exp> ::= "(" <exp> ")" | <variable> | <literal> | <field> | <binop> | <unop> | <call> | <scope> | <while> | <for> | <if> | <switch> | <var> | <val> | <function> | <lambda> <block> ::= do <exp-block> end <scope> ::= scope <block> <while> ::= while <exp> <block> <for> ::= for <lower> [ ":" <type> ] in <exp> { "," <lower> [ ":" <type> ] in <exp> } [ where <exp> ] <block> <if> ::= if <exp> do <exp-block> { elseif <exp> do <exp-block> } [ else <exp-block> ] end <switch> ::= switch <exp> do <match-block> end <var> ::= var <lower> [ ":" <type> ] "=" <exp> <val> ::= val <lower> [ ":" <type> ] "=" <exp> <lambda> ::= <lambda-head> <block> <lambda-head> ::= fun "(" [ <lower> [ ":" <type> ] { "," <lower> [ ":" <type> ] } ] [ "," ] ")" [ ":" <type> ] <where> <function> ::= <function-head> <block> <function-head> ::= fun <lower> <parameters> ":" <type> <where> <call> ::= <exp> "(" [ <exp> { "," <exp> } ] [ <lower> ":" <exp> { "," <lower> ":" <exp> } ] [ "," ] ")"
<methods> ::= { [ ";" ] <doc> <function> } [ ";" ] <method-heads> ::= { [ ";" ] <doc> <function-head> } [ ";" ] <doc> ::= [ <doc-comment> [ ";" ] ] <literal> ::= <simple-literal> | <container-literal> <container-literal> ::= "[" [ <exp> { "," <exp> } [ "," ] ] "]" <simple-literal> ::= <integer> | <float> | <string> <variable> ::= <lower> | <upper> <field> ::= <exp> "." ( <lower> | <upper> ) <exp-block> ::= [ ";" ] [ <exp> { ";" <exp> } [ ";" ] ] [ throw <exp> [ ";" ] ] <catch> ::= [ catch <match-block> ] <parameters> ::= "(" [ <lower> ":" <type> { "," <lower> ":" <type> } ] [ "," ] ")" <match-block> ::= [ ";" ] { <pattern> <block> [ ";" <matches> ] } [ ";" ] <catch> <pattern> ::= "(" <pattern> ")" | <lower> [ ":" <type> ] | <upper> [ "(" <pattern> { "," <pattern> } [ "," ] ")" ] | "[" [ <pattern> { "," <pattern> } ] [ "," ] "]" [ "@" <lower> ] | <simple-literal> <type> ::= <upper> [ "[" [ <type> { "," <type> } [ "," ] ] "]" ] | "{" <type> { "," <type> } "}" | <lambda-head> | <type> "*" | <type> "?" <where> ::= [ where <type> ":" <type> { "," <type> ":" <type> } [ "," ] ] <implement> ::= [ ":" <type> { "," <type> } ] <generic> ::= [ "[" <upper> { "," <upper> } "]" ]
These definitions are here to help implementing the lexer.
<binop> ::= ? Binary operators (infix): .. @ to in + - * / ^ and or = == != < > <= >= ? <unop> ::= ? Unary operators (prefix): scope not - ? <lower> ::= ? Lower-case identifier [a-z][A-Za-z0-9]* ? <upper> ::= ? Upper-case identifier [A-Z][A-Za-z0-9]* ? <integer> ::= ? C-like base 10 and base 16 integers ? <float> ::= ? C-like double, but there must be at least one digit before the dot ? <string> ::= ? C-like double quoted strings, plus the same just for single quotes ? <line-break> ::= ? Any of \r or \n or \r\n (semicolon inserted in some cases) ? <doc-comment> ::= ? The contents of all the ## comments in a row ? <comment> ::= ? Anything (else) after a # on a line, ignored as whitespace ? <white-space> ::= ? Anything with an ASCII code less than or equal to 32, ignored ?
The lexer should follow the informal definitions and recognize the keywords and tokens found in the above definitions. It should insert a semicolon when reaching the end of a line, if the last token was not {
or [
or (
or an infix or prefix operator. Multiple semicolons in a row will be reduced to one in the output token stream.
See more samples .
## This is a doc-comment that ## spans multiple lines. class Vector2[T](x: T, y: T) where T: Number do val magnitudeSquared = x ^ 2 + y ^ 2 methods fun getMagnitudeSquared(): T do magnitudeSquared end fun getX(): T do x end fun getY(): T do y end fun add(other: Point[T]): Point[T] do val a = x + other.X val b = y + other.Y Point(a, b) end end
There could be conjunctive (must-match-both) and disjunctive (must-match-at-least-one) patterns:
switch x do [x, y] @ _ and l do ... end [0, x] or [x, 0] do ... end end
Instead of creating manual getters and setters, sticking val
in front of a constructor variable could make an implicit getter for it, and var
could make both an implicit getter and setter. User-defined getters and setters would still take precedence:
class Point(val x: Int, var y: Int) # is equivalent to class Point(x: Int, y: Int) do var y = y methods fun getX(): Int do x end fun getY(): Int do y end fun setY(value: Int): Void do y = value end end
There is little need for a setter-only shortcut, since those are very rare, and almost definitely require special behavior anyways.
There could be a shorthand for immutable POD types.
fun getPosition(): (X: Int, Y: Int) do (X: x, Y: y) end
Which would be equivalent to
using class AnonymousClass(val x: Int, val y: Int) ... fun getPosition(): { fun getX(): Int, fun getY(): Int } do AnonymousClass(x: x, y: y) end
Appropriate deconstructors would be nice:
val position = foo.getPosition() val (X: x, Y: y) = position switch position do (X: x, Y: y) do ... end end