Compare commits
No commits in common. "72a8bc09e049b99c0514189272897fba9d985a7b" and "145a0fe5a747a23ab8853dff904fe83e00ad3799" have entirely different histories.
72a8bc09e0
...
145a0fe5a7
20 changed files with 291 additions and 589 deletions
|
|
@ -12,50 +12,58 @@ causes an unbound variable exception to be thrown, while
|
||||||
|
|
||||||
returns the value **"froboz"**. This begs the question of whether there's any difference between **"froboz"** and **'froboz**, and the answer is that at this point I don't know.
|
returns the value **"froboz"**. This begs the question of whether there's any difference between **"froboz"** and **'froboz**, and the answer is that at this point I don't know.
|
||||||
|
|
||||||
There will be a concept of a root [namespace](Namespace.md), in which other namespaces may be bound recursively to form a directed graph. Because at least some namespaces are mutable, the graph is not necessarily acyclic. There will be a concept of a current namespace, that is to say the namespace in which the user is currently working.
|
There will be a concept of a root [namespace](Namespace.html), in which other namespaces may be bound recursively to form a directed graph. Because at least some namespaces are mutable, the graph is not necessarily acyclic. There will be a concept of a current namespace, that is to say the namespace in which the user is currently working.
|
||||||
|
|
||||||
There must be some notation to say distinguish a request for the value of a name in the root namespace and the value of a name in the current namespace. For now I'm proposing that:
|
There must be some notation to say distinguish a request for the value of a name in the root namespace and the value of a name in the current namespace. For now I'm proposing that:
|
||||||
|
|
||||||
(eval 'froboz)
|
(eval froboz)
|
||||||
|
|
||||||
will return the value that **froboz** is bound to in the current namespace;
|
will return the value that **froboz** is bound to in the current namespace;
|
||||||
|
|
||||||
(eval ::/froboz)
|
(eval .froboz)
|
||||||
|
|
||||||
will return the value that **froboz** is bound to in the root namespace;
|
will return the value that **froboz** is bound to in the root namespace;
|
||||||
|
|
||||||
(eval 'foobar/froboz)
|
(eval foobar.froboz)
|
||||||
|
|
||||||
will return the value that **froboz** is bound to in a namespace which is the value of the name **foobar** in the current namespace; and that
|
will return the value that **froboz** is bound to in a namespace which is the value of the name **foobar** in the current namespace; and that
|
||||||
|
|
||||||
(eval ::users:simon:environment/froboz)
|
(eval .system.users.simon.environment.froboz)
|
||||||
|
|
||||||
will return the value that **froboz** is bound to in the environment of the user of the system called **simon** (if that is readable by you).
|
will return the value that **froboz** is bound to in the environment of the user of the system called **simon**.
|
||||||
|
|
||||||
The [exact path separator syntax](Paths.md) may change, but the principal that when interning a symbol it is broken down into a path of tokens, and that the value of each token is sought in a namespace bound to the previous token, is likely to remain.
|
The exact path separator syntax may change, but the principal that when interning a symbol it is broken down into a path of tokens, and that the value of each token is sought in a namespace bound to the previous token, is likely to remain.
|
||||||
|
|
||||||
Obviously if **froboz** is interned in one namespace it is not necessarily interned in another, and vice versa. There's a potentially nasty problem here that two lexically identical strings might be bound in different namespaces, so that there is not one canonical interned **froboz**; if this turns out to cause problems in practice there will need to be a separate canonical [hashtable](Hashtable.md) of individual path elements.
|
Obviously if **froboz** is interned in one namespace it is not necessarily interned in another, and vice versa. There's a potentially nasty problem here that two lexically identical strings might be bound in different namespaces, so that there is not one canonical interned **froboz**; if this turns out to cause problems in practice there will need to be a separate canonical [hashtable](Hashtable.html) of individual path elements.
|
||||||
|
|
||||||
Obviously this means there may be arbitrarily many paths which reference the same data item. This is intended.
|
Obviously this means there may be arbitrarily many paths which reference the same data item. This is intended.
|
||||||
|
|
||||||
## Related functions
|
## Related functions
|
||||||
|
|
||||||
### (intern! path)
|
### (intern! string)
|
||||||
|
|
||||||
Binds *path* to **NIL**. If some namespace along the path doesn't exist, throws an exception. Obviously if the current user is not entitled to write to the terminal namespace, also throws an exception.
|
Binds *string*, considered as a path, to **NIL**. If some namespace along the path doesn't exist, throws an exception. Obviously if the current user is not entitled to write to the terminal namespace, also throws an exception.
|
||||||
|
|
||||||
### (intern! path T)
|
### (intern! string T)
|
||||||
|
|
||||||
Binds *path* to **NIL**. If some namespace along the path doesn't exist, create it as the current user with both read and write [access control](Access-control.html) lists taken from the current binding of **:friends** in the current environment. Obviously if the current user is not entitled to write to the last pre-existing namespace, throws an exception.
|
Binds *string*, considered as a path, to **NIL**. If some namespace along the path doesn't exist, create it as the current user with both read and write [access control](Access-control.html) lists taken from the current binding of **friends** in the current environment. Obviously if the current user is not entitled to write to the last pre-existing namespace, throws an exception.
|
||||||
|
|
||||||
|
### (intern! string T write-access-list)
|
||||||
|
|
||||||
|
Binds *string*, considered as a path, to **NIL**. If some namespace along the path doesn't exist, create it as the current user with the read [access control](https://www.journeyman.cc/blog/posts-output/2006-02-20-postscarcity-software/) list taken from the current binding of **friends** in the current environment, and the write access control list taken from the value of *write-access-list*. Obviously if the current user is not entitled to write to the last pre-existing namespace, throws an exception.
|
||||||
|
|
||||||
### (set! string value)
|
### (set! string value)
|
||||||
|
|
||||||
Binds *path* to *value*. If some namespace along the path doesn't exist, throws an exception. Obviously if the current user is not entitled to write to the terminal namespace, also throws an exception.
|
Binds *string*, considered as a path, to *value*. If some namespace along the path doesn't exist, throws an exception. Obviously if the current user is not entitled to write to the terminal namespace, also throws an exception.
|
||||||
|
|
||||||
### (set! string value T)
|
### (set! string value T)
|
||||||
|
|
||||||
Binds *string*, considered as a path, to *value*. If some namespace along the path doesn't exist, create it as the current user with both read and write [access control](Access-control.html) lists taken from the current binding of **friends** in the current environment. Obviously if the current user is not entitled to write to the last pre-existing namespace, throws an exception.
|
Binds *string*, considered as a path, to *value*. If some namespace along the path doesn't exist, create it as the current user with both read and write [access control](Access-control.html) lists taken from the current binding of **friends** in the current environment. Obviously if the current user is not entitled to write to the last pre-existing namespace, throws an exception.
|
||||||
|
|
||||||
|
### (set! string value T write-access-list)
|
||||||
|
|
||||||
|
Binds *string*, considered as a path, to *value*. If some namespace along the path doesn't exist, create it as the current user with the read [access control](Access-control.html) list taken from the current binding of **friends** in the current environment, and the write access control list taken from the value of *write-access-list*. Obviously if the current user is not entitled to write to the last pre-existing namespace, throws an exception.
|
||||||
|
|
||||||
### (put! string token value)
|
### (put! string token value)
|
||||||
|
|
||||||
Considers *string* as the path to some namespace, and binds *token* in that namespace to *value*. *Token* should not contain any path separator syntax. If the namespace doesn't exist or if the current user is not entitled to write to the namespace, throws an exception.
|
Considers *string* as the path to some namespace, and binds *token* in that namespace to *value*. *Token* should not contain any path separator syntax. If the namespace doesn't exist or if the current user is not entitled to write to the namespace, throws an exception.
|
||||||
|
|
@ -63,16 +71,16 @@ Considers *string* as the path to some namespace, and binds *token* in that name
|
||||||
### (string-to-path string)
|
### (string-to-path string)
|
||||||
|
|
||||||
Behaviour as follows:
|
Behaviour as follows:
|
||||||
(string-to-path ":foo:bar/ban") => (-> (environment) :foo :bar 'ban)
|
(string-to-path "foo.bar.ban") => ("foo" "bar" "ban")
|
||||||
(string-to-path "::foo:bar/ban") => (-> (oblist) :foo :bar 'ban)
|
(string-to-path ".foo.bar.ban") => ("" "foo" "bar" "ban")
|
||||||
|
|
||||||
Obviously if the current user can't read the string, throws an exception. `(oblist)` is currently (version 0.0.6) a function which returns the current value of the root namespace; `(environment)` is a proposed function which returns the current value of the environment of current user (with possibly `(environmnt user-name)` returning the value of the environment of the user indicated by `user-name`, if that is readable by you). The symbol `->` represents a threading macro [similar to Clojure's](https://clojuredocs.org/clojure.core/-%3E).
|
Obviously if the current user can't read the string, throws an exception.
|
||||||
|
|
||||||
### (path-to-string list-of-strings)
|
### (path-to-string list-of-strings)
|
||||||
|
|
||||||
Behaviour as follows:
|
Behaviour as follows:
|
||||||
(path-to-string '(:foo :bar 'ban)) => ":foo:bar/ban"
|
(path-to-string '("foo" "bar" "ban")) => "foo.bar.ban"
|
||||||
(path-to-string '("" :foo :bar 'ban)) => "::foo:bar/ban"
|
(path-to-string '("" "foo" "bar" "ban")) => ".foo.bar.ban"
|
||||||
|
|
||||||
Obviously if the current user can't read some element of *list-of-strings*, throws an exception.
|
Obviously if the current user can't read some element of *list-of-strings*, throws an exception.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,31 +3,6 @@
|
||||||
;; `nth` (from `nth.lisp`)
|
;; `nth` (from `nth.lisp`)
|
||||||
;; `string?` (from `types.lisp`)
|
;; `string?` (from `types.lisp`)
|
||||||
|
|
||||||
(set! nil? (lambda
|
|
||||||
(o)
|
|
||||||
"`(nil? object)`: Return `t` if object is `nil`, else `t`."
|
|
||||||
(= o nil)))
|
|
||||||
|
|
||||||
(set! member? (lambda
|
|
||||||
(item collection)
|
|
||||||
"`(member item collection)`: Return `t` if this `item` is a member of this `collection`, else `nil`."
|
|
||||||
(print (list "In member? item is " item "; collection is " collection))
|
|
||||||
;; (println)
|
|
||||||
(cond
|
|
||||||
((= 0 (count collection)) nil)
|
|
||||||
((= item (car collection)) t)
|
|
||||||
(t (member? item (cdr collection))))))
|
|
||||||
|
|
||||||
;; (member? (type member?) '("LMDA" "NLMD"))
|
|
||||||
|
|
||||||
(set! nth (lambda (n l)
|
|
||||||
"Return the `n`th member of this list `l`, or `nil` if none."
|
|
||||||
(cond ((= nil l) nil)
|
|
||||||
((= n 1) (car l))
|
|
||||||
(t (nth (- n 1) (cdr l))))))
|
|
||||||
|
|
||||||
(set! string? (lambda (o) "True if `o` is a string." (= (type o) "STRG") ) )
|
|
||||||
|
|
||||||
(set! documentation (lambda (object)
|
(set! documentation (lambda (object)
|
||||||
"`(documentation object)`: Return documentation for the specified `object`, if available, else `nil`."
|
"`(documentation object)`: Return documentation for the specified `object`, if available, else `nil`."
|
||||||
(cond ((member? (type object) '("FUNC" "SPFM"))
|
(cond ((member? (type object) '("FUNC" "SPFM"))
|
||||||
|
|
@ -40,7 +15,3 @@
|
||||||
|
|
||||||
(set! doc documentation)
|
(set! doc documentation)
|
||||||
|
|
||||||
(documentation apply)
|
|
||||||
|
|
||||||
;; (documentation member?)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -296,9 +296,7 @@ struct cons_pointer add_2( struct stack_frame *frame,
|
||||||
to_long_double( arg2 ) );
|
to_long_double( arg2 ) );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result =
|
result = throw_exception( c_string_to_lisp_string
|
||||||
throw_exception( c_string_to_lisp_symbol( L"+" ),
|
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Cannot add: not a number" ),
|
( L"Cannot add: not a number" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
break;
|
break;
|
||||||
|
|
@ -321,9 +319,7 @@ struct cons_pointer add_2( struct stack_frame *frame,
|
||||||
to_long_double( arg2 ) );
|
to_long_double( arg2 ) );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result =
|
result = throw_exception( c_string_to_lisp_string
|
||||||
throw_exception( c_string_to_lisp_symbol( L"+" ),
|
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Cannot add: not a number" ),
|
( L"Cannot add: not a number" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
break;
|
break;
|
||||||
|
|
@ -336,8 +332,7 @@ struct cons_pointer add_2( struct stack_frame *frame,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = exceptionp( arg2 ) ? arg2 :
|
result = exceptionp( arg2 ) ? arg2 :
|
||||||
throw_exception( c_string_to_lisp_symbol( L"+" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Cannot add: not a number" ),
|
( L"Cannot add: not a number" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
}
|
}
|
||||||
|
|
@ -433,8 +428,7 @@ struct cons_pointer multiply_2( struct stack_frame *frame,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"*" ),
|
throw_exception( make_cons
|
||||||
make_cons
|
|
||||||
( c_string_to_lisp_string
|
( c_string_to_lisp_string
|
||||||
( L"Cannot multiply: argument 2 is not a number: " ),
|
( L"Cannot multiply: argument 2 is not a number: " ),
|
||||||
c_type( arg2 ) ),
|
c_type( arg2 ) ),
|
||||||
|
|
@ -460,8 +454,7 @@ struct cons_pointer multiply_2( struct stack_frame *frame,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"*" ),
|
throw_exception( make_cons
|
||||||
make_cons
|
|
||||||
( c_string_to_lisp_string
|
( c_string_to_lisp_string
|
||||||
( L"Cannot multiply: argument 2 is not a number" ),
|
( L"Cannot multiply: argument 2 is not a number" ),
|
||||||
c_type( arg2 ) ),
|
c_type( arg2 ) ),
|
||||||
|
|
@ -474,8 +467,7 @@ struct cons_pointer multiply_2( struct stack_frame *frame,
|
||||||
to_long_double( arg2 ) );
|
to_long_double( arg2 ) );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = throw_exception( c_string_to_lisp_symbol( L"*" ),
|
result = throw_exception( make_cons( c_string_to_lisp_string
|
||||||
make_cons( c_string_to_lisp_string
|
|
||||||
( L"Cannot multiply: argument 1 is not a number" ),
|
( L"Cannot multiply: argument 1 is not a number" ),
|
||||||
c_type( arg1 ) ),
|
c_type( arg1 ) ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
|
|
@ -628,8 +620,7 @@ struct cons_pointer subtract_2( struct stack_frame *frame,
|
||||||
to_long_double( arg2 ) );
|
to_long_double( arg2 ) );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = throw_exception( c_string_to_lisp_symbol( L"-" ),
|
result = throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Cannot subtract: not a number" ),
|
( L"Cannot subtract: not a number" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
break;
|
break;
|
||||||
|
|
@ -659,8 +650,7 @@ struct cons_pointer subtract_2( struct stack_frame *frame,
|
||||||
to_long_double( arg2 ) );
|
to_long_double( arg2 ) );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = throw_exception( c_string_to_lisp_symbol( L"-" ),
|
result = throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Cannot subtract: not a number" ),
|
( L"Cannot subtract: not a number" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
break;
|
break;
|
||||||
|
|
@ -671,8 +661,7 @@ struct cons_pointer subtract_2( struct stack_frame *frame,
|
||||||
make_real( to_long_double( arg1 ) - to_long_double( arg2 ) );
|
make_real( to_long_double( arg1 ) - to_long_double( arg2 ) );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = throw_exception( c_string_to_lisp_symbol( L"-" ),
|
result = throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Cannot subtract: not a number" ),
|
( L"Cannot subtract: not a number" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
break;
|
break;
|
||||||
|
|
@ -743,8 +732,7 @@ struct cons_pointer lisp_divide( struct
|
||||||
to_long_double( frame->arg[1] ) );
|
to_long_double( frame->arg[1] ) );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = throw_exception( c_string_to_lisp_symbol( L"/" ),
|
result = throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Cannot divide: not a number" ),
|
( L"Cannot divide: not a number" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
break;
|
break;
|
||||||
|
|
@ -774,8 +762,7 @@ struct cons_pointer lisp_divide( struct
|
||||||
to_long_double( frame->arg[1] ) );
|
to_long_double( frame->arg[1] ) );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = throw_exception( c_string_to_lisp_symbol( L"/" ),
|
result = throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Cannot divide: not a number" ),
|
( L"Cannot divide: not a number" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
break;
|
break;
|
||||||
|
|
@ -787,8 +774,7 @@ struct cons_pointer lisp_divide( struct
|
||||||
to_long_double( frame->arg[1] ) );
|
to_long_double( frame->arg[1] ) );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = throw_exception( c_string_to_lisp_symbol( L"/" ),
|
result = throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Cannot divide: not a number" ),
|
( L"Cannot divide: not a number" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -114,8 +114,7 @@ struct cons_pointer add_ratio_ratio( struct cons_pointer arg1,
|
||||||
cell1->payload.ratio.divisor ) );
|
cell1->payload.ratio.divisor ) );
|
||||||
r = make_ratio( dividend, divisor, true );
|
r = make_ratio( dividend, divisor, true );
|
||||||
} else {
|
} else {
|
||||||
r = throw_exception( c_string_to_lisp_symbol( L"+" ),
|
r = throw_exception( make_cons( c_string_to_lisp_string
|
||||||
make_cons( c_string_to_lisp_string
|
|
||||||
( L"Shouldn't happen: bad arg to add_ratio_ratio" ),
|
( L"Shouldn't happen: bad arg to add_ratio_ratio" ),
|
||||||
make_cons( arg1,
|
make_cons( arg1,
|
||||||
make_cons( arg2, NIL ) ) ),
|
make_cons( arg2, NIL ) ) ),
|
||||||
|
|
@ -155,8 +154,7 @@ struct cons_pointer add_integer_ratio( struct cons_pointer intarg,
|
||||||
dec_ref( ratio );
|
dec_ref( ratio );
|
||||||
} else {
|
} else {
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"+" ),
|
throw_exception( make_cons( c_string_to_lisp_string
|
||||||
make_cons( c_string_to_lisp_string
|
|
||||||
( L"Shouldn't happen: bad arg to add_integer_ratio" ),
|
( L"Shouldn't happen: bad arg to add_integer_ratio" ),
|
||||||
make_cons( intarg,
|
make_cons( intarg,
|
||||||
make_cons( ratarg,
|
make_cons( ratarg,
|
||||||
|
|
@ -236,8 +234,7 @@ struct cons_pointer multiply_ratio_ratio( struct
|
||||||
release_integer( divisor );
|
release_integer( divisor );
|
||||||
} else {
|
} else {
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"*" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Shouldn't happen: bad arg to multiply_ratio_ratio" ),
|
( L"Shouldn't happen: bad arg to multiply_ratio_ratio" ),
|
||||||
NIL );
|
NIL );
|
||||||
}
|
}
|
||||||
|
|
@ -272,8 +269,7 @@ struct cons_pointer multiply_integer_ratio( struct cons_pointer intarg,
|
||||||
release_integer( one );
|
release_integer( one );
|
||||||
} else {
|
} else {
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"*" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Shouldn't happen: bad arg to multiply_integer_ratio" ),
|
( L"Shouldn't happen: bad arg to multiply_integer_ratio" ),
|
||||||
NIL );
|
NIL );
|
||||||
}
|
}
|
||||||
|
|
@ -341,8 +337,7 @@ struct cons_pointer make_ratio( struct cons_pointer dividend,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"make_ratio" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Dividend and divisor of a ratio must be integers" ),
|
( L"Dividend and divisor of a ratio must be integers" ),
|
||||||
NIL );
|
NIL );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
src/debug.c
19
src/debug.c
|
|
@ -32,25 +32,6 @@
|
||||||
*/
|
*/
|
||||||
int verbosity = 0;
|
int verbosity = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* When debugging, we want to see exceptions as they happen, because they may
|
|
||||||
* not make their way back down the stack to whatever is expected to handle
|
|
||||||
* them.
|
|
||||||
*/
|
|
||||||
void debug_print_exception( struct cons_pointer ex_ptr ) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
if ( ( verbosity != 0 ) && exceptionp( ex_ptr ) ) {
|
|
||||||
fwide( stderr, 1 );
|
|
||||||
fputws( L"EXCEPTION: ", stderr );
|
|
||||||
|
|
||||||
URL_FILE *ustderr = file_to_url_file( stderr );
|
|
||||||
fwide( stderr, 1 );
|
|
||||||
print( ustderr, ex_ptr );
|
|
||||||
free( ustderr );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief print this debug `message` to stderr, if `verbosity` matches `level`.
|
* @brief print this debug `message` to stderr, if `verbosity` matches `level`.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,6 @@
|
||||||
|
|
||||||
extern int verbosity;
|
extern int verbosity;
|
||||||
|
|
||||||
void debug_print_exception( struct cons_pointer ex_ptr );
|
|
||||||
void debug_print( wchar_t *message, int level );
|
void debug_print( wchar_t *message, int level );
|
||||||
void debug_print_128bit( __int128_t n, int level );
|
void debug_print_128bit( __int128_t n, int level );
|
||||||
void debug_println( int level );
|
void debug_println( int level );
|
||||||
|
|
|
||||||
18
src/init.c
18
src/init.c
|
|
@ -84,18 +84,12 @@ void maybe_bind_init_symbols( ) {
|
||||||
if ( nilp( privileged_symbol_nil ) ) {
|
if ( nilp( privileged_symbol_nil ) ) {
|
||||||
privileged_symbol_nil = c_string_to_lisp_symbol( L"nil" );
|
privileged_symbol_nil = c_string_to_lisp_symbol( L"nil" );
|
||||||
}
|
}
|
||||||
|
if ( nilp( privileged_string_memory_exhausted ) ) {
|
||||||
// we can't make this string when we need it, because memory is then
|
// we can't make this string when we need it, because memory is then
|
||||||
// exhausted!
|
// exhausted!
|
||||||
if ( nilp( privileged_string_memory_exhausted ) ) {
|
|
||||||
privileged_string_memory_exhausted =
|
privileged_string_memory_exhausted =
|
||||||
c_string_to_lisp_string( L"Memory exhausted." );
|
c_string_to_lisp_string( L"Memory exhausted." );
|
||||||
}
|
}
|
||||||
if ( nilp( privileged_keyword_location ) ) {
|
|
||||||
privileged_keyword_location = c_string_to_lisp_keyword( L"location" );
|
|
||||||
}
|
|
||||||
if ( nilp( privileged_keyword_payload ) ) {
|
|
||||||
privileged_keyword_payload = c_string_to_lisp_keyword( L"payload" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_init_symbols( ) {
|
void free_init_symbols( ) {
|
||||||
|
|
@ -293,8 +287,6 @@ int main( int argc, char *argv[] ) {
|
||||||
*/
|
*/
|
||||||
bind_symbol_value( privileged_symbol_nil, NIL, true );
|
bind_symbol_value( privileged_symbol_nil, NIL, true );
|
||||||
bind_value( L"t", TRUE, true );
|
bind_value( L"t", TRUE, true );
|
||||||
bind_symbol_value( privileged_keyword_location, TRUE, true );
|
|
||||||
bind_symbol_value( privileged_keyword_payload, TRUE, true );
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* standard input, output, error and sink streams
|
* standard input, output, error and sink streams
|
||||||
|
|
@ -325,7 +317,7 @@ int main( int argc, char *argv[] ) {
|
||||||
( c_string_to_lisp_keyword
|
( c_string_to_lisp_keyword
|
||||||
( L"url" ),
|
( L"url" ),
|
||||||
c_string_to_lisp_string
|
c_string_to_lisp_string
|
||||||
( L"system:standard output" ) ),
|
( L"system:standard output]" ) ),
|
||||||
NIL ) ), false );
|
NIL ) ), false );
|
||||||
bind_value( L"*log*",
|
bind_value( L"*log*",
|
||||||
make_write_stream( file_to_url_file( stderr ),
|
make_write_stream( file_to_url_file( stderr ),
|
||||||
|
|
@ -409,14 +401,10 @@ int main( int argc, char *argv[] ) {
|
||||||
bind_function( L"inspect",
|
bind_function( L"inspect",
|
||||||
L"`(inspect object ouput-stream)`: Print details of this `object` to this `output-stream` or `*out*`.",
|
L"`(inspect object ouput-stream)`: Print details of this `object` to this `output-stream` or `*out*`.",
|
||||||
&lisp_inspect );
|
&lisp_inspect );
|
||||||
bind_function( L"interned?",
|
|
||||||
L"`(interned? key store)`: Return `t` if the symbol or keyword `key` is bound in this `store`, else `nil`.",
|
|
||||||
&lisp_internedp );
|
|
||||||
bind_function( L"keys",
|
bind_function( L"keys",
|
||||||
L"`(keys store)`: Return a list of all keys in this `store`.",
|
L"`(keys store)`: Return a list of all keys in this `store`.",
|
||||||
&lisp_keys );
|
&lisp_keys );
|
||||||
bind_function( L"list",
|
bind_function( L"list", L"`(list args...): Return a list of these `args`.",
|
||||||
L"`(list args...)`: Return a list of these `args`.",
|
|
||||||
&lisp_list );
|
&lisp_list );
|
||||||
bind_function( L"mapcar",
|
bind_function( L"mapcar",
|
||||||
L"`(mapcar function sequence)`: Apply `function` to each element of `sequence` in turn, and return a sequence of the results.",
|
L"`(mapcar function sequence)`: Apply `function` to each element of `sequence` in turn, and return a sequence of the results.",
|
||||||
|
|
|
||||||
|
|
@ -508,8 +508,8 @@ lisp_read_char( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
if ( readp( frame->arg[0] ) ) {
|
if ( readp( frame->arg[0] ) ) {
|
||||||
result =
|
result =
|
||||||
make_string( url_fgetwc
|
make_string( url_fgetwc
|
||||||
( pointer2cell( frame->arg[0] ).payload.stream.
|
( pointer2cell( frame->arg[0] ).payload.
|
||||||
stream ), NIL );
|
stream.stream ), NIL );
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ void print_map( URL_FILE *output, struct cons_pointer map ) {
|
||||||
struct cons_pointer key = c_car( ks );
|
struct cons_pointer key = c_car( ks );
|
||||||
print( output, key );
|
print( output, key );
|
||||||
url_fputwc( btowc( ' ' ), output );
|
url_fputwc( btowc( ' ' ), output );
|
||||||
print( output, hashmap_get( map, key, false ) );
|
print( output, hashmap_get( map, key ) );
|
||||||
|
|
||||||
if ( !nilp( c_cdr( ks ) ) ) {
|
if ( !nilp( c_cdr( ks ) ) ) {
|
||||||
url_fputws( L", ", output );
|
url_fputws( L", ", output );
|
||||||
|
|
@ -348,9 +348,16 @@ lisp_println( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
|
|
||||||
if ( writep( out_stream ) ) {
|
if ( writep( out_stream ) ) {
|
||||||
output = pointer2cell( out_stream ).payload.stream.stream;
|
output = pointer2cell( out_stream ).payload.stream.stream;
|
||||||
|
inc_ref( out_stream );
|
||||||
|
} else {
|
||||||
|
output = file_to_url_file( stderr );
|
||||||
|
}
|
||||||
|
|
||||||
println( output );
|
println( output );
|
||||||
|
|
||||||
|
if ( writep( out_stream ) ) {
|
||||||
|
dec_ref( out_stream );
|
||||||
|
} else {
|
||||||
free( output );
|
free( output );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -167,8 +167,7 @@ struct cons_pointer read_continuation( struct stack_frame *frame,
|
||||||
|
|
||||||
if ( url_feof( input ) ) {
|
if ( url_feof( input ) ) {
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"read" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"End of file while reading" ), frame_pointer );
|
( L"End of file while reading" ), frame_pointer );
|
||||||
} else {
|
} else {
|
||||||
switch ( c ) {
|
switch ( c ) {
|
||||||
|
|
@ -178,8 +177,7 @@ struct cons_pointer read_continuation( struct stack_frame *frame,
|
||||||
/* skip all characters from semi-colon to the end of the line */
|
/* skip all characters from semi-colon to the end of the line */
|
||||||
break;
|
break;
|
||||||
case EOF:
|
case EOF:
|
||||||
result = throw_exception( c_string_to_lisp_symbol( L"read" ),
|
result = throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"End of input while reading" ),
|
( L"End of input while reading" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
break;
|
break;
|
||||||
|
|
@ -268,8 +266,7 @@ struct cons_pointer read_continuation( struct stack_frame *frame,
|
||||||
result = read_symbol_or_key( input, SYMBOLTV, c );
|
result = read_symbol_or_key( input, SYMBOLTV, c );
|
||||||
} else {
|
} else {
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"read" ),
|
throw_exception( make_cons( c_string_to_lisp_string
|
||||||
make_cons( c_string_to_lisp_string
|
|
||||||
( L"Unrecognised start of input character" ),
|
( L"Unrecognised start of input character" ),
|
||||||
make_string( c, NIL ) ),
|
make_string( c, NIL ) ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
|
|
@ -316,8 +313,7 @@ struct cons_pointer read_number( struct stack_frame *frame,
|
||||||
switch ( c ) {
|
switch ( c ) {
|
||||||
case LPERIOD:
|
case LPERIOD:
|
||||||
if ( seen_period || !nilp( dividend ) ) {
|
if ( seen_period || !nilp( dividend ) ) {
|
||||||
return throw_exception( c_string_to_lisp_symbol( L"read" ),
|
return throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Malformed number: too many periods" ),
|
( L"Malformed number: too many periods" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -328,8 +324,7 @@ struct cons_pointer read_number( struct stack_frame *frame,
|
||||||
break;
|
break;
|
||||||
case LSLASH:
|
case LSLASH:
|
||||||
if ( seen_period || !nilp( dividend ) ) {
|
if ( seen_period || !nilp( dividend ) ) {
|
||||||
return throw_exception( c_string_to_lisp_symbol( L"read" ),
|
return throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Malformed number: dividend of rational must be integer" ),
|
( L"Malformed number: dividend of rational must be integer" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -250,9 +250,8 @@ struct cons_pointer allocate_cell( uint32_t tag ) {
|
||||||
total_cells_allocated++;
|
total_cells_allocated++;
|
||||||
|
|
||||||
debug_printf( DEBUG_ALLOC,
|
debug_printf( DEBUG_ALLOC,
|
||||||
L"Allocated cell of type %4.4s at %u, %u \n",
|
L"Allocated cell of type '%4.4s' at %d, %d \n",
|
||||||
( ( char * ) cell->tag.bytes ), result.page,
|
cell->tag.bytes, result.page, result.offset );
|
||||||
result.offset );
|
|
||||||
} else {
|
} else {
|
||||||
debug_printf( DEBUG_ALLOC, L"WARNING: Allocating non-free cell!" );
|
debug_printf( DEBUG_ALLOC, L"WARNING: Allocating non-free cell!" );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,18 +27,6 @@
|
||||||
#include "memory/vectorspace.h"
|
#include "memory/vectorspace.h"
|
||||||
#include "ops/intern.h"
|
#include "ops/intern.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* Keywords used when constructing exceptions: `:location`. Instantiated in
|
|
||||||
* `init.c`q.v.
|
|
||||||
*/
|
|
||||||
struct cons_pointer privileged_keyword_location = NIL;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Keywords used when constructing exceptions: `:payload`. Instantiated in
|
|
||||||
* `init.c`, q.v.
|
|
||||||
*/
|
|
||||||
struct cons_pointer privileged_keyword_payload = NIL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the value of the tag on the cell at this `pointer` is this `value`,
|
* True if the value of the tag on the cell at this `pointer` is this `value`,
|
||||||
* or, if the tag of the cell is `VECP`, if the value of the tag of the
|
* or, if the tag of the cell is `VECP`, if the value of the tag of the
|
||||||
|
|
@ -47,11 +35,11 @@ struct cons_pointer privileged_keyword_payload = NIL;
|
||||||
bool check_tag( struct cons_pointer pointer, uint32_t value ) {
|
bool check_tag( struct cons_pointer pointer, uint32_t value ) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
struct cons_space_object *cell = &pointer2cell( pointer );
|
struct cons_space_object cell = pointer2cell( pointer );
|
||||||
result = cell->tag.value == value;
|
result = cell.tag.value == value;
|
||||||
|
|
||||||
if ( result == false ) {
|
if ( result == false ) {
|
||||||
if ( cell->tag.value == VECTORPOINTTV ) {
|
if ( cell.tag.value == VECTORPOINTTV ) {
|
||||||
struct vector_space_object *vec = pointer_to_vso( pointer );
|
struct vector_space_object *vec = pointer_to_vso( pointer );
|
||||||
|
|
||||||
if ( vec != NULL ) {
|
if ( vec != NULL ) {
|
||||||
|
|
@ -78,7 +66,7 @@ struct cons_pointer inc_ref( struct cons_pointer pointer ) {
|
||||||
cell->count++;
|
cell->count++;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
debug_printf( DEBUG_ALLOC,
|
debug_printf( DEBUG_ALLOC,
|
||||||
L"\nIncremented cell of type %4.4s at page %u, offset %u to count %u",
|
L"\nIncremented cell of type %4.4s at page %d, offset %d to count %d",
|
||||||
( ( char * ) cell->tag.bytes ), pointer.page,
|
( ( char * ) cell->tag.bytes ), pointer.page,
|
||||||
pointer.offset, cell->count );
|
pointer.offset, cell->count );
|
||||||
if ( strncmp( cell->tag.bytes, VECTORPOINTTAG, TAGLENGTH ) == 0 ) {
|
if ( strncmp( cell->tag.bytes, VECTORPOINTTAG, TAGLENGTH ) == 0 ) {
|
||||||
|
|
@ -131,19 +119,6 @@ struct cons_pointer dec_ref( struct cons_pointer pointer ) {
|
||||||
return pointer;
|
return pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* given a cons_pointer as argument, return the tag.
|
|
||||||
*/
|
|
||||||
uint32_t get_tag_value( struct cons_pointer pointer ) {
|
|
||||||
uint32_t result = pointer2cell( pointer ).tag.value;
|
|
||||||
|
|
||||||
if ( result == VECTORPOINTTV ) {
|
|
||||||
result = pointer_to_vso( pointer )->header.tag.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Lisp type of the single argument.
|
* Get the Lisp type of the single argument.
|
||||||
* @param pointer a pointer to the object whose type is requested.
|
* @param pointer a pointer to the object whose type is requested.
|
||||||
|
|
@ -412,15 +387,15 @@ struct cons_pointer make_symbol_or_key( wint_t c, struct cons_pointer tail,
|
||||||
if ( tag == SYMBOLTV || tag == KEYTV ) {
|
if ( tag == SYMBOLTV || tag == KEYTV ) {
|
||||||
result = make_string_like_thing( c, tail, tag );
|
result = make_string_like_thing( c, tail, tag );
|
||||||
|
|
||||||
// if ( tag == KEYTV ) {
|
if ( tag == KEYTV ) {
|
||||||
// struct cons_pointer r = interned( result, oblist );
|
struct cons_pointer r = internedp( result, oblist );
|
||||||
|
|
||||||
// if ( nilp( r ) ) {
|
if ( nilp( r ) ) {
|
||||||
// intern( result, oblist );
|
intern( result, oblist );
|
||||||
// } else {
|
} else {
|
||||||
// result = r;
|
result = r;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
} else {
|
} else {
|
||||||
result =
|
result =
|
||||||
make_exception( c_string_to_lisp_string
|
make_exception( c_string_to_lisp_string
|
||||||
|
|
|
||||||
|
|
@ -56,18 +56,6 @@
|
||||||
*/
|
*/
|
||||||
#define EXCEPTIONTV 1346721861
|
#define EXCEPTIONTV 1346721861
|
||||||
|
|
||||||
/**
|
|
||||||
* Keywords used when constructing exceptions: `:location`. Instantiated in
|
|
||||||
* `init.c`.
|
|
||||||
*/
|
|
||||||
extern struct cons_pointer privileged_keyword_location;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Keywords used when constructing exceptions: `:payload`. Instantiated in
|
|
||||||
* `init.c`.
|
|
||||||
*/
|
|
||||||
extern struct cons_pointer privileged_keyword_payload;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An unallocated cell on the free list - should never be encountered by a Lisp
|
* An unallocated cell on the free list - should never be encountered by a Lisp
|
||||||
* function.
|
* function.
|
||||||
|
|
@ -722,11 +710,6 @@ struct cons_pointer inc_ref( struct cons_pointer pointer );
|
||||||
|
|
||||||
struct cons_pointer dec_ref( struct cons_pointer pointer );
|
struct cons_pointer dec_ref( struct cons_pointer pointer );
|
||||||
|
|
||||||
/**
|
|
||||||
* given a cons_pointer as argument, return the tag.
|
|
||||||
*/
|
|
||||||
uint32_t get_tag_value( struct cons_pointer pointer );
|
|
||||||
|
|
||||||
struct cons_pointer c_type( struct cons_pointer pointer );
|
struct cons_pointer c_type( struct cons_pointer pointer );
|
||||||
|
|
||||||
struct cons_pointer c_car( struct cons_pointer arg );
|
struct cons_pointer c_car( struct cons_pointer arg );
|
||||||
|
|
|
||||||
|
|
@ -114,10 +114,10 @@ void dump_object( URL_FILE *output, struct cons_pointer pointer ) {
|
||||||
case RATIOTV:
|
case RATIOTV:
|
||||||
url_fwprintf( output,
|
url_fwprintf( output,
|
||||||
L"\t\tRational cell: value %ld/%ld, count %u\n",
|
L"\t\tRational cell: value %ld/%ld, count %u\n",
|
||||||
pointer2cell( cell.payload.ratio.dividend ).payload.
|
pointer2cell( cell.payload.ratio.dividend ).
|
||||||
integer.value,
|
payload.integer.value,
|
||||||
pointer2cell( cell.payload.ratio.divisor ).payload.
|
pointer2cell( cell.payload.ratio.divisor ).
|
||||||
integer.value, cell.count );
|
payload.integer.value, cell.count );
|
||||||
break;
|
break;
|
||||||
case READTV:
|
case READTV:
|
||||||
url_fputws( L"\t\tInput stream; metadata: ", output );
|
url_fputws( L"\t\tInput stream; metadata: ", output );
|
||||||
|
|
|
||||||
|
|
@ -161,10 +161,6 @@ struct cons_pointer make_stack_frame( struct cons_pointer previous,
|
||||||
env );
|
env );
|
||||||
frame->more = more;
|
frame->more = more;
|
||||||
inc_ref( more );
|
inc_ref( more );
|
||||||
|
|
||||||
for ( ; !nilp( args ); args = c_cdr( args ) ) {
|
|
||||||
frame->args++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug_print( L"make_stack_frame: returning\n", DEBUG_STACK );
|
debug_print( L"make_stack_frame: returning\n", DEBUG_STACK );
|
||||||
|
|
|
||||||
|
|
@ -272,9 +272,7 @@ bool equal_map_map( struct cons_pointer a, struct cons_pointer b ) {
|
||||||
|
|
||||||
for ( struct cons_pointer i = keys_a; !nilp( i ); i = c_cdr( i ) ) {
|
for ( struct cons_pointer i = keys_a; !nilp( i ); i = c_cdr( i ) ) {
|
||||||
struct cons_pointer key = c_car( i );
|
struct cons_pointer key = c_car( i );
|
||||||
if ( !equal
|
if ( !equal( hashmap_get( a, key ), hashmap_get( b, key ) ) ) {
|
||||||
( hashmap_get( a, key, false ),
|
|
||||||
hashmap_get( b, key, false ) ) ) {
|
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -377,7 +375,8 @@ bool equal( struct cons_pointer a, struct cons_pointer b ) {
|
||||||
memset( a_buff, 0, sizeof( a_buff ) );
|
memset( a_buff, 0, sizeof( a_buff ) );
|
||||||
memset( b_buff, 0, sizeof( b_buff ) );
|
memset( b_buff, 0, sizeof( b_buff ) );
|
||||||
|
|
||||||
for ( ; ( i < ( STRING_SHIPYARD_SIZE - 1 ) ) && !nilp( a )
|
for ( ;
|
||||||
|
( i < ( STRING_SHIPYARD_SIZE - 1 ) ) && !nilp( a )
|
||||||
&& !nilp( b ); i++ ) {
|
&& !nilp( b ); i++ ) {
|
||||||
a_buff[i] = cell_a->payload.string.character;
|
a_buff[i] = cell_a->payload.string.character;
|
||||||
a = c_cdr( a );
|
a = c_cdr( a );
|
||||||
|
|
|
||||||
267
src/ops/intern.c
267
src/ops/intern.c
|
|
@ -205,7 +205,7 @@ struct cons_pointer hashmap_put_all( struct cons_pointer mapp,
|
||||||
for ( struct cons_pointer keys = hashmap_keys( assoc );
|
for ( struct cons_pointer keys = hashmap_keys( assoc );
|
||||||
!nilp( keys ); keys = c_cdr( keys ) ) {
|
!nilp( keys ); keys = c_cdr( keys ) ) {
|
||||||
struct cons_pointer key = c_car( keys );
|
struct cons_pointer key = c_car( keys );
|
||||||
hashmap_put( mapp, key, hashmap_get( assoc, key, false ) );
|
hashmap_put( mapp, key, hashmap_get( assoc, key ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -216,33 +216,17 @@ struct cons_pointer hashmap_put_all( struct cons_pointer mapp,
|
||||||
/** Get a value from a hashmap.
|
/** Get a value from a hashmap.
|
||||||
*
|
*
|
||||||
* Note that this is here, rather than in memory/hashmap.c, because it is
|
* Note that this is here, rather than in memory/hashmap.c, because it is
|
||||||
* closely tied in with search_store, q.v.
|
* closely tied in with c_assoc, q.v.
|
||||||
*/
|
*/
|
||||||
struct cons_pointer hashmap_get( struct cons_pointer mapp,
|
struct cons_pointer hashmap_get( struct cons_pointer mapp,
|
||||||
struct cons_pointer key, bool return_key ) {
|
struct cons_pointer key ) {
|
||||||
#ifdef DEBUG
|
|
||||||
debug_print( L"\nhashmap_get: key is `", DEBUG_BIND );
|
|
||||||
debug_print_object( key, DEBUG_BIND );
|
|
||||||
debug_print( L"`; store of type `", DEBUG_BIND );
|
|
||||||
debug_print_object( c_type( mapp ), DEBUG_BIND );
|
|
||||||
debug_printf( DEBUG_BIND, L"`; returning `%s`.\n",
|
|
||||||
return_key ? "key" : "value" );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
if ( hashmapp( mapp ) && truep( authorised( mapp, NIL ) ) && !nilp( key ) ) {
|
if ( hashmapp( mapp ) && truep( authorised( mapp, NIL ) ) && !nilp( key ) ) {
|
||||||
struct vector_space_object *map = pointer_to_vso( mapp );
|
struct vector_space_object *map = pointer_to_vso( mapp );
|
||||||
uint32_t bucket_no = get_hash( key ) % map->payload.hashmap.n_buckets;
|
uint32_t bucket_no = get_hash( key ) % map->payload.hashmap.n_buckets;
|
||||||
|
|
||||||
result =
|
result = c_assoc( key, map->payload.hashmap.buckets[bucket_no] );
|
||||||
search_store( key, map->payload.hashmap.buckets[bucket_no],
|
|
||||||
return_key );
|
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
|
||||||
debug_print( L"\nhashmap_get returning: `", DEBUG_BIND );
|
|
||||||
debug_print_object( result, DEBUG_BIND );
|
|
||||||
debug_print( L"`\n", DEBUG_BIND );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -283,146 +267,57 @@ struct cons_pointer clone_hashmap( struct cons_pointer ptr ) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (keys set let quote read equal *out* *log* oblist cons source cond close meta mapcar negative? open subtract eval nλ *in* *sink* cdr set! reverse slurp try assoc eq add list time car t *prompt* absolute append apply divide exception get-hash hashmap inspect metadata multiply print put! put-all! read-char repl throw type + * - / = lambda λ nlambda progn)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief `(search-store key store return-key?)` Search this `store` for this
|
* Implementation of interned? in C. The final implementation if interned? will
|
||||||
* a key lexically identical to this `key`.
|
* deal with stores which can be association lists or hashtables or hybrids of
|
||||||
|
* the two, but that will almost certainly be implemented in lisp.
|
||||||
*
|
*
|
||||||
* If found, then, if `return-key?` is non-nil, return the copy found in the
|
* If this key is lexically identical to a key in this store, return the key
|
||||||
* `store`, else return the value associated with it.
|
* from the store (so that later when we want to retrieve a value, an eq test
|
||||||
*
|
* will work); otherwise return NIL.
|
||||||
* At this stage the following structures are legal stores:
|
|
||||||
* 1. an association list comprising (key . value) dotted pairs;
|
|
||||||
* 2. a hashmap;
|
|
||||||
* 3. a namespace (which for these purposes is identical to a hashmap);
|
|
||||||
* 4. a hybrid list comprising both (key . value) pairs and hashmaps as first
|
|
||||||
* level items;
|
|
||||||
* 5. such a hybrid list, but where the last CDR pointer is to a hashmap
|
|
||||||
* rather than to a cons sell or to `nil`.
|
|
||||||
*
|
|
||||||
* This is over-complex and type 5 should be disallowed, but it will do for
|
|
||||||
* now.
|
|
||||||
*/
|
*/
|
||||||
struct cons_pointer search_store( struct cons_pointer key,
|
struct cons_pointer
|
||||||
struct cons_pointer store,
|
internedp( struct cons_pointer key, struct cons_pointer store ) {
|
||||||
bool return_key ) {
|
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
debug_print( L"\nsearch_store; key is `", DEBUG_BIND );
|
|
||||||
debug_print_object( key, DEBUG_BIND );
|
|
||||||
debug_print( L"`; store of type `", DEBUG_BIND );
|
|
||||||
debug_print_object( c_type( store ), DEBUG_BIND );
|
|
||||||
debug_printf( DEBUG_BIND, L"`; returning `%s`.\n",
|
|
||||||
return_key ? "key" : "value" );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ( symbolp( key ) || keywordp( key ) ) {
|
if ( symbolp( key ) || keywordp( key ) ) {
|
||||||
struct cons_space_object *store_cell = &pointer2cell( store );
|
// TODO: I see what I was doing here and it would be the right thing to
|
||||||
|
// do for stores which are old-fashioned assoc lists, but it will not work
|
||||||
|
// for my new hybrid stores.
|
||||||
|
// for ( struct cons_pointer next = store;
|
||||||
|
// nilp( result ) && consp( next );
|
||||||
|
// next = pointer2cell( next ).payload.cons.cdr ) {
|
||||||
|
// struct cons_space_object entry =
|
||||||
|
// pointer2cell( pointer2cell( next ).payload.cons.car );
|
||||||
|
|
||||||
switch ( get_tag_value( store ) ) {
|
// debug_print( L"Internedp: checking whether `", DEBUG_BIND );
|
||||||
case CONSTV:
|
// debug_print_object( key, DEBUG_BIND );
|
||||||
for ( struct cons_pointer cursor = store;
|
// debug_print( L"` equals `", DEBUG_BIND );
|
||||||
nilp( result ) && ( consp( cursor )
|
// debug_print_object( entry.payload.cons.car, DEBUG_BIND );
|
||||||
|| hashmapp( cursor ) );
|
// debug_print( L"`\n", DEBUG_BIND );
|
||||||
cursor = pointer2cell( cursor ).payload.cons.cdr ) {
|
|
||||||
switch ( get_tag_value( cursor ) ) {
|
|
||||||
case CONSTV:
|
|
||||||
struct cons_pointer entry_ptr = c_car( cursor );
|
|
||||||
|
|
||||||
switch ( get_tag_value( entry_ptr ) ) {
|
// if ( equal( key, entry.payload.cons.car ) ) {
|
||||||
case CONSTV:
|
// result = entry.payload.cons.car;
|
||||||
if ( equal( key, c_car( entry_ptr ) ) ) {
|
// }
|
||||||
result =
|
if ( !nilp( c_assoc( key, store ) ) ) {
|
||||||
return_key ? c_car( entry_ptr ) :
|
result = key;
|
||||||
c_cdr( entry_ptr );
|
} else if ( equal( key, privileged_symbol_nil ) ) {
|
||||||
}
|
result = privileged_symbol_nil;
|
||||||
break;
|
|
||||||
case HASHTV:
|
|
||||||
case NAMESPACETV:
|
|
||||||
// TODO: I think this should be impossible, and we should maybe
|
|
||||||
// throw an exception.
|
|
||||||
result =
|
|
||||||
hashmap_get( entry_ptr, key,
|
|
||||||
return_key );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result =
|
|
||||||
throw_exception
|
|
||||||
( c_string_to_lisp_symbol
|
|
||||||
( L"search-store (entry)" ),
|
|
||||||
make_cons( c_string_to_lisp_string
|
|
||||||
( L"Unexpected store type: " ),
|
|
||||||
c_type( c_car
|
|
||||||
( entry_ptr ) ) ),
|
|
||||||
NIL );
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HASHTV:
|
|
||||||
case NAMESPACETV:
|
|
||||||
debug_print
|
|
||||||
( L"\n\tHashmap as top-level value in list",
|
|
||||||
DEBUG_BIND );
|
|
||||||
result = hashmap_get( cursor, key, return_key );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result =
|
|
||||||
throw_exception( c_string_to_lisp_symbol
|
|
||||||
( L"search-store (cursor)" ),
|
|
||||||
make_cons
|
|
||||||
( c_string_to_lisp_string
|
|
||||||
( L"Unexpected store type: " ),
|
|
||||||
c_type( cursor ) ), NIL );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case HASHTV:
|
|
||||||
case NAMESPACETV:
|
|
||||||
result = hashmap_get( store, key, return_key );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result =
|
|
||||||
throw_exception( c_string_to_lisp_symbol
|
|
||||||
( L"search-store (store)" ),
|
|
||||||
make_cons( c_string_to_lisp_string
|
|
||||||
( L"Unexpected store type: " ),
|
|
||||||
c_type( store ) ), NIL );
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// failing with key type NIL here (?). Probably worth dumping the stack?
|
debug_print( L"`", DEBUG_BIND );
|
||||||
result =
|
debug_print_object( key, DEBUG_BIND );
|
||||||
throw_exception( c_string_to_lisp_symbol( L"search-store (key)" ),
|
debug_print( L"` is a ", DEBUG_BIND );
|
||||||
make_cons
|
debug_printf( DEBUG_BIND, L"%4.4s",
|
||||||
( c_string_to_lisp_string
|
( char * ) pointer2cell( key ).tag.bytes );
|
||||||
( L"Unexpected key type: " ), c_type( key ) ),
|
debug_print( L", not a KEYW or SYMB", DEBUG_BIND );
|
||||||
NIL );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_print( L"search-store: returning `", DEBUG_BIND );
|
|
||||||
debug_print_object( result, DEBUG_BIND );
|
|
||||||
debug_print( L"`\n", DEBUG_BIND );
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cons_pointer interned( struct cons_pointer key,
|
|
||||||
struct cons_pointer store ) {
|
|
||||||
return search_store( key, store, true );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Implementation of `interned?` in C: predicate wrapped around interned.
|
|
||||||
*
|
|
||||||
* @param key the key to search for.
|
|
||||||
* @param store the store to search in.
|
|
||||||
* @return struct cons_pointer `t` if the key was found, else `nil`.
|
|
||||||
*/
|
|
||||||
struct cons_pointer internedp( struct cons_pointer key,
|
|
||||||
struct cons_pointer store ) {
|
|
||||||
return nilp( interned( key, store ) ) ? NIL : TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of assoc in C. Like interned?, the final implementation will
|
* Implementation of assoc in C. Like interned?, the final implementation will
|
||||||
* deal with stores which can be association lists or hashtables or hybrids of
|
* deal with stores which can be association lists or hashtables or hybrids of
|
||||||
|
|
@ -433,7 +328,65 @@ struct cons_pointer internedp( struct cons_pointer key,
|
||||||
*/
|
*/
|
||||||
struct cons_pointer c_assoc( struct cons_pointer key,
|
struct cons_pointer c_assoc( struct cons_pointer key,
|
||||||
struct cons_pointer store ) {
|
struct cons_pointer store ) {
|
||||||
return search_store( key, store, false );
|
struct cons_pointer result = NIL;
|
||||||
|
|
||||||
|
if ( !nilp( key ) ) {
|
||||||
|
if ( consp( store ) ) {
|
||||||
|
for ( struct cons_pointer next = store;
|
||||||
|
nilp( result ) && ( consp( next ) || hashmapp( next ) );
|
||||||
|
next = pointer2cell( next ).payload.cons.cdr ) {
|
||||||
|
if ( consp( next ) ) {
|
||||||
|
// #ifdef DEBUG
|
||||||
|
// debug_print( L"\nc_assoc; key is `", DEBUG_BIND );
|
||||||
|
// debug_print_object( key, DEBUG_BIND );
|
||||||
|
// debug_print( L"`\n", DEBUG_BIND );
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
struct cons_pointer entry_ptr = c_car( next );
|
||||||
|
struct cons_space_object entry = pointer2cell( entry_ptr );
|
||||||
|
|
||||||
|
switch ( entry.tag.value ) {
|
||||||
|
case CONSTV:
|
||||||
|
if ( equal( key, entry.payload.cons.car ) ) {
|
||||||
|
result = entry.payload.cons.cdr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VECTORPOINTTV:
|
||||||
|
result = hashmap_get( entry_ptr, key );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw_exception( c_append
|
||||||
|
( c_string_to_lisp_string
|
||||||
|
( L"Store entry is of unknown type: " ),
|
||||||
|
c_type( entry_ptr ) ), NIL );
|
||||||
|
}
|
||||||
|
|
||||||
|
// #ifdef DEBUG
|
||||||
|
// debug_print( L"c_assoc `", DEBUG_BIND );
|
||||||
|
// debug_print_object( key, DEBUG_BIND );
|
||||||
|
// debug_print( L"` returning: ", DEBUG_BIND );
|
||||||
|
// debug_print_object( result, DEBUG_BIND );
|
||||||
|
// debug_println( DEBUG_BIND );
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ( hashmapp( store ) ) {
|
||||||
|
result = hashmap_get( store, key );
|
||||||
|
} else if ( !nilp( store ) ) {
|
||||||
|
// #ifdef DEBUG
|
||||||
|
// debug_print( L"c_assoc; store is of unknown type `", DEBUG_BIND );
|
||||||
|
// debug_printf( DEBUG_BIND, L"%4.4s", (char *)pointer2cell(key).tag.bytes);
|
||||||
|
// debug_print( L"`\n", DEBUG_BIND );
|
||||||
|
// #endif
|
||||||
|
result =
|
||||||
|
throw_exception( c_append
|
||||||
|
( c_string_to_lisp_string
|
||||||
|
( L"Store is of unknown type: " ),
|
||||||
|
c_type( store ) ), NIL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -461,15 +414,11 @@ struct cons_pointer hashmap_put( struct cons_pointer mapp,
|
||||||
map->payload.hashmap.buckets[bucket_no] );
|
map->payload.hashmap.buckets[bucket_no] );
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_print( L"hashmap_put:\n", DEBUG_BIND );
|
|
||||||
debug_dump_object( mapp, DEBUG_BIND );
|
|
||||||
|
|
||||||
return mapp;
|
return mapp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this store is modifiable, add this key value pair to it. Otherwise,
|
* Return a new key/value store containing all the key/value pairs in this
|
||||||
* return a new key/value store containing all the key/value pairs in this
|
|
||||||
* store with this key/value pair added to the front.
|
* store with this key/value pair added to the front.
|
||||||
*/
|
*/
|
||||||
struct cons_pointer set( struct cons_pointer key, struct cons_pointer value,
|
struct cons_pointer set( struct cons_pointer key, struct cons_pointer value,
|
||||||
|
|
@ -477,7 +426,7 @@ struct cons_pointer set( struct cons_pointer key, struct cons_pointer value,
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
bool deep = eq( store, oblist );
|
bool deep = vectorpointp( store );
|
||||||
debug_print_binding( key, value, deep, DEBUG_BIND );
|
debug_print_binding( key, value, deep, DEBUG_BIND );
|
||||||
|
|
||||||
if ( deep ) {
|
if ( deep ) {
|
||||||
|
|
@ -485,7 +434,9 @@ struct cons_pointer set( struct cons_pointer key, struct cons_pointer value,
|
||||||
pointer2cell( store ).payload.vectorp.tag.bytes );
|
pointer2cell( store ).payload.vectorp.tag.bytes );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if ( nilp( store ) || consp( store ) ) {
|
if ( nilp( value ) ) {
|
||||||
|
result = store;
|
||||||
|
} else if ( nilp( store ) || consp( store ) ) {
|
||||||
result = make_cons( make_cons( key, value ), store );
|
result = make_cons( make_cons( key, value ), store );
|
||||||
} else if ( hashmapp( store ) ) {
|
} else if ( hashmapp( store ) ) {
|
||||||
result = hashmap_put( store, key, value );
|
result = hashmap_put( store, key, value );
|
||||||
|
|
@ -501,8 +452,16 @@ struct cons_pointer
|
||||||
deep_bind( struct cons_pointer key, struct cons_pointer value ) {
|
deep_bind( struct cons_pointer key, struct cons_pointer value ) {
|
||||||
debug_print( L"Entering deep_bind\n", DEBUG_BIND );
|
debug_print( L"Entering deep_bind\n", DEBUG_BIND );
|
||||||
|
|
||||||
|
struct cons_pointer old = oblist;
|
||||||
|
|
||||||
oblist = set( key, value, oblist );
|
oblist = set( key, value, oblist );
|
||||||
|
|
||||||
|
// The oblist is not now an assoc list, and I don't think it will be again.
|
||||||
|
// if ( consp( oblist ) ) {
|
||||||
|
// inc_ref( oblist );
|
||||||
|
// dec_ref( old );
|
||||||
|
// }
|
||||||
|
|
||||||
debug_print( L"deep_bind returning ", DEBUG_BIND );
|
debug_print( L"deep_bind returning ", DEBUG_BIND );
|
||||||
debug_print_object( key, DEBUG_BIND );
|
debug_print_object( key, DEBUG_BIND );
|
||||||
debug_println( DEBUG_BIND );
|
debug_println( DEBUG_BIND );
|
||||||
|
|
@ -521,7 +480,7 @@ intern( struct cons_pointer key, struct cons_pointer environment ) {
|
||||||
struct cons_pointer canonical = internedp( key, environment );
|
struct cons_pointer canonical = internedp( key, environment );
|
||||||
if ( nilp( canonical ) ) {
|
if ( nilp( canonical ) ) {
|
||||||
/*
|
/*
|
||||||
* not currently bound. TODO: this should bind to NIL?
|
* not currently bound
|
||||||
*/
|
*/
|
||||||
result = set( key, TRUE, environment );
|
result = set( key, TRUE, environment );
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,6 @@
|
||||||
#ifndef __intern_h
|
#ifndef __intern_h
|
||||||
#define __intern_h
|
#define __intern_h
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
|
|
||||||
extern struct cons_pointer privileged_symbol_nil;
|
extern struct cons_pointer privileged_symbol_nil;
|
||||||
|
|
||||||
extern struct cons_pointer oblist;
|
extern struct cons_pointer oblist;
|
||||||
|
|
@ -34,7 +31,7 @@ void free_hashmap( struct cons_pointer ptr );
|
||||||
void dump_map( URL_FILE * output, struct cons_pointer pointer );
|
void dump_map( URL_FILE * output, struct cons_pointer pointer );
|
||||||
|
|
||||||
struct cons_pointer hashmap_get( struct cons_pointer mapp,
|
struct cons_pointer hashmap_get( struct cons_pointer mapp,
|
||||||
struct cons_pointer key, bool return_key );
|
struct cons_pointer key );
|
||||||
|
|
||||||
struct cons_pointer hashmap_put( struct cons_pointer mapp,
|
struct cons_pointer hashmap_put( struct cons_pointer mapp,
|
||||||
struct cons_pointer key,
|
struct cons_pointer key,
|
||||||
|
|
@ -49,18 +46,15 @@ struct cons_pointer make_hashmap( uint32_t n_buckets,
|
||||||
struct cons_pointer hash_fn,
|
struct cons_pointer hash_fn,
|
||||||
struct cons_pointer write_acl );
|
struct cons_pointer write_acl );
|
||||||
|
|
||||||
struct cons_pointer search_store( struct cons_pointer key,
|
|
||||||
struct cons_pointer store, bool return_key );
|
|
||||||
|
|
||||||
struct cons_pointer c_assoc( struct cons_pointer key,
|
struct cons_pointer c_assoc( struct cons_pointer key,
|
||||||
struct cons_pointer store );
|
struct cons_pointer store );
|
||||||
|
|
||||||
struct cons_pointer interned( struct cons_pointer key,
|
|
||||||
struct cons_pointer environment );
|
|
||||||
|
|
||||||
struct cons_pointer internedp( struct cons_pointer key,
|
struct cons_pointer internedp( struct cons_pointer key,
|
||||||
struct cons_pointer environment );
|
struct cons_pointer environment );
|
||||||
|
|
||||||
|
struct cons_pointer hashmap_get( struct cons_pointer mapp,
|
||||||
|
struct cons_pointer key );
|
||||||
|
|
||||||
struct cons_pointer hashmap_put( struct cons_pointer mapp,
|
struct cons_pointer hashmap_put( struct cons_pointer mapp,
|
||||||
struct cons_pointer key,
|
struct cons_pointer key,
|
||||||
struct cons_pointer val );
|
struct cons_pointer val );
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ lisp_nlambda( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
* Evaluate a lambda or nlambda expression.
|
* Evaluate a lambda or nlambda expression.
|
||||||
*/
|
*/
|
||||||
struct cons_pointer
|
struct cons_pointer
|
||||||
eval_lambda( struct cons_space_object *cell, struct stack_frame *frame,
|
eval_lambda( struct cons_space_object cell, struct stack_frame *frame,
|
||||||
struct cons_pointer frame_pointer, struct cons_pointer env ) {
|
struct cons_pointer frame_pointer, struct cons_pointer env ) {
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
@ -257,8 +257,8 @@ eval_lambda( struct cons_space_object *cell, struct stack_frame *frame,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct cons_pointer new_env = env;
|
struct cons_pointer new_env = env;
|
||||||
struct cons_pointer names = cell->payload.lambda.args;
|
struct cons_pointer names = cell.payload.lambda.args;
|
||||||
struct cons_pointer body = cell->payload.lambda.body;
|
struct cons_pointer body = cell.payload.lambda.body;
|
||||||
|
|
||||||
if ( consp( names ) ) {
|
if ( consp( names ) ) {
|
||||||
/* if `names` is a list, bind successive items from that list
|
/* if `names` is a list, bind successive items from that list
|
||||||
|
|
@ -328,56 +328,6 @@ eval_lambda( struct cons_space_object *cell, struct stack_frame *frame,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* if `r` is an exception, and it doesn't have a location, fix up its location from
|
|
||||||
* the name associated with this fn_pointer, if any.
|
|
||||||
*/
|
|
||||||
struct cons_pointer maybe_fixup_exception_location( struct cons_pointer r,
|
|
||||||
struct cons_pointer
|
|
||||||
fn_pointer ) {
|
|
||||||
struct cons_pointer result = r;
|
|
||||||
|
|
||||||
if ( exceptionp( result )
|
|
||||||
&& ( functionp( fn_pointer ) || specialp( fn_pointer ) ) ) {
|
|
||||||
struct cons_space_object *fn_cell = &pointer2cell( fn_pointer );
|
|
||||||
|
|
||||||
struct cons_pointer payload =
|
|
||||||
pointer2cell( result ).payload.exception.payload;
|
|
||||||
/* TODO: should name_key also be a privileged keyword? */
|
|
||||||
struct cons_pointer name_key = c_string_to_lisp_keyword( L"name" );
|
|
||||||
|
|
||||||
switch ( get_tag_value( payload ) ) {
|
|
||||||
case NILTV:
|
|
||||||
case CONSTV:
|
|
||||||
case HASHTV:
|
|
||||||
{
|
|
||||||
if ( nilp( c_assoc( privileged_keyword_location,
|
|
||||||
payload ) ) ) {
|
|
||||||
pointer2cell( result ).payload.exception.payload =
|
|
||||||
set( privileged_keyword_location,
|
|
||||||
c_assoc( name_key,
|
|
||||||
fn_cell->payload.function.meta ),
|
|
||||||
payload );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pointer2cell( result ).payload.exception.payload =
|
|
||||||
make_cons( make_cons( privileged_keyword_location,
|
|
||||||
c_assoc( name_key,
|
|
||||||
fn_cell->payload.
|
|
||||||
function.meta ) ),
|
|
||||||
make_cons( make_cons
|
|
||||||
( privileged_keyword_payload,
|
|
||||||
payload ), NIL ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
dec_ref( name_key );
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal guts of apply.
|
* Internal guts of apply.
|
||||||
|
|
@ -398,10 +348,10 @@ c_apply( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
if ( exceptionp( fn_pointer ) ) {
|
if ( exceptionp( fn_pointer ) ) {
|
||||||
result = fn_pointer;
|
result = fn_pointer;
|
||||||
} else {
|
} else {
|
||||||
struct cons_space_object *fn_cell = &pointer2cell( fn_pointer );
|
struct cons_space_object fn_cell = pointer2cell( fn_pointer );
|
||||||
struct cons_pointer args = c_cdr( frame->arg[0] );
|
struct cons_pointer args = c_cdr( frame->arg[0] );
|
||||||
|
|
||||||
switch ( get_tag_value( fn_pointer ) ) {
|
switch ( fn_cell.tag.value ) {
|
||||||
case EXCEPTIONTV:
|
case EXCEPTIONTV:
|
||||||
/* just pass exceptions straight back */
|
/* just pass exceptions straight back */
|
||||||
result = fn_pointer;
|
result = fn_pointer;
|
||||||
|
|
@ -419,15 +369,10 @@ c_apply( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
struct stack_frame *next =
|
struct stack_frame *next =
|
||||||
get_stack_frame( next_pointer );
|
get_stack_frame( next_pointer );
|
||||||
|
|
||||||
result = maybe_fixup_exception_location( ( *
|
result =
|
||||||
( fn_cell->
|
( *fn_cell.payload.function.executable ) ( next,
|
||||||
payload.
|
|
||||||
function.
|
|
||||||
executable ) )
|
|
||||||
( next,
|
|
||||||
next_pointer,
|
next_pointer,
|
||||||
env ),
|
env );
|
||||||
fn_pointer );
|
|
||||||
dec_ref( next_pointer );
|
dec_ref( next_pointer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -461,6 +406,8 @@ c_apply( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case VECTORPOINTTV:
|
||||||
|
switch ( pointer_to_vso( fn_pointer )->header.tag.value ) {
|
||||||
case HASHTV:
|
case HASHTV:
|
||||||
/* \todo: if arg[0] is a CONS, treat it as a path */
|
/* \todo: if arg[0] is a CONS, treat it as a path */
|
||||||
result = c_assoc( eval_form( frame,
|
result = c_assoc( eval_form( frame,
|
||||||
|
|
@ -470,6 +417,8 @@ c_apply( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
[0] ) ), env ),
|
[0] ) ), env ),
|
||||||
fn_pointer );
|
fn_pointer );
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case NLAMBDATV:
|
case NLAMBDATV:
|
||||||
{
|
{
|
||||||
|
|
@ -492,16 +441,15 @@ c_apply( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
{
|
{
|
||||||
struct cons_pointer next_pointer =
|
struct cons_pointer next_pointer =
|
||||||
make_special_frame( frame_pointer, args, env );
|
make_special_frame( frame_pointer, args, env );
|
||||||
// inc_ref( next_pointer );
|
inc_ref( next_pointer );
|
||||||
if ( exceptionp( next_pointer ) ) {
|
if ( exceptionp( next_pointer ) ) {
|
||||||
result = next_pointer;
|
result = next_pointer;
|
||||||
} else {
|
} else {
|
||||||
result = maybe_fixup_exception_location( ( *
|
result =
|
||||||
( fn_cell->
|
( *fn_cell.payload.
|
||||||
payload.
|
special.executable ) ( get_stack_frame
|
||||||
special.
|
( next_pointer ),
|
||||||
executable ) )
|
next_pointer, env );
|
||||||
( get_stack_frame( next_pointer ), next_pointer, env ), fn_pointer );
|
|
||||||
debug_print( L"Special form returning: ", DEBUG_EVAL );
|
debug_print( L"Special form returning: ", DEBUG_EVAL );
|
||||||
debug_print_object( result, DEBUG_EVAL );
|
debug_print_object( result, DEBUG_EVAL );
|
||||||
debug_println( DEBUG_EVAL );
|
debug_println( DEBUG_EVAL );
|
||||||
|
|
@ -517,16 +465,13 @@ c_apply( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
memset( buffer, '\0', bs );
|
memset( buffer, '\0', bs );
|
||||||
swprintf( buffer, bs,
|
swprintf( buffer, bs,
|
||||||
L"Unexpected cell with tag %d (%4.4s) in function position",
|
L"Unexpected cell with tag %d (%4.4s) in function position",
|
||||||
fn_cell->tag.value, &( fn_cell->tag.bytes[0] ) );
|
fn_cell.tag.value, &fn_cell.tag.bytes[0] );
|
||||||
struct cons_pointer message =
|
struct cons_pointer message =
|
||||||
c_string_to_lisp_string( buffer );
|
c_string_to_lisp_string( buffer );
|
||||||
free( buffer );
|
free( buffer );
|
||||||
result =
|
result = throw_exception( message, frame_pointer );
|
||||||
throw_exception( c_string_to_lisp_symbol( L"apply" ),
|
|
||||||
message, frame_pointer );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_print( L"c_apply: returning: ", DEBUG_EVAL );
|
debug_print( L"c_apply: returning: ", DEBUG_EVAL );
|
||||||
|
|
@ -563,24 +508,23 @@ lisp_eval( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
debug_dump_object( frame_pointer, DEBUG_EVAL );
|
debug_dump_object( frame_pointer, DEBUG_EVAL );
|
||||||
|
|
||||||
struct cons_pointer result = frame->arg[0];
|
struct cons_pointer result = frame->arg[0];
|
||||||
struct cons_space_object *cell = &pointer2cell( frame->arg[0] );
|
struct cons_space_object cell = pointer2cell( frame->arg[0] );
|
||||||
|
|
||||||
switch ( cell->tag.value ) {
|
switch ( cell.tag.value ) {
|
||||||
case CONSTV:
|
case CONSTV:
|
||||||
result = c_apply( frame, frame_pointer, env );
|
result = c_apply( frame, frame_pointer, env );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SYMBOLTV:
|
case SYMBOLTV:
|
||||||
{
|
{
|
||||||
struct cons_pointer canonical = interned( frame->arg[0], env );
|
struct cons_pointer canonical =
|
||||||
|
internedp( frame->arg[0], env );
|
||||||
if ( nilp( canonical ) ) {
|
if ( nilp( canonical ) ) {
|
||||||
struct cons_pointer message =
|
struct cons_pointer message =
|
||||||
make_cons( c_string_to_lisp_string
|
make_cons( c_string_to_lisp_string
|
||||||
( L"Attempt to take value of unbound symbol." ),
|
( L"Attempt to take value of unbound symbol." ),
|
||||||
frame->arg[0] );
|
frame->arg[0] );
|
||||||
result =
|
result = throw_exception( message, frame_pointer );
|
||||||
throw_exception( c_string_to_lisp_symbol( L"eval" ),
|
|
||||||
message, frame_pointer );
|
|
||||||
} else {
|
} else {
|
||||||
result = c_assoc( canonical, env );
|
result = c_assoc( canonical, env );
|
||||||
inc_ref( result );
|
inc_ref( result );
|
||||||
|
|
@ -681,8 +625,7 @@ lisp_set( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
result = frame->arg[1];
|
result = frame->arg[1];
|
||||||
} else {
|
} else {
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"set" ),
|
throw_exception( make_cons
|
||||||
make_cons
|
|
||||||
( c_string_to_lisp_string
|
( c_string_to_lisp_string
|
||||||
( L"The first argument to `set` is not a symbol: " ),
|
( L"The first argument to `set` is not a symbol: " ),
|
||||||
make_cons( frame->arg[0], NIL ) ),
|
make_cons( frame->arg[0], NIL ) ),
|
||||||
|
|
@ -721,8 +664,7 @@ lisp_set_shriek( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
result = val;
|
result = val;
|
||||||
} else {
|
} else {
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"set!" ),
|
throw_exception( make_cons
|
||||||
make_cons
|
|
||||||
( c_string_to_lisp_string
|
( c_string_to_lisp_string
|
||||||
( L"The first argument to `set!` is not a symbol: " ),
|
( L"The first argument to `set!` is not a symbol: " ),
|
||||||
make_cons( frame->arg[0], NIL ) ),
|
make_cons( frame->arg[0], NIL ) ),
|
||||||
|
|
@ -794,25 +736,24 @@ struct cons_pointer
|
||||||
lisp_car( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
lisp_car( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer env ) {
|
struct cons_pointer env ) {
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
struct cons_space_object *cell = &pointer2cell( frame->arg[0] );
|
struct cons_space_object cell = pointer2cell( frame->arg[0] );
|
||||||
|
|
||||||
switch ( cell->tag.value ) {
|
switch ( cell.tag.value ) {
|
||||||
case CONSTV:
|
case CONSTV:
|
||||||
result = cell->payload.cons.car;
|
result = cell.payload.cons.car;
|
||||||
break;
|
break;
|
||||||
case NILTV:
|
case NILTV:
|
||||||
break;
|
break;
|
||||||
case READTV:
|
case READTV:
|
||||||
result =
|
result =
|
||||||
make_string( url_fgetwc( cell->payload.stream.stream ), NIL );
|
make_string( url_fgetwc( cell.payload.stream.stream ), NIL );
|
||||||
break;
|
break;
|
||||||
case STRINGTV:
|
case STRINGTV:
|
||||||
result = make_string( cell->payload.string.character, NIL );
|
result = make_string( cell.payload.string.character, NIL );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"car" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Attempt to take CAR of non sequence" ),
|
( L"Attempt to take CAR of non sequence" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
}
|
}
|
||||||
|
|
@ -839,25 +780,24 @@ struct cons_pointer
|
||||||
lisp_cdr( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
lisp_cdr( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer env ) {
|
struct cons_pointer env ) {
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
struct cons_space_object *cell = &pointer2cell( frame->arg[0] );
|
struct cons_space_object cell = pointer2cell( frame->arg[0] );
|
||||||
|
|
||||||
switch ( cell->tag.value ) {
|
switch ( cell.tag.value ) {
|
||||||
case CONSTV:
|
case CONSTV:
|
||||||
result = cell->payload.cons.cdr;
|
result = cell.payload.cons.cdr;
|
||||||
break;
|
break;
|
||||||
case NILTV:
|
case NILTV:
|
||||||
break;
|
break;
|
||||||
case READTV:
|
case READTV:
|
||||||
url_fgetwc( cell->payload.stream.stream );
|
url_fgetwc( cell.payload.stream.stream );
|
||||||
result = frame->arg[0];
|
result = frame->arg[0];
|
||||||
break;
|
break;
|
||||||
case STRINGTV:
|
case STRINGTV:
|
||||||
result = cell->payload.string.cdr;
|
result = cell.payload.string.cdr;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"cdr" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Attempt to take CDR of non sequence" ),
|
( L"Attempt to take CDR of non sequence" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
}
|
}
|
||||||
|
|
@ -895,35 +835,7 @@ struct cons_pointer lisp_length( struct stack_frame *frame,
|
||||||
struct cons_pointer
|
struct cons_pointer
|
||||||
lisp_assoc( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
lisp_assoc( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer env ) {
|
struct cons_pointer env ) {
|
||||||
return c_assoc( frame->arg[0],
|
return c_assoc( frame->arg[0], frame->arg[1] );
|
||||||
nilp( frame->arg[1] ) ? oblist : frame->arg[1] );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief `(interned? key store)`: Return `t` if the symbol or keyword `key` is bound in this `store`, else `nil`.
|
|
||||||
*
|
|
||||||
* @param frame
|
|
||||||
* @param frame_pointer
|
|
||||||
* @param env
|
|
||||||
* @return struct cons_pointer
|
|
||||||
*/
|
|
||||||
struct cons_pointer
|
|
||||||
lisp_internedp( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
|
||||||
struct cons_pointer env ) {
|
|
||||||
struct cons_pointer result = internedp( frame->arg[0],
|
|
||||||
nilp( frame->arg[1] ) ? oblist :
|
|
||||||
frame->arg[1] );
|
|
||||||
|
|
||||||
if ( exceptionp( result ) ) {
|
|
||||||
struct cons_pointer old = result;
|
|
||||||
struct cons_space_object *cell = &( pointer2cell( result ) );
|
|
||||||
result =
|
|
||||||
throw_exception( c_string_to_lisp_symbol( L"interned?" ),
|
|
||||||
cell->payload.exception.payload, frame_pointer );
|
|
||||||
dec_ref( old );
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cons_pointer c_keys( struct cons_pointer store ) {
|
struct cons_pointer c_keys( struct cons_pointer store ) {
|
||||||
|
|
@ -1058,15 +970,11 @@ lisp_read( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
frame->arg[0] : get_default_stream( true, env );
|
frame->arg[0] : get_default_stream( true, env );
|
||||||
|
|
||||||
if ( readp( in_stream ) ) {
|
if ( readp( in_stream ) ) {
|
||||||
debug_print( L"lisp_read: setting input stream\n",
|
debug_print( L"lisp_read: setting input stream\n", DEBUG_IO );
|
||||||
DEBUG_IO | DEBUG_REPL );
|
|
||||||
debug_dump_object( in_stream, DEBUG_IO );
|
debug_dump_object( in_stream, DEBUG_IO );
|
||||||
input = pointer2cell( in_stream ).payload.stream.stream;
|
input = pointer2cell( in_stream ).payload.stream.stream;
|
||||||
inc_ref( in_stream );
|
inc_ref( in_stream );
|
||||||
} else {
|
} else {
|
||||||
/* should not happen, but has done. */
|
|
||||||
debug_print( L"WARNING: invalid input stream; defaulting!\n",
|
|
||||||
DEBUG_IO | DEBUG_REPL );
|
|
||||||
input = file_to_url_file( stdin );
|
input = file_to_url_file( stdin );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1280,8 +1188,7 @@ struct cons_pointer eval_cond_clause( struct cons_pointer clause,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = throw_exception( c_string_to_lisp_symbol( L"cond" ),
|
result = throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Arguments to `cond` must be lists" ),
|
( L"Arguments to `cond` must be lists" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
}
|
}
|
||||||
|
|
@ -1339,32 +1246,18 @@ lisp_cond( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
* pointer to the frame in which the exception occurred.
|
* pointer to the frame in which the exception occurred.
|
||||||
*/
|
*/
|
||||||
struct cons_pointer
|
struct cons_pointer
|
||||||
throw_exception( struct cons_pointer location,
|
throw_exception( struct cons_pointer message,
|
||||||
struct cons_pointer message,
|
|
||||||
struct cons_pointer frame_pointer ) {
|
struct cons_pointer frame_pointer ) {
|
||||||
|
debug_print( L"\nERROR: ", DEBUG_EVAL );
|
||||||
|
debug_dump_object( message, DEBUG_EVAL );
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
|
|
||||||
#ifdef DEBUG
|
struct cons_space_object cell = pointer2cell( message );
|
||||||
debug_print( L"\nERROR: `", 511 );
|
|
||||||
debug_print_object( message, 511 );
|
|
||||||
debug_print( L"` at `", 511 );
|
|
||||||
debug_print_object( location, 511 );
|
|
||||||
debug_print( L"`\n", 511 );
|
|
||||||
debug_print_object( location, 511 );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct cons_space_object *cell = &pointer2cell( message );
|
if ( cell.tag.value == EXCEPTIONTV ) {
|
||||||
|
|
||||||
if ( cell->tag.value == EXCEPTIONTV ) {
|
|
||||||
result = message;
|
result = message;
|
||||||
} else {
|
} else {
|
||||||
result =
|
result = make_exception( message, frame_pointer );
|
||||||
make_exception( make_cons
|
|
||||||
( make_cons( privileged_keyword_location,
|
|
||||||
location ),
|
|
||||||
make_cons( make_cons
|
|
||||||
( privileged_keyword_payload,
|
|
||||||
message ), NIL ) ), frame_pointer );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -1377,7 +1270,7 @@ throw_exception( struct cons_pointer location,
|
||||||
* normally return. A function which detects a problem it cannot resolve
|
* normally return. A function which detects a problem it cannot resolve
|
||||||
* *should* return an exception.
|
* *should* return an exception.
|
||||||
*
|
*
|
||||||
* * (exception message location)
|
* * (exception message frame)
|
||||||
*
|
*
|
||||||
* @param frame my stack frame.
|
* @param frame my stack frame.
|
||||||
* @param frame_pointer a pointer to my stack_frame.
|
* @param frame_pointer a pointer to my stack_frame.
|
||||||
|
|
@ -1392,10 +1285,9 @@ struct cons_pointer
|
||||||
lisp_exception( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
lisp_exception( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer env ) {
|
struct cons_pointer env ) {
|
||||||
struct cons_pointer message = frame->arg[0];
|
struct cons_pointer message = frame->arg[0];
|
||||||
|
|
||||||
return exceptionp( message ) ? message : throw_exception( message,
|
return exceptionp( message ) ? message : throw_exception( message,
|
||||||
frame->arg[1],
|
frame->
|
||||||
frame->previous );
|
previous );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1415,11 +1307,7 @@ struct cons_pointer lisp_repl( struct stack_frame *frame,
|
||||||
struct cons_pointer env ) {
|
struct cons_pointer env ) {
|
||||||
struct cons_pointer expr = NIL;
|
struct cons_pointer expr = NIL;
|
||||||
|
|
||||||
#ifdef DEBUG
|
debug_printf( DEBUG_REPL, L"Entering new inner REPL\n" );
|
||||||
debug_print( L"Entering new inner REPL\n\tenv is `", DEBUG_REPL );
|
|
||||||
debug_print_object( env, DEBUG_REPL );
|
|
||||||
debug_print( L"`\n", DEBUG_REPL );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct cons_pointer input = get_default_stream( true, env );
|
struct cons_pointer input = get_default_stream( true, env );
|
||||||
struct cons_pointer output = get_default_stream( false, env );
|
struct cons_pointer output = get_default_stream( false, env );
|
||||||
|
|
@ -1434,7 +1322,7 @@ struct cons_pointer lisp_repl( struct stack_frame *frame,
|
||||||
set( c_string_to_lisp_symbol( L"*in*" ), frame->arg[1], new_env );
|
set( c_string_to_lisp_symbol( L"*in*" ), frame->arg[1], new_env );
|
||||||
input = frame->arg[1];
|
input = frame->arg[1];
|
||||||
}
|
}
|
||||||
if ( writep( frame->arg[2] ) ) {
|
if ( readp( frame->arg[2] ) ) {
|
||||||
new_env =
|
new_env =
|
||||||
set( c_string_to_lisp_symbol( L"*out*" ), frame->arg[2], new_env );
|
set( c_string_to_lisp_symbol( L"*out*" ), frame->arg[2], new_env );
|
||||||
output = frame->arg[2];
|
output = frame->arg[2];
|
||||||
|
|
@ -1444,16 +1332,8 @@ struct cons_pointer lisp_repl( struct stack_frame *frame,
|
||||||
inc_ref( output );
|
inc_ref( output );
|
||||||
inc_ref( prompt_name );
|
inc_ref( prompt_name );
|
||||||
|
|
||||||
/* output should NEVER BE nil; but during development it has happened.
|
URL_FILE *os = pointer2cell( output ).payload.stream.stream;
|
||||||
* To allow debugging under such circumstances, we need an emergency
|
|
||||||
* default. */
|
|
||||||
URL_FILE *os =
|
|
||||||
!writep( output ) ? file_to_url_file( stdout ) :
|
|
||||||
pointer2cell( output ).payload.stream.stream;
|
|
||||||
if ( !writep( output ) ) {
|
|
||||||
debug_print( L"WARNING: invalid output; defaulting!\n",
|
|
||||||
DEBUG_IO | DEBUG_REPL );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* \todo this is subtly wrong. If we were evaluating
|
/* \todo this is subtly wrong. If we were evaluating
|
||||||
* (print (eval (read)))
|
* (print (eval (read)))
|
||||||
|
|
@ -1470,10 +1350,7 @@ struct cons_pointer lisp_repl( struct stack_frame *frame,
|
||||||
* \todo the whole process of resolving symbol values needs to be revisited
|
* \todo the whole process of resolving symbol values needs to be revisited
|
||||||
* when we get onto namespaces. */
|
* when we get onto namespaces. */
|
||||||
/* OK, there's something even more subtle here if the root namespace is a map.
|
/* OK, there's something even more subtle here if the root namespace is a map.
|
||||||
* H'mmmm...
|
* H'mmmm... */
|
||||||
* I think that now the oblist is a hashmap masquerading as a namespace,
|
|
||||||
* we should no longer have to do this. TODO: test, and if so, delete this
|
|
||||||
* statement. */
|
|
||||||
if ( !eq( oblist, old_oblist ) ) {
|
if ( !eq( oblist, old_oblist ) ) {
|
||||||
struct cons_pointer cursor = oblist;
|
struct cons_pointer cursor = oblist;
|
||||||
|
|
||||||
|
|
@ -1517,9 +1394,6 @@ struct cons_pointer lisp_repl( struct stack_frame *frame,
|
||||||
dec_ref( expr );
|
dec_ref( expr );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( nilp( output ) ) {
|
|
||||||
free( os );
|
|
||||||
}
|
|
||||||
dec_ref( input );
|
dec_ref( input );
|
||||||
dec_ref( output );
|
dec_ref( output );
|
||||||
dec_ref( prompt_name );
|
dec_ref( prompt_name );
|
||||||
|
|
@ -1546,24 +1420,24 @@ struct cons_pointer lisp_source( struct stack_frame *frame,
|
||||||
struct cons_pointer frame_pointer,
|
struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer env ) {
|
struct cons_pointer env ) {
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
struct cons_space_object *cell = &pointer2cell( frame->arg[0] );
|
struct cons_space_object cell = pointer2cell( frame->arg[0] );
|
||||||
struct cons_pointer source_key = c_string_to_lisp_keyword( L"source" );
|
struct cons_pointer source_key = c_string_to_lisp_keyword( L"source" );
|
||||||
switch ( cell->tag.value ) {
|
switch ( cell.tag.value ) {
|
||||||
case FUNCTIONTV:
|
case FUNCTIONTV:
|
||||||
result = c_assoc( source_key, cell->payload.function.meta );
|
result = c_assoc( source_key, cell.payload.function.meta );
|
||||||
break;
|
break;
|
||||||
case SPECIALTV:
|
case SPECIALTV:
|
||||||
result = c_assoc( source_key, cell->payload.special.meta );
|
result = c_assoc( source_key, cell.payload.special.meta );
|
||||||
break;
|
break;
|
||||||
case LAMBDATV:
|
case LAMBDATV:
|
||||||
result = make_cons( c_string_to_lisp_symbol( L"lambda" ),
|
result = make_cons( c_string_to_lisp_symbol( L"lambda" ),
|
||||||
make_cons( cell->payload.lambda.args,
|
make_cons( cell.payload.lambda.args,
|
||||||
cell->payload.lambda.body ) );
|
cell.payload.lambda.body ) );
|
||||||
break;
|
break;
|
||||||
case NLAMBDATV:
|
case NLAMBDATV:
|
||||||
result = make_cons( c_string_to_lisp_symbol( L"nlambda" ),
|
result = make_cons( c_string_to_lisp_symbol( L"nlambda" ),
|
||||||
make_cons( cell->payload.lambda.args,
|
make_cons( cell.payload.lambda.args,
|
||||||
cell->payload.lambda.body ) );
|
cell.payload.lambda.body ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// \todo suffers from premature GC, and I can't see why!
|
// \todo suffers from premature GC, and I can't see why!
|
||||||
|
|
@ -1586,8 +1460,7 @@ struct cons_pointer c_append( struct cons_pointer l1, struct cons_pointer l2 ) {
|
||||||
c_append( c_cdr( l1 ), l2 ) );
|
c_append( c_cdr( l1 ), l2 ) );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw_exception( c_string_to_lisp_symbol( L"append" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Can't append: not same type" ), NIL );
|
( L"Can't append: not same type" ), NIL );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -1597,25 +1470,24 @@ struct cons_pointer c_append( struct cons_pointer l1, struct cons_pointer l2 ) {
|
||||||
if ( pointer2cell( l1 ).tag.value == pointer2cell( l2 ).tag.value ) {
|
if ( pointer2cell( l1 ).tag.value == pointer2cell( l2 ).tag.value ) {
|
||||||
if ( nilp( c_cdr( l1 ) ) ) {
|
if ( nilp( c_cdr( l1 ) ) ) {
|
||||||
return
|
return
|
||||||
make_string_like_thing( ( pointer2cell( l1 ).payload.
|
make_string_like_thing( ( pointer2cell( l1 ).
|
||||||
string.character ), l2,
|
payload.string.character ),
|
||||||
|
l2,
|
||||||
pointer2cell( l1 ).tag.value );
|
pointer2cell( l1 ).tag.value );
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
make_string_like_thing( ( pointer2cell( l1 ).payload.
|
make_string_like_thing( ( pointer2cell( l1 ).
|
||||||
string.character ),
|
payload.string.character ),
|
||||||
c_append( c_cdr( l1 ), l2 ),
|
c_append( c_cdr( l1 ), l2 ),
|
||||||
pointer2cell( l1 ).tag.value );
|
pointer2cell( l1 ).tag.value );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw_exception( c_string_to_lisp_symbol( L"append" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Can't append: not same type" ), NIL );
|
( L"Can't append: not same type" ), NIL );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw_exception( c_string_to_lisp_symbol( L"append" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Can't append: not a sequence" ), NIL );
|
( L"Can't append: not a sequence" ), NIL );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1727,8 +1599,7 @@ struct cons_pointer lisp_let( struct stack_frame *frame,
|
||||||
bindings = make_cons( make_cons( symbol, val ), bindings );
|
bindings = make_cons( make_cons( symbol, val ), bindings );
|
||||||
} else {
|
} else {
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"let" ),
|
throw_exception( c_string_to_lisp_string
|
||||||
c_string_to_lisp_string
|
|
||||||
( L"Let: cannot bind, not a symbol" ),
|
( L"Let: cannot bind, not a symbol" ),
|
||||||
frame_pointer );
|
frame_pointer );
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -131,9 +131,6 @@ struct cons_pointer lisp_cdr( struct stack_frame *frame,
|
||||||
struct cons_pointer lisp_inspect( struct stack_frame *frame,
|
struct cons_pointer lisp_inspect( struct stack_frame *frame,
|
||||||
struct cons_pointer frame_pointer,
|
struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer env );
|
struct cons_pointer env );
|
||||||
struct cons_pointer lisp_internedp( struct stack_frame *frame,
|
|
||||||
struct cons_pointer frame_pointer,
|
|
||||||
struct cons_pointer env );
|
|
||||||
struct cons_pointer lisp_eq( struct stack_frame *frame,
|
struct cons_pointer lisp_eq( struct stack_frame *frame,
|
||||||
struct cons_pointer frame_pointer,
|
struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer env );
|
struct cons_pointer env );
|
||||||
|
|
@ -196,8 +193,7 @@ struct cons_pointer lisp_cond( struct stack_frame *frame,
|
||||||
* signature of a lisp function; but it is nevertheless to be preferred to
|
* signature of a lisp function; but it is nevertheless to be preferred to
|
||||||
* make_exception. A real `throw_exception`, which does, will be needed.
|
* make_exception. A real `throw_exception`, which does, will be needed.
|
||||||
*/
|
*/
|
||||||
struct cons_pointer throw_exception( struct cons_pointer location,
|
struct cons_pointer throw_exception( struct cons_pointer message,
|
||||||
struct cons_pointer message,
|
|
||||||
struct cons_pointer frame_pointer );
|
struct cons_pointer frame_pointer );
|
||||||
|
|
||||||
struct cons_pointer lisp_exception( struct stack_frame *frame,
|
struct cons_pointer lisp_exception( struct stack_frame *frame,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue