Skip to content

Language Reference

Andrew Elliot edited this page Aug 19, 2023 · 8 revisions

EBNF rule

Some notes:

  1. we use := to denote a definition of a syntax item.
  2. we use { ... } to mean there are 0 or more items.
  3. we use [ ... ] to mean there are 0 or 1 item.
  4. we use ( ... ) to group things together.
  5. we use " ... " to mean literal.
  6. we use ` as another way to write literal.
  7. we use | to denote an alternation.
  8. we use (space) to denote a concatenation.
  9. we use * postfix operator to denote 0 or more items.
  10. we use + postfix operator to denote 1 or more items.
  11. we use ? postfix operator to denote 0 or 1 item.
  12. we use normal identifier to denote a definition of syntax.
  13. we use < ... > to mean a special groups of syntax item. It is usually clear by context.
  14. we use a ... b to mean a sequence. e.g. "1" ... "5" to mean ("1"|"2"|"3"|"4"|"5").
  15. we use // to mean a comment.
  16. we use # prefix operator to denote an external defined syntax item. This usually means you need to find definition of pattern, in case you encounter a #pattern, in other place.

NOTE NOTE: Except note 12, ... in notes means meta syntax item. e.g. from [ ... ] and |, we can have ["a"|"b"] to mean optional literal a or b in language syntax.

NOTE NOTE: Operators *, + and ? are all unary operator and attached to its preceding item.

Syntax

Expression definition

// common identifier
name := ("_"|ASCII_alphabet) {"_"|ASCII_alphabet|digit}

literal := string | number | record | selector | variant | tuple

string := `"` <Unicode>* `"`

number := integer | floating
integer := digit+
floating := integer ["." integer]

record := "{" record_field {"," record_field} "}"
record_field := name "=" expression

tuple := "(" expression {"," expression} ")"

// these two acts like a function. see info in Intuition section.
variant := "`" name
selector := "." name

expression := name
            | literal
            | expression_group
            | expression_type
            | expression expression_annotation
            | expression_let
            | expression_lambda

expression_group := "(" expression ")

expression_type := "@" (#type_literal | #type_name | #type_quantifier | "(" #type ")")
expression_annotation := ":" #type

expression_let := "let" #pattern "=" expression "in" expression

expression_lambda := equation_line | equation_group
equation_line := "\" [name+ ";;"] #pattern {"," #pattern} "=" expression
equation_group := "[" [name+ ";;"] equation_branch {"|" equation_branch} "]"
equation_branch := pattern_group "=" expression {"|" pattern_group "=" expression  }
pattern_group := pattern_sequel {"|" pattern_sequel}
pattern_sequel := #pattern {"," #pattern}

// common syntax item
ASCII_alphabet := ("a" ... "z")
                | ("A" ... "Z")
digit := "0" ... "9"

<Unicode> is Unicode sequence. e.g. "中文" or emoji "😊" or latin "Ʀ"

Intuition

Expression

  • name: name1, _name2, name_1_name3, ___name4
  • string and number literal: "this is a string", 32, 23.2

    there is no escape token in string literal, we may add it later

  • record: {a = _a_name, b = 32}, { job = "student", age = 32 }
  • one line lambda: \ ?a = a, \ 32 = "it is 32", \ a;; (?a : a) = a , \ ;; ?x, ?y = x + y

    operator like + has its own rule and acts like a syntax sugar. we introduce it in another section.

  • multi line lambda:
    • [ ?f, ?a = f a ]
    • [ 0 = "it is zero" | ?a = "it is number: " <> toString a ]
    •  [ 0 | 1 | 2 | 3 = "it is from 0 to 3"
       | _ = "number above 3"
       ]
      
  • local let definition:
    • let ?a = 32 in a + 6
      
    • let ?name = "Polo";;
          ?age = 32 : int;;
          ?compute = [ ( ?x, ?y : int ), ?inc = (x, y + inc) ]
      in { name = name, age = age, count = compute
      
Clone this wiki locally