Prequel
primitive recursive driven programming


Prequel Grammar

prequel-program =
  [ "@" module-name ":" newline ]
  module
  {
  "@" module-name ":" newline
  module
  }

module =
  instruction newline
  instructions

instructions =
  {
  instruction newline
  }

instruction
  = assignment
  | assignment-random
  | unassign
  | push
  | queue
  | pop
  | unqueue
  | if
  | repeat
  | procedure-call
  | print

assignment
  = mvar { index } "=" expression

assignment-random
  = mvar { index } "~=" "random"
  | mvar { index } "~=" expression

unassign
  = mvar ".unassign"

push
  = mvar { index } ".push" "(" expression [ "," expression ] ")"

queue
  = mvar { index } ".queue" "(" expression ")"

pop
  = [ mvar { index } "=" ]
    mvar { index } ".pop" "(" [ expression ] ")"

unqueue
  = [ mvar { index } "=" ]
    mvar { index } ".unqueue" "(" ")"

if =
  "if" expression newline
   instructions
  {
  "elif" expression newline
   instructions
  }
  [
  "else" newline
   instructions
  ]
  "endif"

repeat =
  "repeat" ivar newline
   instructions (* including "break" or "continue" *)
  "endrep"

procedure-call = procedure-name "(" { arg "," } ")"

print = "print" "(" print-arg { "," print-arg } ")"

index = "[" expression "]"

expression
  = "(" expression ")"
  | "not" expression
  | expression "and" expression
  | expression "or" expression
  | expression is-or-isnot expression-type
  | expression rel-op expression
  | unary-op expression
  | expression add-op expression
  | expression mul-op expression
  | var { index }
  | var { index } ".length"
  | var { index } ".indexof" "(" expression [ "," expression ] ")"
  | "[" { expression "," } "]" { index }
  | number
  | math-factor

number
  = decimal
  | binary
  | hexadecimal

math-factor
  = "math.abs" "(" expression ")"
  | "math.acos" "(" expression ")"
  | "math.asin" "(" expression ")"
  | "math.atan" "(" expression ")"
  | "math.atan2" "(" expression "," expression ")"
  | "math.ceil" "(" expression ")"
  | "math.cos" "(" expression ")"
  | "math.e"
  | "math.exp" "(" expression ")"
  | "math.exp2" "(" expression ")"
  | "math.floor" "(" expression ")"
  | "math.log" "(" expression ")"
  | "math.log2" "(" expression ")"
  | "math.max" "(" expression "," expression ")"
  | "math.min" "(" expression "," expression ")"
  | "math.pi"
  | "math.pow" "(" expression "," expression ")"
  | "math.round" "(" expression ")"
  | "math.sign" "(" expression ")"
  | "math.sin" "(" expression ")"
  | "math.sqrt" "(" expression ")"
  | "math.tan" "(" expression ")"

procedure-name
  = evar
  | "call"
  | "return"

arg
  = expression
  | module-name-ref
  | mvar-ref
  | string

print-arg
  = expression
  | string

var
  = mvar
  | evar

mvar
  = ivar
  | csvar

ivar = ivar-start-char { ivar-char }

ivar-start-char
  = "_"
  | alpha

ivar-char
  = "_"
  | alphanum

csvar = "!" ivar [ "@" module-name ]

evar = ivar "." ivar { "." ivar }

module-name-ref = "@" module-name

mvar-ref = "&" mvar { index }

is-or-isnot
  = "is"
  | "isnot"

expression-type
  = "number"
  | "list"
  | "empty"
  | "procedure"
  | "undefined"

rel-op
  = "=="
  | "<>"
  | "<"
  | "<="
  | ">"
  | ">="

unary-op
  = "+"
  | "-"
  | "~" (* bitwise not *)

add-op
  = "+"
  | "-"
  | "|" (* bitwise or *)
  | "^" (* bitwise xor *)

mul-op
  = "*"
  | "/"
  | "%"  (* modulo *)
  | "//" (* integer division *)
  | "&"  (* bitwise and *)
  | "<<" (* bitwise shift left *)
  | ">>" (* bitwise shift right *)

module-name = module-name-start-char { module-name-char }

module-name-start-char
  = "_"
  | alpha

module-name-char
  = "_"
  | alphanum

alphanum
  = alpha
  | d-digit

decimal = d-digit { d-digit } [ "." d-digit { d-digit } ]

binary = "0b" b-digit { b-digit } [ "." b-digit { b-digit } ]

hexadecimal = "0x" h-digit { h-digit } [ "." h-digit { h-digit } ]

string = """ { string-char } """

alpha
  = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i"
  | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r"
  | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
  | "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I"
  | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R"
  | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"

d-digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"

b-digit = "0" | "1"

h-digit
  = d-digit
  | "a" | "b" | "c" | "d" | "e" | "f"
  | "A" | "B" | "C" | "D" | "E" | "F"

string-char
  = non-backslash-char (* ascii code between 32 and 126, except "\" *)
  | "\" printable-char (* ascii code between 32 and 126 *)

newline = line-feed-char (* ascii code 10 *)

Syntactic Sugar

sugar-incr
    mvar { index } "++"
  = mvar { index } "+=" "1"

sugar-decr
    mvar { index } "--"
  = mvar { index } "-=" "1"

sugar-toggle
    mvar { index } "~~"
  = mvar { index } "="
    "~" mvar { index }

sugar-plus-assign
    mvar { index } "+=" expression
  = mvar { index } "="
    mvar { index } "+" expression

sugar-minus-assign
    mvar { index } "-=" expression
  = mvar { index } "="
    mvar { index } "-" expression

sugar-mul-assign
    mvar { index } "*=" expression
  = mvar { index } "="
    mvar { index } "*" expression

sugar-div-assign
    mvar { index } "/=" expression
  = mvar { index } "="
    mvar { index } "/" expression

sugar-mod-assign
    mvar { index } "%=" expression
  = mvar { index } "="
    mvar { index } "%" expression

sugar-and-assign
    mvar { index } "&=" expression
  = mvar { index } "="
    mvar { index } "&" expression

sugar-or-assign
    mvar { index } "|=" expression
  = mvar { index } "="
    mvar { index } "|" expression

sugar-xor-assign
    mvar { index } "^=" expression
  = mvar { index } "="
    mvar { index } "^" expression

sugar-shift-left-assign
    mvar { index } "<<=" expression
  = mvar { index } "="
    mvar { index } "<<" expression

sugar-shift-right-assign
    mvar { index } ">>=" expression
  = mvar { index } "="
    mvar { index } ">>" expression

sugar-procedure-assign
    { mvar { index } "," }
    "=" procedure-name "(" { arg "," } ")"
  = procedure-name "(" { mvar-ref "," } { arg "," } ")"

sugar-last-comma-par
    "(" { element "," } ")"
  = "(" [ element { "," element } ] ")"

sugar-last-comma-sqr
    "[" { element "," } "]"
  = "[" [ element { "," element } ] "]"

sugar-last-comma-proc
    "," "=" procedure-name "("
  = "=" procedure-name "("