Skip to content

Instantly share code, notes, and snippets.

@Chubek
Last active April 19, 2024 06:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Chubek/bd54df78fe1f71f46cb262ba990a209b to your computer and use it in GitHub Desktop.
Save Chubek/bd54df78fe1f71f46cb262ba990a209b to your computer and use it in GitHub Desktop.
Xeph Grammar -> Draft 1

Xeph.ebnf contains the first draft of the Xeph non-pure functional language. A prototype of Xeph, compiled targeting GNU C, is at works.

EDIT: It is currently the second revision. I have added meta programming, and a lot of other imporvements.

However, the definition is weak, and it needs your feedback to be refined.

The ADTs in Xeph are taken from Zephyr ASDL (which there are many implementations of, like mine) and the rest are 'original', that is, taken from ML, Haskell, and Scheme.

This is not the final version of the grammar. The implementation at the moment is focusing on the backend and semantics. The grammar of a functional language is its most important aspect, and it can't be taken lightly.

Please opine on it, and tell me what you think. You can reach me via:

chubakbidpaa [at] riseup [dot] net

.chubak on Discord

Remember this is just the first draft. Your input is appreciated.

PS: Reading EBNF ->

  • { and } mark a sequence, for example, "a" { "b" } means abbbbbbbbbb....
  • [ and ] mark optional rulese, for example, [ 'a' ] could mean a or an empty language (sigma).
  • ( and ) mark a group.
  • Text between two ? is free description in English.
  • Terminals are enclosed in quotes.
  • Non-terminals are assigned by ::=.
  • Different cases are altered by |.

Thanks.

