flisp/spec.md
2025-03-08 11:14:18 +01:00

223 lines
6.3 KiB
Markdown
Executable file
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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