Lumia Aya

Home About Gopher

Nezufun Overview


Nezufun is a Lisp-ish impure functional programming language with dynamic typing and eager evaluation. It is a simple, stupid language with very little abstraction that can be described as a “low level functional language”

Nezufun is designed to be compiled and run on a custom purpose VM, but could be compiled to native code or run interactively.

Types of Expressions


The main purpose of Nezufun is to evaluate expressions, so Nezufun programs are lists of expressions to evaluate in order. Since Nezufun is an impure language, some of those expressions can cause side effects when evaluated. Optionally, the results of an evaluated expression can be assigned to a global name which can be referred to later.

Expressions come in a few forms:

  1. Literal values
  2. Builtin operators
  3. Special forms
  4. Function definition
  5. Function application
  6. Names which refer to values

Literals

Literals can be strings, numbers, or booleans. They always evaluate to their own value.

Strings

Strings are encosed in double quotes, and can span multiple lines. The backslash character can be used to insert newlines and the double quote character without ending a string.

"one line string"

"multi
line
string"

"string\nwith \"escape characters\""

Numbers

Numbers are either integers or floating point values. The precision of these is left implementation defined. Floating point values must always contain a decimal point with at least one digit before and after it. Integers and floats can be prefixed with a minus sign ‘-’ without whitespace to indicate a negative number.

Nezufun doesn’t support scientific notation.

Integers:

42
-8

Floats:

42.0
42.9
-8.2

Booleans

There are only two boolean literals: true and false.

Built-In Operators

Special Forms

Special forms are reserved for constructs which are evaluated differently from other operators or functions, and therefore cannot be partially applied. Here are the special forms in Nezufun:

TODO: Specify how are these compiled differently

Function Definition

Function Application

Names

Names are identifiers that are bound to values. Names are either bound in the global space by def, or they are bound locally by fun or let. Whether a name refers to a global value or a local value is determined statically at compile time.

TODO: really nail down what names are valid, since nf should be able to support basically any kind of name

The convention is to use kebab-case, and to use the question mark as a suffix for the names of predicates, and the exclamation mark as a suffix for functions which produce side effects. However, Nezufun does not enforce these rules and any naming convention can be used.

Formal grammar


Nezufun is always encoded in ASCII. The following grammar is given in ABNF form according to RFC 5234, with the modification that the following rules are case sensitive.

;--CHAR TYPES--

;; space is one or more space char
space   = 1*(%x00-0x20 / %x7F)
digit   = %x30-%x39
alpha   = %x41-5A / %x61-7A
;; all parens are allowed to have no space before or after them
rparen  = [space] "(" [space]
lparen  = [space] ")" [space]



;--LITERALS--

; numbers
minus   = "-"
decimal = "."
integer = [minus] 1*digit
float   = [minus] 1*digit decimal 1*digit
number  = integer / float

; strings
quote      = %x22
;; everything except a quote or a backslash
str_char   = %x00-%x21 / %x23-5B / %x5D-7F
esc_code   = "\"" / "\n"
string_lit = quote *(str_char / esc_code) quote

; booleans
bool = "true" / "false"



;--NAMES--

; names can contain letters, "-", "_", "!", "?", and digits, but they must start
; with a letter
name_char = alpha / digit / "-" / "_" / "!" / "?"
name      = alpha *name_char



;--FUNCTION APPLICATION--

app = name rparen [expr *(space expr)] lparen



;--SPECIAL FORMS--

lambda  =  ("fun" / "\") (space name) (space expr)
lambda  =/ ("fun" / "\") lparen (name (space expr)) rparen
let     =  "let" (space name) 2(space expr)
let     =/ "let" lparen (name 2(space expr)) rparen
if      =  "if" 3(space expr)
if      =/ "if" lparen (expr 2(space expr)) rparen
do      =  "do" lparen (expr *(space expr)) rparen
logic   =  "not" (space expr)
logic   =/ "not" lparen [expr] rparen
logic   =/ ("and" / "or") 2(space expr)
logic   =/ ("and" / "or") lparen [expr *(space expr)] rparen
special = lambda / let / if / do / and / or



;--OTHER BUILTINS--

; 1  = 1 argument
; 2  = 2 arguments
; 2v = 2 or more arguments

; arithmetic functions
arith1  =  "ceil" / "floor" / "round" / "trunc" / "sqrt" / "abs" / "sign"
arith1  =/ "sin" / "cos" / "tan" / "asin" / "acos" / "atan"
arith1  =/ "log" / "ln" / "exp"
airth1  =/ "int?" / "float?" / "num?"
arith2  = "%" / "pow" / "gt?" / "lt?" / "gte?" / "lte?"
arith2v = "+" / "-" / "*" / "/" / "min" / "max"

; list functions
list1    = "head" / "tail" / "rev" / "list?" / "nil?"
list2    = "cons" / "app"
list_con = "list" lparen [expr *(space expr)] rparen
nil      = "nil"

; generic operators
gen1 = "size" / "print"
gen2 = "eq?"

builtin1  = arith1 / list1 / gen1
builtin2  = arith2 / list2 / gen2
builtin2v = artith2v

builtin =  (builtin1  1(space expr)) / (builtin1  lparen *1(expr) rparen)
builtin =/ (builtin2  2(space expr)) / (builtin2  lparen *2(expr) rparen)
builtin =/ (builtin2v 2(space expr)) / (builtin2v lparen  *(expr) rparen)
builtin =/ list_con / nil



;--EXPRESSIONS--
expr =  number / string / boolean
expr =/ name
expr =/ app
expr =/ special
expr =/ builtin



;--DEFINITIONS AND PROGRAMS--
definition =  "def" (space name) (space expr)
definition =/ "def" lparen ((space name) (space expr)) rparen

line = expr / definition

program = [space] line *(space line) [space]