# EBNF Grammar for Xeph, a non-pure functional language based on Zephyr ASDL
# Github.com/Chubek/Xeph
# History:
# Apr 19 - Revision Draft 1
# Apr 19 - Revision Draft 2
pattern ::= [ con-id ] factor "begin" expr-list "end"
;
factor ::= name-id
| symbol-literal
| long-name-id
| numeric-literal
| text-literal
| list-literal
| function-lambda
| tacit-arg
| '(' expr ')'
;
name-id ::= lowercase { letter | digit | '_' | "'" | '?' }
;
con-id ::= uppercase { letter | digit }
;
any-character ::= ? any character that the native system supports ?
;
operator-sym ::= ? up to 4 punctuation marks, except [?:;,'"] ?
;
uppercase ::= 'A' | 'B' | 'C' | ... | 'Z'
;
lowercase ::= 'a' | 'b' | 'c' | ... | 'z'
;
letter ::= uppercase | lowercase
;
digit ::= '0' | '1' | '2' | ... | '9'
;
long-name-id ::= name-id { '.' name-id | ".[" expr ']' }
;
numeric-literal ::= integer
| float
| scientific
| complex
;
integer ::= digit { digit }
;
float ::= digit { digit } '.' { digit }
;
scientific ::= ( digit { digit } '.' { digit } | integer ) 'e' [ '+' | '-' ] digit { digit }
;
complex ::= ( integer | float ) 'i'
;
tacit-arg ::= '$' integer
;
text-literal ::= character-literal
| string-literal
| unescaped-string-literal
| regex-literal
;
character-literal ::= "#\" ( any-character | name-id )
;
string-literal ::= [ "u8" ] '"' { any-character } '"'
;
unescaped-literal ::= [ "u8" ] "'" { any-character } "'"
;
regex-literal ::= '/' { any-character - '/' } '/'
;
symbol-literal ::= ':' name-id
;
symbolic-id ::= name-id
| symbol-literal
;
list-literal ::= basic-list | associative-list
;
basic-list ::= '[' [ expr { ';' expr } ] ']'
;
associative-list ::= '{' [ symbolic-id ':' expr { ';' symbolic-id ':' expr } ] '}'
;
function-lambda ::= "fn" [ name-id { ',' name-id } ] "begin" expr-list "end"
;
mk-exception ::= "exception" symbolic-id [ string-literal ] ';'
;
mk-infix ::= ( "infix" | "infixr" ) operator-sym
;
mk-postfix ::= "postfix" operator-sym
;
mk-prefix ::= "prefix" operator-sym
;
force-prefix ::= "<-" '(' operator-sym ')'
;
prefix-expr ::= ( force-prefix | operator-sym ) factor
;
postfix-expr ::= factor operator-sym
;
unary-expr ::= prefix-expr | postfix-expr
;
binary-expr ::= expr operator-sym expr
;
op-expr ::= unary-expr | binary-expr
;
concat-expr ::= op-expr { ( "<|" | "|>" ) op-expr } ';'
;
cond-expr ::= "if" expr "begin" expr-list "end"
;
loop-expr ::= "while" expr "begin" expr-list "end"
;
match-expr ::= "match" expr "with" "begin" alt-expr "end"
alt-expr ::= pattern { '|' pattern }
;
call-expr ::= name-id { expr }
;
bind-expr ::= "let" name-id "in" "begin" expr-list "end"
;
function-expr ::= "fun" "begin" alt-expr "end"
;
local-expr ::= "local" expr "in" "begin" exp-list "end"
;
where-expr ::= "begin" expr-list "end" "where" expr
;
try-except-expr ::= "try" "begin" expr-list "end" "except" [ pattern ] "begin" expr-list "end"
;
failwith-expr ::= "failwith" name-id
;
runtime-eval-expr ::= "eval" concat-expr
;
compiletime-eval-expr ::= "eval!" concat-expr
;
eval-expr ::= runtime-eval-expr
| compiletime-eval-expr
;
import-expr ::= "import" name-id [ "as" name-id ] { ',' name-id [ "as" name-id ] } [ "from" string-literal ]
;
export-expr ::= "export" name-id [ "as" name-id ] { ',' name-id [ "as" name-id ] }
;
module-expr ::= "module" name-id "begin" top-level "end"
;
expr ::= unary-expr
| binary-expr
| alt-expr
| call-expr
| bind-expr
| function-expr
| loop-expr
| cond-expr
| match-expr
| local-expr
| where-expr
| concat-expr
| try-except-expr
| failwith-expr
| eval-expr
| import-expr
| export-expr
| module-expr
;
expr-list ::= expr { { "and" | "then" | "also" } expr }
;
builtin-type-int ::= "int" | "uint"
| "int8" | "uint8"
| "int16" | "uint16"
| "int32" | "uint32"
| "int64" | "uint64"
| "size" | "usize"
| "byte" | "ubyte"
;
builtin-type-float ::= "float" | "double"
;
builtin-type-txt ::= "char" | "uchar" | "string"
;
builtin-type-id ::= "symbol" | "exn"
;
builtin-type-coll ::= "map" | "list" | "array"
;
builtin-type ::= builtin-type-int
| builtin-type-float
| builtin-type-txt
| builtin-type-coll
;
type-id ::= lower { lower | '_' }
;
type-name ::= type-id
| builtin-type
;
type-name-ref ::= type-name
| '[' type-name ']'
;
field-item ::= type-name-ref [ '*' | '?' ] name-id
;
field ::= '(' field-item { ',' field-item } ')'
;
variant ::= con-id [ field ]
;
sum-type ::= variant { '|' variant }
;
product-type ::= field
;
adt-body ::= sum-type
| product-type
;
curry-sig ::= type-name-ref { "->" type-name-ref }
;
subscribes ::= ':' | ":>" sig-ref [ where-clause ]
;
where-clause ::= "where" clause-binding { ',' clause-binding }
;
clause-binding ::= name-id '=' name-id
| type-name '=' type-name-ref
;
type-decl ::= "type" type-name ';'
;
value-decl ::= "val" name-id ':' curry-sig ';'
;
structure-decl ::= "struct" con-id [ subscribes ] ';'
;
declarations ::= type-decl
| value-decl
| structure-decl
;
type-defn ::= "type" type-name "::=" adt-body
;
value-defn ::= "val" name-id { factor } [ ':' curry-sig ] "::=" "begin" expr-list "end"
;
structure-defn-func ::= "struct" con-id "::=" cond-id '(' con-id ')' where-clause
;
structure-defn-mod ::= "struct" con-id [ subscribes ( con-id | sig-defn-inline ) ] "begin" { definitions } "end"
;
structure-defn-inline ::= "struct" { inline-definitions } "end"
;
signature-defn-inline ::= "sig" { inline-declarations } "end"
;
signature-defn-mod ::= "sig" con-id "begin" { declarations } "end"
;
definitions ::= struct-defn-mod
| struct-defn-inline
| sig-defn-mod
| sig-defn-func
| sig-defn-inline
;
inline-declarations ::= ? applying inline rules to 'declarations' ?
;
inline-definitions ::= ? applying inline rules to 'definitions' ?
;
top-level-non-meta ::= { definitions | declarations }
;
syntax-chunk-literal ::= ? a chunk of Xeph syntax, enclosed in "'''" or '`' ?
;
syntax-chunk ::= ? a syntax chunk, with optional string-only infix operators ?
;
meta-tacit ::= '#' integer
;
meta-quote ::= ( "quote'" | 'quote"' ) syntax-chunk
;
meta-expr ::= expr | meta-quote | meta-tacit
;
meta-expr-list ::= meta-expr { ';' meta-expr }
;
meta-id ::= letter { letter | digit | '_' }
;
runtime-macro ::= "macro" meta-id { meta-id } "::=" "begin" meta-expr-list "end"
;
compiletime-macro ::= "macro!" meta-id { meta-id } "::=" "begin" meta-expr-list "end"
;
runtime-alias ::= "alias" meta-id "begin" meta-expr-list "end"
;
compiletime-alias ::= "alias!" meta-id "begin" meta-expr-list "end"
;
macro ::= runtime-macro | compiletime-macro
;
alias ::= runtime-alias | compiletime-alias
;
top-level-meta ::= { macro | alias }
;
top-level ::= [ attrs ] { top-level-meta | top-level-non-meta | top-level-ffi } [ "fin." ]
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment