223 lines
6.3 KiB
Markdown
Executable file
223 lines
6.3 KiB
Markdown
Executable file
# fLisp
|
||
|
||
In this document :
|
||
- `<...>` :
|
||
Mandatory argument
|
||
- `[...]` :
|
||
Optional argument
|
||
- `|` :
|
||
Or
|
||
|
||
- Calls
|
||
`(<func> [arg0 ... argN])`
|
||
Calls func with optional args arg0 to argN
|
||
- Assignements
|
||
`(<var> <value>)`
|
||
Will assign value to var. Value may be any valid expression
|
||
Vectors and strings :
|
||
- `(<vec> <pos>)` will return the value at position pos of vector vec.
|
||
- `(<vec> <pos> <value>)` will assign value to position pos of vector vec
|
||
- `(<string> <pos>)` will return a one length string, the character at pos
|
||
of string
|
||
- `(<string> <pos> <value>)` will assign the first char of string value to
|
||
position pos of the string
|
||
- `(*<vec|string> <value>)` will replace the contents of vec/string with a
|
||
shallow copy of value
|
||
- `(*<vec|string> *<value>)` Same as the previous, but deepcopies value
|
||
- Literals:
|
||
Literals are of the following form:
|
||
- `1234`: int literal
|
||
- `12.34`: float literal
|
||
- `"abcd"`: string literal
|
||
- `(1,2,3,4)`: vector literal. All values must be of the same type
|
||
Null and fix literals do not exist. "Fix" type constants may exist by
|
||
assigning to a fix typed variable, such as `(let:fix x 0.5)`, where x will
|
||
be of value 0.5 in fixed point
|
||
- Comments are indicated by `#`. The whole rest of the line is ignored
|
||
- Compiled to bytecode
|
||
|
||
## Core types
|
||
|
||
- `null`:
|
||
Represents a null value - always evaluates to false
|
||
- `int`:
|
||
32 bit signed integer, evaluates to false if zero and true otherwise
|
||
- `fix`:
|
||
16:16 bit fixed point signed integer, same evaluation rules as ints
|
||
- `float`:
|
||
32bit IEEE floating point value, same evaluation as ints (within epsilon)
|
||
- `str`:
|
||
ASCII character string - always evaluates to false
|
||
- `fn`:
|
||
Function, function "variables" are inherently of type fn - handle with care !
|
||
- `vec`:
|
||
Vectors of any type, the syntax is `:vec:<type>`
|
||
|
||
## Core functions
|
||
|
||
- `(var[:type] <name> [size])`:
|
||
Declares a global variable of optional type type and name name
|
||
if type is of format `:vec:<type>`, the variable will be a vector
|
||
of type type, and optional size size (otherwise size 0)
|
||
(if type isn't specified it is inferred)
|
||
|
||
- `(let[:type] <name> [size])`:
|
||
Same as var, but variable is of local scope (recommended)
|
||
|
||
- `(if <cond> [expressions])`:
|
||
If cond evaluates to true, will execute optional expressions
|
||
|
||
- `(else [expressions])`:
|
||
Must follow a if, will execute if the if's cond evaluates to false
|
||
|
||
- `(while <cond> [expressions])`:
|
||
while cond evalutates to true, will execute optional expressions
|
||
|
||
- `(fn (<name>[:type] [arg0[:type] ... argN[:type]]) [expressions])` :
|
||
Declares a function of name name, optional return type type,
|
||
optional args arg0-argN with optional types (recommended to explicit them),
|
||
that executes expressions. There should at least be one expression.
|
||
The function will return the value of the last expression
|
||
Passed vectors and strings are shallow copied
|
||
|
||
- `(import <lib0> [... libN])` :
|
||
Import the functions and variables from lib0-libN
|
||
|
||
For the following numerical functions, values must be scalars (except + and =,
|
||
where they may be strings), and of the same type
|
||
- `(+ <a> <b>)`:
|
||
Returns a+b, if they are both strings they will be concatenated
|
||
|
||
- `(- <a> <b>)`:
|
||
Returns a-b
|
||
|
||
- `(* <a> <b>)`:
|
||
Returns a×b
|
||
|
||
- `(/ <a> <b>)`:
|
||
Returns a/b
|
||
|
||
- `(% <a> <b>)`:
|
||
Returns a%b
|
||
|
||
- `(< <a> <b>)`:
|
||
Returns 1 if a < b, else 0
|
||
|
||
- ̀`(<= <a> <b>)`:
|
||
Returns 1 if a <= b, else 0
|
||
|
||
- `(= <a> <b>)̀̀`:
|
||
Returns 1 if a == b, else 0
|
||
|
||
- `(>= <a> <b>)`:
|
||
Returns 1 if a >= b, else 0
|
||
|
||
- `(> <a> <b>)`:
|
||
Returns 1 if a > b, else 0
|
||
|
||
- `(! <a>)`:
|
||
If a evaluates to false, returns true, and false otherwise
|
||
|
||
- `(and <a> <b>)`:
|
||
Logical and on a and b
|
||
|
||
- `(or <a> <b>)`:
|
||
Logical or on a and b
|
||
|
||
- `(is<:type> <arg>)`:
|
||
Returns 1 if arg is of type type
|
||
|
||
- `(<:type> <arg>)`:
|
||
Will attempt to convert arg to type, returns it on success, and returns
|
||
null on failure.
|
||
|
||
- `(len <vec>)` :
|
||
Returns the length of vector vec.
|
||
|
||
- `(push <vec> <arg>)`:
|
||
Adds item arg to the end of vec, increasing the size of vec
|
||
|
||
- `(pop <vec> <arg>)`:
|
||
Deletes item at pos arg from vec, and returns it
|
||
|
||
## utils functions (`(import utils)`)
|
||
|
||
- `(rand-seed <arg>)` :
|
||
Sets the seed of the random number generator of random to integer arg
|
||
By default is seeded with a random enough value, gotten at runtime
|
||
|
||
- `(random)` :
|
||
Returns a random integer between -2³¹ and +2³¹-1
|
||
|
||
- `(time)` :
|
||
Returns the current number of seconds since 2010, as an integer
|
||
|
||
## console functions (`(import console)`)
|
||
|
||
- `(input)`:
|
||
Will try to get input from the user, returns it as a string
|
||
|
||
- `(write <var>)`:
|
||
Will try to convert var to a string then print it to the console
|
||
|
||
- `(newline)`:
|
||
Will print a newline to the console (newline characters aren't escaped with
|
||
write)
|
||
|
||
## gint functions
|
||
|
||
TODO
|
||
|
||
# Bytecode
|
||
|
||
- 8 byte Value :
|
||
2 bytes tag, 6 bytes value itself
|
||
- 4 byte bytecode ops:
|
||
1 byte op, 3 byte args (named 1-3)
|
||
|
||
## Bytecode types
|
||
|
||
- `T_Null̀̀` -> null
|
||
- `T_Int` -> int
|
||
- `T_Fix` -> fix
|
||
- `T_Float` -> float
|
||
- `T_Str` -> string :
|
||
- If shorter than 4 chars (+ `\0`), is a "compact string"
|
||
- Otherwise, gets converted to a vector, inherently of chars
|
||
- `T_Fn` -> fn / function
|
||
|
||
## Bytecode operations :
|
||
|
||
if just 1, 2 or 3, means the value at pos 1,2,3 of the stack
|
||
if #1,#2,#3, the immediate value of 1,2,3
|
||
if 1:2 / 1:2:3, means stitching 1,2,3 together as a 2 or 3 byte value
|
||
- `add` : 1+2 -> stack
|
||
- `sub` : 1-2 -> stack
|
||
- `mul` : 1×2 -> stack
|
||
- `div` : 1/2 -> stack
|
||
- `mod` : 1%2 -> stack
|
||
- `call` : calls 1
|
||
- `ret` : returns to caller
|
||
- `mov` : 1 -> 2
|
||
- `copy` : deepcopy of 1 -> 2
|
||
- `get` : value at pos 2 of vector 1 -> stack
|
||
- `set` : set value at pos 2 of vector 1 to 3
|
||
- `gt` : 1>2 -> stack
|
||
- `ge` : 1>=2 -> stack
|
||
- `eq` : 1==2 -> stack
|
||
- `jmp` : Jumps to bytecode at relative 2:3
|
||
- `brt` : Jumps to bytecode at relative 2:3 if 1
|
||
- `cast` : Casts 1 to the type of 2 -> 1
|
||
- `fcast` : Casts 1 to the type of 2:3 -> 1
|
||
- `init` : value of type 2:3 and size 1 -> stack
|
||
- `fcall` : calls function of hash 1:2:3
|
||
- `pop` : pop value 1
|
||
- `popl` : pops the last #2 values on stack, starting from #1
|
||
- `cst0` : 2:3 -> LSW of 3
|
||
- `cst1` : 2:3 -> MSW of 3
|
||
- `not` : !1 -> stack
|
||
- `and` : 1 && 2 -> stack
|
||
- `or` : 1 || 2 -> stack
|
||
- `vpop` : removes element at pos 2 of vec 1 -> stack
|
||
- `vpsh` : pushes back 2 on vector 1
|
||
|