Added logical operators and, not and or. Closes #3
This commit is contained in:
parent
8df304bc60
commit
62ebaf9819
13 changed files with 422 additions and 132 deletions
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "memory/consspaceobject.h"
|
||||
|
||||
|
||||
#define replace_integer_i(p,i) {struct cons_pointer __p = acquire_integer(i,NIL); release_integer(p); p = __p;}
|
||||
#define replace_integer_p(p,q) {struct cons_pointer __p = p; release_integer( p); p = q;}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,35 @@ bool zerop( struct cons_pointer arg ) {
|
|||
return result;
|
||||
}
|
||||
|
||||
// TODO: think about
|
||||
// bool greaterp( struct cons_pointer arg_1, struct cons_pointer arg_2) {
|
||||
// bool result = false;
|
||||
// struct cons_space_object * cell_1 = & pointer2cell( arg_1 );
|
||||
// struct cons_space_object * cell_2 = & pointer2cell( arg_2 );
|
||||
|
||||
// if (cell_1->tag.value == cell_2->tag.value) {
|
||||
|
||||
// switch ( cell_1->tag.value ) {
|
||||
// case INTEGERTV:{
|
||||
// if ( nilp(cell_1->payload.integer.more) && nilp( cell_2->payload.integer.more)) {
|
||||
// result = cell_1->payload.integer.value > cell_2->payload.integer.value;
|
||||
// }
|
||||
// // else deal with comparing bignums...
|
||||
// }
|
||||
// break;
|
||||
// case RATIOTV:
|
||||
// result = lisp_ratio_to_real( cell_1) > ratio_to_real( cell_2);
|
||||
// break;
|
||||
// case REALTV:
|
||||
// result = ( cell.payload.real.value == 0 );
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return result;
|
||||
|
||||
// }
|
||||
|
||||
/**
|
||||
* does this `arg` point to a negative number?
|
||||
*/
|
||||
|
|
@ -86,24 +115,35 @@ bool is_negative( struct cons_pointer arg ) {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief if `arg` is a number, return the absolute value of that number, else
|
||||
* `NIL`
|
||||
*
|
||||
* @param arg a cons space object, probably a number.
|
||||
* @return struct cons_pointer
|
||||
*/
|
||||
struct cons_pointer absolute( struct cons_pointer arg ) {
|
||||
struct cons_pointer result = NIL;
|
||||
struct cons_space_object cell = pointer2cell( arg );
|
||||
|
||||
if ( is_negative( arg ) ) {
|
||||
switch ( cell.tag.value ) {
|
||||
case INTEGERTV:
|
||||
result =
|
||||
make_integer( llabs( cell.payload.integer.value ),
|
||||
cell.payload.integer.more );
|
||||
break;
|
||||
case RATIOTV:
|
||||
result = make_ratio( absolute( cell.payload.ratio.dividend ),
|
||||
cell.payload.ratio.divisor, false );
|
||||
break;
|
||||
case REALTV:
|
||||
result = make_real( 0 - cell.payload.real.value );
|
||||
break;
|
||||
if ( numberp( arg)) {
|
||||
if ( is_negative( arg ) ) {
|
||||
switch ( cell.tag.value ) {
|
||||
case INTEGERTV:
|
||||
result =
|
||||
make_integer( llabs( cell.payload.integer.value ),
|
||||
cell.payload.integer.more );
|
||||
break;
|
||||
case RATIOTV:
|
||||
result = make_ratio( absolute( cell.payload.ratio.dividend ),
|
||||
cell.payload.ratio.divisor, false );
|
||||
break;
|
||||
case REALTV:
|
||||
result = make_real( 0 - cell.payload.real.value );
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
result = arg;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,19 @@
|
|||
*/
|
||||
#define INTEGER_BIT_SHIFT (60)
|
||||
|
||||
/**
|
||||
* @brief return `true` if arg is `nil`, else `false`.
|
||||
*
|
||||
* Note that this doesn't really belong in `peano.h`, but after code cleanup it
|
||||
* was the last thing remaining in either `boolean.c` or `boolean.h`, and it
|
||||
* wasn't worth keeping two files around for one one-line macro.
|
||||
*
|
||||
* @param arg
|
||||
* @return true if the sole argument is `nil`.
|
||||
* @return false otherwise.
|
||||
*/
|
||||
#define truthy(arg)(!nilp(arg))
|
||||
|
||||
bool zerop( struct cons_pointer arg );
|
||||
|
||||
struct cons_pointer negative( struct cons_pointer arg );
|
||||
|
|
|
|||
133
src/init.c
133
src/init.c
|
|
@ -67,10 +67,14 @@ struct cons_pointer check_exception( struct cons_pointer pointer,
|
|||
return result;
|
||||
}
|
||||
|
||||
struct cons_pointer init_documentation_symbol = NIL;
|
||||
struct cons_pointer init_name_symbol = NIL;
|
||||
struct cons_pointer init_primitive_symbol = NIL;
|
||||
|
||||
void maybe_bind_init_symbols( ) {
|
||||
if ( nilp( init_documentation_symbol)) {
|
||||
init_documentation_symbol = c_string_to_lisp_keyword( L"documentation");
|
||||
}
|
||||
if ( nilp( init_name_symbol ) ) {
|
||||
init_name_symbol = c_string_to_lisp_keyword( L"name" );
|
||||
}
|
||||
|
|
@ -83,6 +87,7 @@ void maybe_bind_init_symbols( ) {
|
|||
}
|
||||
|
||||
void free_init_symbols( ) {
|
||||
dec_ref( init_documentation_symbol);
|
||||
dec_ref( init_name_symbol );
|
||||
dec_ref( init_primitive_symbol );
|
||||
}
|
||||
|
|
@ -95,21 +100,25 @@ void free_init_symbols( ) {
|
|||
* more readable and aid debugging generally.
|
||||
*/
|
||||
struct cons_pointer bind_function( wchar_t *name,
|
||||
wchar_t *doc,
|
||||
struct cons_pointer ( *executable )
|
||||
( struct stack_frame *,
|
||||
struct cons_pointer,
|
||||
struct cons_pointer ) ) {
|
||||
struct cons_pointer n = c_string_to_lisp_symbol( name );
|
||||
struct cons_pointer d = c_string_to_lisp_string( doc);
|
||||
|
||||
struct cons_pointer meta =
|
||||
make_cons( make_cons( init_primitive_symbol, TRUE ),
|
||||
make_cons( make_cons( init_name_symbol, n ),
|
||||
NIL ) );
|
||||
make_cons( make_cons( init_documentation_symbol, d), NIL) ) );
|
||||
|
||||
struct cons_pointer r =
|
||||
check_exception( deep_bind( n, make_function( meta, executable ) ),
|
||||
"bind_function" );
|
||||
|
||||
dec_ref( n );
|
||||
dec_ref( d );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
@ -321,52 +330,82 @@ int main( int argc, char *argv[] ) {
|
|||
/*
|
||||
* primitive function operations
|
||||
*/
|
||||
bind_function( L"absolute", &lisp_absolute );
|
||||
bind_function( L"add", &lisp_add );
|
||||
bind_function( L"append", &lisp_append );
|
||||
bind_function( L"apply", &lisp_apply );
|
||||
bind_function( L"assoc", &lisp_assoc );
|
||||
bind_function( L"car", &lisp_car );
|
||||
bind_function( L"cdr", &lisp_cdr );
|
||||
bind_function( L"close", &lisp_close );
|
||||
bind_function( L"cons", &lisp_cons );
|
||||
bind_function( L"divide", &lisp_divide );
|
||||
bind_function( L"eq", &lisp_eq );
|
||||
bind_function( L"equal", &lisp_equal );
|
||||
bind_function( L"eval", &lisp_eval );
|
||||
bind_function( L"exception", &lisp_exception );
|
||||
bind_function( L"get-hash", &lisp_get_hash );
|
||||
bind_function( L"hashmap", lisp_make_hashmap );
|
||||
bind_function( L"inspect", &lisp_inspect );
|
||||
bind_function( L"keys", &lisp_keys );
|
||||
bind_function( L"list", &lisp_list );
|
||||
bind_function( L"mapcar", &lisp_mapcar );
|
||||
bind_function( L"meta", &lisp_metadata );
|
||||
bind_function( L"metadata", &lisp_metadata );
|
||||
bind_function( L"multiply", &lisp_multiply );
|
||||
bind_function( L"negative?", &lisp_is_negative );
|
||||
bind_function( L"oblist", &lisp_oblist );
|
||||
bind_function( L"open", &lisp_open );
|
||||
bind_function( L"print", &lisp_print );
|
||||
bind_function( L"put!", lisp_hashmap_put );
|
||||
bind_function( L"put-all!", &lisp_hashmap_put_all );
|
||||
bind_function( L"ratio->real", &lisp_ratio_to_real );
|
||||
bind_function( L"read", &lisp_read );
|
||||
bind_function( L"read-char", &lisp_read_char );
|
||||
bind_function( L"repl", &lisp_repl );
|
||||
bind_function( L"reverse", &lisp_reverse );
|
||||
bind_function( L"set", &lisp_set );
|
||||
bind_function( L"slurp", &lisp_slurp );
|
||||
bind_function( L"source", &lisp_source );
|
||||
bind_function( L"subtract", &lisp_subtract );
|
||||
bind_function( L"throw", &lisp_exception );
|
||||
bind_function( L"time", &lisp_time );
|
||||
bind_function( L"type", &lisp_type );
|
||||
bind_function( L"+", &lisp_add );
|
||||
bind_function( L"*", &lisp_multiply );
|
||||
bind_function( L"-", &lisp_subtract );
|
||||
bind_function( L"/", &lisp_divide );
|
||||
bind_function( L"=", &lisp_equal );
|
||||
/* TODO: docstrings should be moved to a header file, or even to an at-run-time resolution system.
|
||||
* HTTP from an address at journeyman? */
|
||||
bind_function( L"absolute",
|
||||
L"`(absolute arg)`: If `arg` is a number, return the absolute value of that number, else `nil`.",
|
||||
&lisp_absolute );
|
||||
bind_function( L"add",
|
||||
L"`(+ args...)`: If `args` are all numbers, return the sum of those numbers.",
|
||||
&lisp_add );
|
||||
bind_function( L"and",
|
||||
L"`(and args...)`: Return a logical `and` of all the arguments and return `t` only if all are truthy, else `nil`.",
|
||||
&lisp_and);
|
||||
bind_function( L"append", L"`(append args...)`: If args are all collections, return the concatenation of those collections.",
|
||||
&lisp_append );
|
||||
bind_function( L"apply",
|
||||
L"`(apply f args)`: If `f` is usable as a function, and `args` is a collection, apply `f` to `args` and return the value.",
|
||||
&lisp_apply );
|
||||
bind_function( L"assoc",
|
||||
L"`(assoc key store)`: Return the value associated with this `key` in this `store`.",
|
||||
&lisp_assoc );
|
||||
bind_function( L"car",
|
||||
L"`(car arg)`: If `arg` is a sequence, return the item which is the head of that sequence.",
|
||||
&lisp_car );
|
||||
bind_function( L"cdr",
|
||||
L"`(cdr arg)`: If `arg` is a sequence, return the remainder of that sequence with the first item removed.",
|
||||
&lisp_cdr );
|
||||
bind_function( L"close", L"`(close stream)`: If `stream` is a stream, close that stream.", &lisp_close );
|
||||
bind_function( L"cons", L"`(cons a b)`: Return a cons cell whose `car` is `a` and whose `cdr` is `b`.", &lisp_cons );
|
||||
bind_function( L"divide",
|
||||
L"`(/ a b)`: If `a` and `b` are both numbers, return the numeric result of dividing `a` by `b`.",
|
||||
&lisp_divide );
|
||||
bind_function( L"eq", L"`(eq a b)`: Return `t` if `a` and `b` are the exact same object, else `nil`.", &lisp_eq );
|
||||
bind_function( L"equal", L"`(eq a b)`: Return `t` if `a` and `b` have logically equivalent value, else `nil`.", &lisp_equal );
|
||||
bind_function( L"eval", L"", &lisp_eval );
|
||||
bind_function( L"exception", L"`(exception message)`: Return (throw) an exception with this `message`.", &lisp_exception );
|
||||
bind_function( L"get-hash", L"`(get-hash arg)`: returns the natural number hash value of `arg`.", &lisp_get_hash );
|
||||
bind_function( L"hashmap",
|
||||
L"`(hashmap n-buckets hashfn store acl)`: Return a new hashmap, with `n-buckets` buckets and this `hashfn`, containing the content of this `store`.",
|
||||
lisp_make_hashmap );
|
||||
bind_function( L"inspect",
|
||||
L"`(inspect object ouput-stream)`: Print details of this `object` to this `output-stream` or `*out*`.",
|
||||
&lisp_inspect );
|
||||
bind_function( L"keys", L"`(keys store)`: Return a list of all keys in this `store`.", &lisp_keys );
|
||||
bind_function( L"list", L"`(list args...): Return a list of these `args`.", &lisp_list );
|
||||
bind_function( L"mapcar", L"`(mapcar function sequence)`: Apply `function` to each element of `sequence` in turn, and return a sequence of the results.", &lisp_mapcar );
|
||||
bind_function( L"meta", L"`(meta symbol)`: If the binding of `symbol` has metadata, return that metadata, else `nil`.", &lisp_metadata );
|
||||
bind_function( L"metadata", L"`(metadata symbol)`: If the binding of `symbol` has metadata, return that metadata, else `nil`.", &lisp_metadata );
|
||||
bind_function( L"multiply", L"`(* args...)` Multiply these `args`, all of which should be numbers.", &lisp_multiply );
|
||||
bind_function( L"negative?", L"`(negative? n)`: Return `t` if `n` is a negative number, else `nil`.", &lisp_is_negative );
|
||||
bind_function( L"not",
|
||||
L"`(not arg)`: Return`t` only if `arg` is `nil`, else `nil`.",
|
||||
&lisp_not);
|
||||
bind_function( L"oblist", L"`(oblist)`: Return the current symbol bindings, as a map.", &lisp_oblist );
|
||||
bind_function( L"open", L"`(open url read?)`: Open a stream to this `url`. If `read` is present and is non-nil, open it for reading, else writing.", &lisp_open );
|
||||
bind_function( L"or",
|
||||
L"`(or args...)`: Return a logical `or` of all the arguments and return `t` if any is truthy, else `nil`.",
|
||||
&lisp_or);
|
||||
bind_function( L"print", L"`(print object stream)`: Print `object` to `stream`, if specified, else to `*out*`.", &lisp_print );
|
||||
bind_function( L"put!", L"", lisp_hashmap_put );
|
||||
bind_function( L"put-all!", L"", &lisp_hashmap_put_all );
|
||||
bind_function( L"ratio->real", L"", &lisp_ratio_to_real );
|
||||
bind_function( L"read", L"", &lisp_read );
|
||||
bind_function( L"read-char", L"", &lisp_read_char );
|
||||
bind_function( L"repl", L"", &lisp_repl );
|
||||
bind_function( L"reverse", L"", &lisp_reverse );
|
||||
bind_function( L"set", L"", &lisp_set );
|
||||
bind_function( L"slurp", L"", &lisp_slurp );
|
||||
bind_function( L"source", L"", &lisp_source );
|
||||
bind_function( L"subtract", L"", &lisp_subtract );
|
||||
bind_function( L"throw", L"", &lisp_exception );
|
||||
bind_function( L"time", L"", &lisp_time );
|
||||
bind_function( L"type", L"", &lisp_type );
|
||||
bind_function( L"+", L"", &lisp_add );
|
||||
bind_function( L"*", L"", &lisp_multiply );
|
||||
bind_function( L"-", L"", &lisp_subtract );
|
||||
bind_function( L"/", L"", &lisp_divide );
|
||||
bind_function( L"=", L"", &lisp_equal );
|
||||
/*
|
||||
* primitive special forms
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -10,12 +10,15 @@
|
|||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "memory/conspage.h"
|
||||
#include "memory/consspaceobject.h"
|
||||
#include "arith/integer.h"
|
||||
#include "arith/peano.h"
|
||||
#include "arith/ratio.h"
|
||||
#include "debug.h"
|
||||
#include "memory/conspage.h"
|
||||
#include "memory/consspaceobject.h"
|
||||
#include "memory/vectorspace.h"
|
||||
#include "ops/equal.h"
|
||||
#include "ops/intern.h"
|
||||
|
||||
/**
|
||||
* Shallow, and thus cheap, equality: true if these two objects are
|
||||
|
|
@ -240,6 +243,86 @@ bool equal_number_number( struct cons_pointer a, struct cons_pointer b ) {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief equality of two map-like things.
|
||||
*
|
||||
* The list returned by `keys` on a map-like thing is not sorted, and is not
|
||||
* guaranteed always to come out in the same order. So equality is established
|
||||
* if:
|
||||
* 1. the length of the keys list is the same; and
|
||||
* 2. the value of each key in the keys list for map `a` is the same in map `a`
|
||||
* and in map `b`.
|
||||
*
|
||||
* Private function, do not use outside this file, **WILL NOT** work
|
||||
* unless both arguments are VECPs.
|
||||
*
|
||||
* @param a a pointer to a vector space object.
|
||||
* @param b another pointer to a vector space object.
|
||||
* @return true if the two objects have the same logical structure.
|
||||
* @return false otherwise.
|
||||
*/
|
||||
bool equal_map_map( struct cons_pointer a, struct cons_pointer b ) {
|
||||
bool result=false;
|
||||
|
||||
struct cons_pointer keys_a = hashmap_keys( a);
|
||||
|
||||
if ( c_length( keys_a) == c_length( hashmap_keys( b))) {
|
||||
result = true;
|
||||
|
||||
for ( struct cons_pointer i = keys_a; !nilp( i); i = c_cdr( i)) {
|
||||
struct cons_pointer key = c_car( i);
|
||||
if ( !equal( hashmap_get( a, key),hashmap_get( b, key))) {
|
||||
result = false; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief equality of two vector-space things.
|
||||
*
|
||||
* Expensive, but we need to be able to check for equality of at least hashmaps
|
||||
* and namespaces.
|
||||
*
|
||||
* Private function, do not use outside this file, not guaranteed to work
|
||||
* unless both arguments are VECPs pointing to map like things.
|
||||
*
|
||||
* @param a a pointer to a vector space object.
|
||||
* @param b another pointer to a vector space object.
|
||||
* @return true if the two objects have the same logical structure.
|
||||
* @return false otherwise.
|
||||
*/
|
||||
bool equal_vector_vector( struct cons_pointer a, struct cons_pointer b ) {
|
||||
bool result = false;
|
||||
|
||||
if ( eq( a, b)) {
|
||||
result = true; // same
|
||||
/* there shouldn't ever be two separate VECP cells which point to the
|
||||
* same address in vector space, so I don't believe it's worth checking
|
||||
* for this.
|
||||
*/
|
||||
} else if ( vectorp( a) && vectorp( b)) {
|
||||
struct vector_space_object * va = pointer_to_vso( a);
|
||||
struct vector_space_object * vb = pointer_to_vso( b);
|
||||
|
||||
/* what we're saying here is that a namespace is not equal to a map,
|
||||
* even if they have identical logical structure. Is this right? */
|
||||
if ( va->header.tag.value == vb->header.tag.value) {
|
||||
switch ( va->header.tag.value) {
|
||||
case HASHTV:
|
||||
case NAMESPACETV:
|
||||
result = equal_map_map( a, b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// else can't throw an exception from here but TODO: should log.
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deep, and thus expensive, equality: true if these two objects have
|
||||
* identical structure, else false.
|
||||
|
|
@ -319,6 +402,13 @@ bool equal( struct cons_pointer a, struct cons_pointer b ) {
|
|||
result = fabs( num_a - num_b ) < ( max / 1000000.0 );
|
||||
}
|
||||
break;
|
||||
case VECTORPOINTTV:
|
||||
if ( cell_b->tag.value == VECTORPOINTTV) {
|
||||
result = equal_vector_vector( a, b);
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result = false;
|
||||
break;
|
||||
|
|
@ -329,8 +419,8 @@ bool equal( struct cons_pointer a, struct cons_pointer b ) {
|
|||
|
||||
/*
|
||||
* there's only supposed ever to be one T and one NIL cell, so each
|
||||
* should be caught by eq; equality of vector-space objects is a whole
|
||||
* other ball game so we won't deal with it now (and indeed may never).
|
||||
* should be caught by eq.
|
||||
*
|
||||
* I'm not certain what equality means for read and write streams, so
|
||||
* I'll ignore them, too, for now.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -24,19 +24,20 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "memory/consspaceobject.h"
|
||||
#include "memory/conspage.h"
|
||||
#include "debug.h"
|
||||
#include "memory/dump.h"
|
||||
#include "ops/equal.h"
|
||||
#include "arith/integer.h"
|
||||
#include "ops/intern.h"
|
||||
#include "arith/peano.h"
|
||||
#include "debug.h"
|
||||
#include "io/io.h"
|
||||
#include "ops/lispops.h"
|
||||
#include "io/print.h"
|
||||
#include "io/read.h"
|
||||
#include "memory/conspage.h"
|
||||
#include "memory/consspaceobject.h"
|
||||
#include "memory/stack.h"
|
||||
#include "memory/vectorspace.h"
|
||||
#include "memory/dump.h"
|
||||
#include "ops/equal.h"
|
||||
#include "ops/intern.h"
|
||||
#include "ops/lispops.h"
|
||||
|
||||
/**
|
||||
* @brief the name of the symbol to which the prompt is bound;
|
||||
|
|
@ -74,7 +75,6 @@ struct cons_pointer eval_form( struct stack_frame *parent,
|
|||
/* things which evaluate to themselves */
|
||||
case EXCEPTIONTV:
|
||||
case FREETV: // shouldn't happen, but anyway...
|
||||
// FUNCTIONTV, LAMBDATV, NLAMBDATV, SPECIALTV ?
|
||||
case INTEGERTV:
|
||||
case KEYTV:
|
||||
case LOOPTV: // don't think this should happen...
|
||||
|
|
@ -85,7 +85,6 @@ struct cons_pointer eval_form( struct stack_frame *parent,
|
|||
case STRINGTV:
|
||||
case TIMETV:
|
||||
case TRUETV:
|
||||
// case VECTORPOINTTV: ?
|
||||
case WRITETV:
|
||||
break;
|
||||
default:
|
||||
|
|
@ -243,10 +242,10 @@ lisp_nlambda( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
|||
}
|
||||
|
||||
void log_binding( struct cons_pointer name, struct cons_pointer val ) {
|
||||
debug_print( L"\n\tBinding ", DEBUG_ALLOC );
|
||||
debug_dump_object( name, DEBUG_ALLOC );
|
||||
debug_print( L" to ", DEBUG_ALLOC );
|
||||
debug_dump_object( val, DEBUG_ALLOC );
|
||||
debug_print( L"\n\tBinding ", DEBUG_LAMBDA );
|
||||
debug_dump_object( name, DEBUG_LAMBDA );
|
||||
debug_print( L" to ", DEBUG_LAMBDA );
|
||||
debug_dump_object( val, DEBUG_LAMBDA );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -305,12 +304,15 @@ eval_lambda( struct cons_space_object cell, struct stack_frame *frame,
|
|||
|
||||
debug_print( L"In lambda: evaluating ", DEBUG_LAMBDA );
|
||||
debug_print_object( sexpr, DEBUG_LAMBDA );
|
||||
// debug_print( L"\t env is: ", DEBUG_LAMBDA );
|
||||
// debug_print_object( new_env, DEBUG_LAMBDA );
|
||||
debug_println( DEBUG_LAMBDA );
|
||||
|
||||
/* if a result is not the terminal result in the lambda, it's a
|
||||
* side effect, and needs to be GCed */
|
||||
if ( !nilp( result ) )
|
||||
dec_ref( result );
|
||||
if ( !nilp( result ) ){
|
||||
// dec_ref( result );
|
||||
}
|
||||
|
||||
result = eval_form( frame, frame_pointer, sexpr, new_env );
|
||||
|
||||
|
|
@ -319,7 +321,7 @@ eval_lambda( struct cons_space_object cell, struct stack_frame *frame,
|
|||
}
|
||||
}
|
||||
|
||||
dec_ref( new_env );
|
||||
// dec_ref( new_env );
|
||||
|
||||
debug_print( L"eval_lambda returning: \n", DEBUG_LAMBDA );
|
||||
debug_print_object( result, DEBUG_LAMBDA );
|
||||
|
|
@ -870,7 +872,12 @@ struct cons_pointer lisp_keys( struct stack_frame *frame,
|
|||
struct cons_pointer lisp_eq( struct stack_frame *frame,
|
||||
struct cons_pointer frame_pointer,
|
||||
struct cons_pointer env ) {
|
||||
return eq( frame->arg[0], frame->arg[1] ) ? TRUE : NIL;
|
||||
if ( frame->args == 2) {
|
||||
return eq( frame->arg[0], frame->arg[1] ) ? TRUE : NIL;
|
||||
} else {
|
||||
return throw_exception( c_string_to_lisp_string( L"Wrong number of args to `eq`."),
|
||||
frame_pointer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -886,7 +893,12 @@ struct cons_pointer lisp_eq( struct stack_frame *frame,
|
|||
struct cons_pointer
|
||||
lisp_equal( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||
struct cons_pointer env ) {
|
||||
return equal( frame->arg[0], frame->arg[1] ) ? TRUE : NIL;
|
||||
if ( frame->args == 2) {
|
||||
return equal( frame->arg[0], frame->arg[1] ) ? TRUE : NIL;
|
||||
} else {
|
||||
return throw_exception( c_string_to_lisp_string( L"Wrong number of args to `equal`."),
|
||||
frame_pointer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1507,6 +1519,14 @@ struct cons_pointer lisp_mapcar( struct stack_frame *frame,
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief construct and return a list of arbitrarily many arguments.
|
||||
*
|
||||
* @param frame The stack frame.
|
||||
* @param frame_pointer A pointer to the stack frame.
|
||||
* @param env The evaluation environment.
|
||||
* @return struct cons_pointer a pointer to the result
|
||||
*/
|
||||
struct cons_pointer lisp_list( struct stack_frame *frame,
|
||||
struct cons_pointer frame_pointer,
|
||||
struct cons_pointer env ) {
|
||||
|
|
@ -1563,35 +1583,70 @@ struct cons_pointer lisp_let( struct stack_frame *frame,
|
|||
|
||||
}
|
||||
|
||||
// struct cons_pointer c_concat( struct cons_pointer a, struct cons_pointer b) {
|
||||
// struct cons_pointer result = b;
|
||||
/**
|
||||
* @brief Boolean `and` of arbitrarily many arguments.
|
||||
*
|
||||
* @param frame The stack frame.
|
||||
* @param frame_pointer A pointer to the stack frame.
|
||||
* @param env The evaluation environment.
|
||||
* @return struct cons_pointer a pointer to the result
|
||||
*/
|
||||
struct cons_pointer lisp_and( struct stack_frame *frame,
|
||||
struct cons_pointer frame_pointer,
|
||||
struct cons_pointer env ) {
|
||||
bool accumulator = true;
|
||||
struct cons_pointer result = frame->more;
|
||||
|
||||
// if ( nilp( b.tag.value)) {
|
||||
// result = make_cons( a, b);
|
||||
// } else {
|
||||
// if ( ! nilp( a)) {
|
||||
// if (a.tag.value == b.tag.value) {
|
||||
for ( int a = 0; accumulator == true && a < args_in_frame; a++) {
|
||||
accumulator = truthy( frame->arg[ a]);
|
||||
}
|
||||
|
||||
// struct cons_pointer tail = c_concat( c_cdr( a), b);
|
||||
if ( accumulator && ! nilp( frame->more)) {
|
||||
for ( struct cons_pointer rest = frame->more; accumulator == true && !nilp( rest); rest = c_cdr(rest)) {
|
||||
accumulator = truthy( c_car( rest));
|
||||
}
|
||||
}
|
||||
|
||||
// switch ( a.tag.value) {
|
||||
// case CONSTV:
|
||||
// result = make_cons( c_car( a), tail);
|
||||
// break;
|
||||
// case KEYTV:
|
||||
// case STRINGTV:
|
||||
// case SYMBOLTV:
|
||||
// result = make_string_like_thing()
|
||||
return accumulator ? TRUE : NIL;
|
||||
}
|
||||
|
||||
// }
|
||||
/**
|
||||
* @brief Boolean `or` of arbitrarily many arguments.
|
||||
*
|
||||
* @param frame The stack frame.
|
||||
* @param frame_pointer A pointer to the stack frame.
|
||||
* @param env The evaluation environment.
|
||||
* @return struct cons_pointer a pointer to the result
|
||||
*/
|
||||
struct cons_pointer lisp_or( struct stack_frame *frame,
|
||||
struct cons_pointer frame_pointer,
|
||||
struct cons_pointer env ) {
|
||||
bool accumulator = false;
|
||||
struct cons_pointer result = frame->more;
|
||||
|
||||
// } else {
|
||||
// // throw an exception
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
for ( int a = 0; accumulator == false && a < args_in_frame; a++) {
|
||||
accumulator = truthy( frame->arg[ a]);
|
||||
}
|
||||
|
||||
if ( ! accumulator && ! nilp( frame->more)) {
|
||||
for ( struct cons_pointer rest = frame->more; accumulator == false && !nilp( rest); rest = c_cdr(rest)) {
|
||||
accumulator = truthy( c_car( rest));
|
||||
}
|
||||
}
|
||||
|
||||
return accumulator ? TRUE : NIL;
|
||||
}
|
||||
|
||||
// return result;
|
||||
// }
|
||||
/**
|
||||
* @brief Logical inverese: if the first argument is `nil`, return `t`, else `nil`.
|
||||
*
|
||||
* @param frame The stack frame.
|
||||
* @param frame_pointer A pointer to the stack frame.
|
||||
* @param env The evaluation environment.
|
||||
* @return struct cons_pointer `t` if the first argument is `nil`, else `nil`.
|
||||
*/
|
||||
struct cons_pointer lisp_not( struct stack_frame *frame,
|
||||
struct cons_pointer frame_pointer,
|
||||
struct cons_pointer env ) {
|
||||
return nilp( frame->arg[0]) ? TRUE : NIL;
|
||||
}
|
||||
|
|
@ -225,4 +225,17 @@ struct cons_pointer lisp_let( struct stack_frame *frame,
|
|||
struct cons_pointer lisp_try( struct stack_frame *frame,
|
||||
struct cons_pointer frame_pointer,
|
||||
struct cons_pointer env );
|
||||
|
||||
|
||||
struct cons_pointer lisp_and( struct stack_frame *frame,
|
||||
struct cons_pointer frame_pointer,
|
||||
struct cons_pointer env );
|
||||
|
||||
struct cons_pointer lisp_or( struct stack_frame *frame,
|
||||
struct cons_pointer frame_pointer,
|
||||
struct cons_pointer env );
|
||||
|
||||
struct cons_pointer lisp_not( struct stack_frame *frame,
|
||||
struct cons_pointer frame_pointer,
|
||||
struct cons_pointer env );
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue