Gabriel Pariat
2 years ago
7 changed files with 5324 additions and 32 deletions
@ -1,13 +0,0 @@ |
|||||||
Running suite(s): Memory |
|
||||||
Array |
|
||||||
Table |
|
||||||
Symbol |
|
||||||
String |
|
||||||
Cons |
|
||||||
Environment |
|
||||||
Evaluator |
|
||||||
Lisp |
|
||||||
Reader |
|
||||||
Printer |
|
||||||
100%: Checks: 85, Failures: 0, Errors: 0 |
|
||||||
PASS check_ptlisp (exit status: 0) |
|
@ -1,4 +0,0 @@ |
|||||||
:test-result: PASS |
|
||||||
:global-test-result: PASS |
|
||||||
:recheck: no |
|
||||||
:copy-in-global-log: no |
|
@ -1,14 +0,0 @@ |
|||||||
====================================== |
|
||||||
ptlisp 0.1: tests/test-suite.log |
|
||||||
====================================== |
|
||||||
|
|
||||||
# TOTAL: 1 |
|
||||||
# PASS: 1 |
|
||||||
# SKIP: 0 |
|
||||||
# XFAIL: 0 |
|
||||||
# FAIL: 0 |
|
||||||
# XPASS: 0 |
|
||||||
# ERROR: 0 |
|
||||||
|
|
||||||
.. contents:: :depth: 2 |
|
||||||
|
|
@ -0,0 +1,375 @@ |
|||||||
|
* Types: |
||||||
|
** integer |
||||||
|
** double |
||||||
|
** rational |
||||||
|
** character |
||||||
|
** string |
||||||
|
** cons |
||||||
|
** fn |
||||||
|
** macro |
||||||
|
** array |
||||||
|
** hash-table |
||||||
|
** stream |
||||||
|
* Symbols: |
||||||
|
** nil |
||||||
|
** t |
||||||
|
** NaN |
||||||
|
** undefined |
||||||
|
* Functions: |
||||||
|
** number? |
||||||
|
*** Is the argument a number? |
||||||
|
Takes anything and return T if it's type is an integer, double or rational. |
||||||
|
** integer? |
||||||
|
*** Is the argument an integer? |
||||||
|
Takes anything and return T if it's type is an integer. |
||||||
|
** double? |
||||||
|
*** Is the argument a double floating-point number? |
||||||
|
Takes anything and return T if it's type is a double. |
||||||
|
** rational? |
||||||
|
*** Is the argument a rational number? |
||||||
|
Takes anything and return T if it's type is a rational. |
||||||
|
** NaN? |
||||||
|
*** Is the argument not a number? |
||||||
|
Takes anything and return T if it's type is a double and the value is NaN. |
||||||
|
** undefined? |
||||||
|
*** Is the argument undefined? |
||||||
|
Takes anything and return T if it's pointer is the same as undefined. |
||||||
|
** char? |
||||||
|
*** Is the argument a character? |
||||||
|
Takes anything and return T if it's type is a character. |
||||||
|
** string? |
||||||
|
*** Is the argument a string? |
||||||
|
Takes anything and return T if it's type is a string. |
||||||
|
** cons? |
||||||
|
*** Is the argument a cons pair? |
||||||
|
Takes anything and return T if it's type is a cons. |
||||||
|
** fn? |
||||||
|
*** Is the argument a function? |
||||||
|
Takes anything and return T if it's type is a function. |
||||||
|
** macro? |
||||||
|
*** Is the argument a macro? |
||||||
|
Takes anything and return T if it's type is a macro. |
||||||
|
** array? |
||||||
|
*** Is the argument an array? |
||||||
|
Takes anything and return T if it's type is an array. |
||||||
|
** hash-table? |
||||||
|
*** Is the argument an hash-table? |
||||||
|
Takes anything and return T if it's type is an hash-table. |
||||||
|
** stream? |
||||||
|
*** Is the argument a stream? |
||||||
|
Takes anything and return T if it's type is a stream. |
||||||
|
** double |
||||||
|
*** Convert a number to double floating-point? |
||||||
|
Takes a number and convert it into a double floating-point number. |
||||||
|
** ceil |
||||||
|
*** Round a number upward? |
||||||
|
Takes a number and round it upward. |
||||||
|
** floor |
||||||
|
*** Round a number downward? |
||||||
|
Takes a number and round it downward. |
||||||
|
** round |
||||||
|
*** Round a number |
||||||
|
Takes a number and round it to mathematically closest and if it's in between two |
||||||
|
integers i.e 0.5, round to closest even (divisible by two) integer |
||||||
|
** + |
||||||
|
*** Add n numbers |
||||||
|
Takes integers, rationals and doubles. |
||||||
|
If a number is double return a double. |
||||||
|
Else if a number is rational and the result's denominator is not 1 |
||||||
|
then return a rational. |
||||||
|
Else return an integer. |
||||||
|
**** 0 number => 0 |
||||||
|
**** 1 number => n |
||||||
|
**** > 1 numbers => n0 + n1 + n2 ... |
||||||
|
** - |
||||||
|
*** Substract n numbers |
||||||
|
Takes integers, rationals and doubles. |
||||||
|
If a number is double return a double. |
||||||
|
Else if a number is rational and the result's denominator is not 1 |
||||||
|
then return a rational. |
||||||
|
Else return an integer. |
||||||
|
**** 0 number => Error |
||||||
|
**** 1 number => 0 - n |
||||||
|
**** > 1 numbers => n0 - n1 - n2 ... |
||||||
|
** * |
||||||
|
*** Multiply n numbers |
||||||
|
Takes integers, rationals and doubles. |
||||||
|
If a number is double return a double. |
||||||
|
Else if a number is rational and the result's denominator is not 1 |
||||||
|
then return a rational. |
||||||
|
Else return an integer. |
||||||
|
**** 0 number => 1 |
||||||
|
**** 1 number => n |
||||||
|
**** > 1 numbers => n0 * n1 * n2 ... |
||||||
|
** / |
||||||
|
*** Divide n numbers |
||||||
|
Takes integers, rationals and doubles. |
||||||
|
If a number is double return a double. |
||||||
|
Else if a number is rational and the result's denominator is not 1 |
||||||
|
then return a rational. |
||||||
|
Else return an integer. |
||||||
|
**** 0 number => Error |
||||||
|
**** 1 number => 1 / n |
||||||
|
**** > 1 numbers => n0 / n1 / n2 ... |
||||||
|
** ** |
||||||
|
*** Power 2 numbers |
||||||
|
Takes integers, rationals and doubles. |
||||||
|
If a number is double return a double. |
||||||
|
Else if a number is rational and the result's denominator is not 1 |
||||||
|
then return a rational. |
||||||
|
Else return an integer. |
||||||
|
**** < 2 number => Error |
||||||
|
**** 2 numbers => n0 ** n1 |
||||||
|
**** > 2 numbers => Error |
||||||
|
** & |
||||||
|
*** Bitwise AND numbers |
||||||
|
Takes integers and return an integer. |
||||||
|
**** 0 number => -1 |
||||||
|
**** 1 number => n |
||||||
|
**** > 1 numbers => n0 & n1 & n2 ... |
||||||
|
** | |
||||||
|
*** Bitwise OR numbers |
||||||
|
Takes integers and return an integer. |
||||||
|
**** 0 number => 0 |
||||||
|
**** 1 number => n |
||||||
|
**** > 1 numbers => n0 | n1 | n2 ... |
||||||
|
** ^ |
||||||
|
*** Bitwise XOR numbers |
||||||
|
Takes integers and return an integer. |
||||||
|
**** 0 number => 0 |
||||||
|
**** 1 number => n |
||||||
|
**** > 1 numbers => n0 ^ n1 ^ n2 ... |
||||||
|
** ~ |
||||||
|
*** Bitwise NOT numbers |
||||||
|
Takes an integer and return an integer. |
||||||
|
**** 0 number => ERROR |
||||||
|
**** 1 number => ~n |
||||||
|
**** > 1 numbers => ERROR |
||||||
|
** && |
||||||
|
*** Branching AND expresions. |
||||||
|
Takes anything, evaluate left to right and return the first item that eval to NIL |
||||||
|
or the result of the last eval. |
||||||
|
**** 0 item => T |
||||||
|
**** > 0 items => first item to eval to nil or the last item. |
||||||
|
** || |
||||||
|
*** Branching OR expresions. |
||||||
|
Takes anything, evaluate left to right and return the first item that eval to not NIL |
||||||
|
or the result of the last eval. |
||||||
|
**** 0 item => T |
||||||
|
**** > 0 items => first item to eval to not nil or the last item eval. |
||||||
|
** ! |
||||||
|
*** Return T if NIL else NIL. |
||||||
|
Takes anything. |
||||||
|
** if |
||||||
|
*** Branching tree. |
||||||
|
Evaluate the condition and then evaluate the true or false branch based on the result. |
||||||
|
I.e: if the condition evaluate to nil, evaluate the false branch. |
||||||
|
** = |
||||||
|
*** Compare 2 arguments for equality. |
||||||
|
Takes 2 argument and compare them for equality. |
||||||
|
If the types are different, return false, unless they're different number types. |
||||||
|
Compare numbers by value: |
||||||
|
Integer value to integer value if both integer. |
||||||
|
If integer and rational than always return false. |
||||||
|
If one is a double, the other argument is to be converted to double |
||||||
|
and then compared. |
||||||
|
Rationals are to be compared numerator to numerator and denominator to denominator. |
||||||
|
** < |
||||||
|
*** Is n0 less than n1? |
||||||
|
Compare the first number with the second and return true |
||||||
|
if it's less than. |
||||||
|
** > |
||||||
|
*** Is n0 greater than n1? |
||||||
|
Compare the first number with the second and return true |
||||||
|
if it's greater than. |
||||||
|
** <= |
||||||
|
*** Is n0 less than or equal to n1? |
||||||
|
Compare the first number with the second and return true |
||||||
|
if it's less than or equal. |
||||||
|
** >= |
||||||
|
*** Is n0 greater than or equal to n1? |
||||||
|
Compare the first number with the second and return true |
||||||
|
if it's greater than or equal. |
||||||
|
** != |
||||||
|
*** Compare 2 arguments for inequality. |
||||||
|
Takes 2 argument and compare them for inequality. |
||||||
|
Compare |
||||||
|
** list |
||||||
|
*** Return a list from the arguments |
||||||
|
Return nil if no arguments. |
||||||
|
** cons |
||||||
|
*** Return a cons pair from 2 arguments |
||||||
|
Return an error if more than 2 arguments. |
||||||
|
** car |
||||||
|
*** Return first element of a pair/list |
||||||
|
Return an error if not a cons. |
||||||
|
** cdr |
||||||
|
*** Return second element of a pair / rest of the list |
||||||
|
Return an error if not a cons. |
||||||
|
** peek-char |
||||||
|
*** Return first char in the specified stream. |
||||||
|
Takes nothing, NIL, T or a stream, anything else return an error. |
||||||
|
If nothing, NIL or T use the standard-input stream as the stream. |
||||||
|
Return the first character without increasing the reading pointer |
||||||
|
in the stream. |
||||||
|
** read-char |
||||||
|
*** Return first char in the specified stream. |
||||||
|
Takes nothing, NIL, T or a stream, anything else return an error. |
||||||
|
If nothing, NIL or T use the standard-input stream as the stream. |
||||||
|
Return the first character while increasing the reading pointer |
||||||
|
in the stream. |
||||||
|
** set-reader-macro |
||||||
|
*** Bind a function on a character that will be triggered during reading. |
||||||
|
Takes a character and a function. The later takes in a character |
||||||
|
and a stream and return a value. |
||||||
|
** read |
||||||
|
*** Return an expression read in the specified stream. |
||||||
|
Takes nothing, NIL, T or a stream, anything else return an error. |
||||||
|
If nothing, NIL or T use the standard-input stream as the stream. |
||||||
|
Return the first character while increasing the reading pointer |
||||||
|
in the stream. |
||||||
|
** eval |
||||||
|
*** Return the result of the evaluation of an expression. |
||||||
|
Takes 1 argument of anything and evaluate it and return the result. |
||||||
|
** quote |
||||||
|
*** Return the argument received as is. |
||||||
|
Therefore preventing any evaluation of it. |
||||||
|
** def |
||||||
|
*** Bound a value to a symbol in the global environment. |
||||||
|
Takes a symbol and anything else. More than 2 arguments result in an error. |
||||||
|
** set |
||||||
|
*** Set the value of the symbol bound in the environment. |
||||||
|
It goes from the local environmnet outward trying to find a binding on |
||||||
|
the symbol and if it doesn't then it bind it in the global env. |
||||||
|
** macro |
||||||
|
*** Create a macro function from a list of arguments and the rest is the body. |
||||||
|
** fn |
||||||
|
*** Create a function from a list of arguments and the rest is the body. |
||||||
|
** string |
||||||
|
*** Create a string from different value. |
||||||
|
If it's a string return it. |
||||||
|
If it's a symbol, create string from it's text value. |
||||||
|
If it's a character, create string from it. |
||||||
|
If it's a number, create the string representation of it. |
||||||
|
If it's a list or array, concactenate it's content string representation. |
||||||
|
i.e (string '(\h \e \l \l \o)) => "hello" |
||||||
|
Return an error on anything else. I.e hash-table, function... |
||||||
|
** array |
||||||
|
*** Create an array from the arguments. |
||||||
|
Takes anything or nothing and create an array with the arguments in it. |
||||||
|
(array 1 2 3 4) => [1 2 3 4] |
||||||
|
** hash-table |
||||||
|
*** Create an hash-table from the arguments. |
||||||
|
Takes anything or nothing and create an hash-table with the arguments |
||||||
|
splitted in pairs. The first element of a pair is the key and the second is |
||||||
|
the value. Return an error if odd number of arguments. |
||||||
|
** push |
||||||
|
*** Push an element at the end of a collection. |
||||||
|
If the collection is a string, convert the element to string and append it. |
||||||
|
If the collection is a list, append the element to the end of it. |
||||||
|
If the collection is an array, append the element to the end of it. |
||||||
|
Else return an error. |
||||||
|
** pop |
||||||
|
*** Pop an element from the end of a collection. |
||||||
|
If the collection is a string, reduce it's length by 1 and return the last character. |
||||||
|
Handle UTF-8 character so that if the last byte of the string is part of an |
||||||
|
UTF-8 character, reduce the length until you get the header, and return the UTF-8 |
||||||
|
character. |
||||||
|
If the collection is a list, set the cdr of second to last pair to nil and |
||||||
|
return the last element. |
||||||
|
If the collection is an array, reduce the length by 1 and return the last element. |
||||||
|
Else return an error. |
||||||
|
** insert |
||||||
|
*** Insert an element at a position in a collection. |
||||||
|
Let you insert into list, string, array and hash-table. |
||||||
|
Takes a number position for a list, string, array |
||||||
|
or anything as key for an hash-table. |
||||||
|
Takes anything as value to be inserted. |
||||||
|
** get |
||||||
|
*** Get an element at a position in a collection. |
||||||
|
Let you retrieve an element into list, string, array and hash-table. |
||||||
|
Takes a number position for a list, string, array |
||||||
|
or anything as key for an hash-table. |
||||||
|
Return undefined if nothing is found. |
||||||
|
** write |
||||||
|
*** Write to a stream in a format that could be read back. |
||||||
|
Write in a way that the reader could make sense of the result. |
||||||
|
Useful for writing to a file to be read from later on, or just debugging. |
||||||
|
** print |
||||||
|
*** Print to a stream in a human friendly way. |
||||||
|
Useful for user messages. |
||||||
|
** do |
||||||
|
*** Block of expresions to be evaluated. |
||||||
|
The last evaluation is to be returned. |
||||||
|
** length |
||||||
|
*** Return the length of string, list or array. |
||||||
|
If anything but a string, list or array return an error. |
||||||
|
Accepts only 1 argument. |
||||||
|
** let |
||||||
|
*** Create a local environment |
||||||
|
Takes a list of key value list and a body. |
||||||
|
Creates a new environment table and insert for the key, the evaluated value. |
||||||
|
Reuse this new environment table for the next key, value pair. |
||||||
|
Making it that the key, value of the previous pair can be used to eval the |
||||||
|
current one. |
||||||
|
Then eval the body, one expression after the other using the new local environment |
||||||
|
and return the result of the last expression. |
||||||
|
** quasiquote |
||||||
|
*** Acts like quote but with a twist. |
||||||
|
Don't eval the expression but navigate it and eval only the |
||||||
|
expression with 'unquote' or 'unquote-splicing' as their car. |
||||||
|
** unquote |
||||||
|
*** Evaluate the expression in place |
||||||
|
** unquote-splicing |
||||||
|
*** Evaluate the expression and inline the list result. |
||||||
|
Inline in a list by changing the cdr of the previous pair to |
||||||
|
result and the cdr of the last cons in result to be the cdr |
||||||
|
of the previous cons before the change. |
||||||
|
i.e (quasiquote 1 2 3 (unquote-splicing (list 4 5)) 6) => |
||||||
|
(cons 1 (cons 2 (cons 3 (cons 4 (cons 5 (cons 6 nil)))))) |
||||||
|
* Reader macros: |
||||||
|
** \( |
||||||
|
Create a list by reading elements after elements until a \) is encountered. |
||||||
|
** \) |
||||||
|
Return a error because there shouldn't be a closing bracket without a begining. |
||||||
|
** \' |
||||||
|
Quote the following read. I.e 'hello => (quote hello) |
||||||
|
** \[ |
||||||
|
Create an array by reading elements after elements until a \] is encountered. |
||||||
|
** \] |
||||||
|
Return a error because there shouldn't be a closing bracket without a begining. |
||||||
|
** \{ |
||||||
|
Create an hash-table by reading elements after elements until a \} is encountered. |
||||||
|
** \} |
||||||
|
Return a error because there shouldn't be a closing bracket without a begining. |
||||||
|
** \` |
||||||
|
Quasiquote the following read. I.e `hello => (quasiquote hello). |
||||||
|
But also create the \, reader-macro and remove it after the following read. |
||||||
|
** \, |
||||||
|
Is created and removed by \`. |
||||||
|
Unquote or unquote-splicing the following read. |
||||||
|
I.e ,hello => (unquote hello) |
||||||
|
,@'(1 2) => (unquote-splicing '(1 2)) |
||||||
|
* Requirements: |
||||||
|
** Garbage collection |
||||||
|
The idea of the garbage collector is to iterate through the blocks in |
||||||
|
memory and marking them as free. Then navigate the global environment |
||||||
|
to mark everything in it as used (not free). And finally reiterate through |
||||||
|
the blocks again to then actually free them. |
||||||
|
It's probably a naive implementation, but it's better than nothing. |
||||||
|
It will run when something is to be allocated and according to a certain interval. |
||||||
|
Maintain a counter that decrease by an amount relative to the percent of memory used. |
||||||
|
If the counter goes below zero, run the garbage collector and reset the counter. |
||||||
|
** Tail call optimisation |
||||||
|
This optimisation will be done in the evaluator. The goal is to detect when a |
||||||
|
function is calling it self in tail position. And to achieve this, on function |
||||||
|
evaluation on the last item of the body navigate through those constructs if |
||||||
|
existant: LET, IF, AND, OR and DO. And when we navigate through those construct |
||||||
|
we're looking for the tail call of them. I.e LET, AND, OR and DO is the last expression, |
||||||
|
IF is the true or false path. And when after that navigation we end up on call to |
||||||
|
the function currently being evaluated then we can optimise. The optimisation will |
||||||
|
consist in updating the environment with the new argument values to be passed |
||||||
|
to the function and instead of calling eval on it, just execute a jump to the |
||||||
|
start of the current function evaluation. In the eye of the user nothing will happen, |
||||||
|
but it will prevent that the stack based host pulls out a stack overflow. |
||||||
|
There might be a boost in performance, but it's probably minimal. |
Loading…
Reference in new issue