Skip to content

EK Formal Grammar

Lindon Aliu edited this page Jan 29, 2024 · 1 revision

The full formal grammar of the EK Programming Language can be found here. We use a flavour of BNF that is inspired by the one Swift uses.

Definition

Nonterminal symbols are in italic, terminal ones are enclosed in double quotes or described in English in bold. We use an equals symbol for definitions.

A question mark (?) after a symbol means it is optional, an asterisk (*) means it is repeated 0 or more times, and a plus sign (+) means it is repeated 1 or more times.

Alternatives use pipes (|) and composition uses juxtaposition. Note that there is implicit whitespace allowed in juxtaposition.

Whitespace

whitespace = whitespace-item+

whitespace-item = line-break | space | comment

line-break = Line Feed (LF, U+000A) | Carriage Return (CR, U+000D)

space = Any Unicode character in the Space general category

comment = "//" comment-text line-break

comment-text = Any character except U+000A or U+000D *

Identifiers

identifier = text-identifier | identifier-operator | "[" | "]"

text-identifier = identifier-head identifier-char+

identifier-head = Any Unicode character in the UppercaseLetter, LowercaseLetter, TitlecaseLetter, ModifierLetter or OtherLetter unicode general category

identifier-char = identifier-head | Digits 0 through 9 | "'"

identifier-operator = identifier-operator-char+

identifier-operator-char = "/" | "-" | "+" | "*" | "!" | "?" | "%" | "<" | ">" | "&" | "|" | "^" | "~" | "=" | "." | "$"

Literals

literal = float-literal | int-literal | string-literal

int-literal = decimal-literal

decimal-literal = decimal-digit+

decimal-digit = Digits 0 through 9

float-literal = decimal-digit+ "." decimal-digit+

quote = The double quote character (")

string-literal = quote quoted-text* quote

quoted-text = escape-sequence | Any Unicode character except double quotes and backslash

escape-sequence = "\" escape-char

escape-char = "0" | "\" | "t" | "n" | "r" | quote

Definitions

definition = atom-definition | type-definition | struct-definition | function-definition | import-definition

atom-definition = "atom" text-identifier

type-definition = "type" text-identifier "=" type

struct-definition = "struct" text-identifier "{" struct-elems? "}"

struct-elems = struct-elem | struct-elem "," struct-elems?

struct-elem = text-identifier typed

import-definition = "import" text-identifier

Functions

function-definition = "fn" function-pattern "=" expression | "extern" "fn" function-pattern

function-pattern = function-pattern-item+ typed? precedence-clause?

function-pattern-item = identifier | placeholder | argument-pattern

placeholder = "_"

argument-pattern = "(" argument ")"

argument = "lazy"? text-identifier typed?

precedence-clause = "precedence" precedence

precedence = int-literal

Types

typed = ":" type

type = paren-type | text-identifier | int-range | union-type | fn-type

paren-type = "(" type ")"

union-type = type "|" type

fn-type = type "->" type

int-range = int-literal | "[" int-literal? ".." int-literal? "]"

Expressions

expression = primary-expr | call | struct-constructor | lambda | type-check | arr-lit

struct-expr = expression | expression "," struct-expr

struct-constructor = text-identifier "{" struct-expr? "}"

primary-expr = paren-expr | literal

paren-expr = "(" expression ")"

arr-lit = "[" struct-expr? "]"

call = call-item+

call-item = identifier | expression | placeholder

lambda = "" lambda-args "=" expression

lambda-args = identifier+

type-check = expression "is" type

Clone this wiki locally