Skip to content

Commit 1e3aad3

Browse files
add better keywordp and fix behavior of Lisp keywordp on non-builtin symbols
1 parent 6beb510 commit 1e3aad3

File tree

1 file changed

+39
-26
lines changed

1 file changed

+39
-26
lines changed

ulisp.hpp

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ volatile flags_t Flags = 0b00001; // PRINTREADABLY set by default
223223

224224
// Forward references
225225
object* tee;
226+
bool builtin_keywordp (object*);
226227
bool keywordp (object*);
227228
void pfstring (PGM_P, pfun_t);
228229
char nthchar (object*, int);
@@ -875,7 +876,7 @@ bool builtinp (symbol_t name) {
875876
}
876877

877878
int checkkeyword (object* obj) {
878-
if (!keywordp(obj)) error(PSTR("argument is not a keyword"), obj);
879+
if (!builtin_keywordp(obj)) error(PSTR("argument is not a keyword"), obj);
879880
builtin_t kname = builtin(obj->name);
880881
minmax_t context = getminmax(kname);
881882
if (context != 0 && context != (minmax_t)Context) error(invalidkey, obj);
@@ -1628,7 +1629,7 @@ object* findvalue (object* var, object* env) {
16281629

16291630
// Handling closures
16301631

1631-
object* closure (int tc, symbol_t name, object* function, object* args, object** env) {
1632+
object* closure (bool tc, symbol_t name, object* function, object* args, object** env) {
16321633
object* state = car(function);
16331634
function = cdr(function);
16341635
int trace = 0;
@@ -1702,12 +1703,12 @@ object* apply (object* function, object* args, object* env) {
17021703
} else function = eval(function, env);
17031704
}
17041705
if (consp(function) && isbuiltin(car(function), LAMBDA)) {
1705-
object* result = closure(0, sym(NIL), function, args, &env);
1706+
object* result = closure(false, sym(NIL), function, args, &env);
17061707
return eval(result, env);
17071708
}
17081709
if (consp(function) && isbuiltin(car(function), CLOSURE)) {
17091710
function = cdr(function);
1710-
object* result = closure(0, sym(NIL), function, args, &env);
1711+
object* result = closure(false, sym(NIL), function, args, &env);
17111712
return eval(result, env);
17121713
}
17131714
error(PSTR("illegal function"), function);
@@ -6773,14 +6774,24 @@ void testescape () {
67736774
}
67746775

67756776
/*
6776-
keywordp - check that obj is a keyword
6777+
builtin_keywordp - check that obj is a built-in keyword
67776778
*/
6778-
bool keywordp (object* obj) {
6779+
bool builtin_keywordp (object* obj) {
67796780
if (!(symbolp(obj) && builtinp(obj->name))) return false;
67806781
builtin_t name = builtin(obj->name);
67816782
PGM_P s = (char*)pgm_read_ptr(&(getentry(name)->string));
67826783
char c = pgm_read_byte(&s[0]);
6783-
return (c == ':');
6784+
return c == ':';
6785+
}
6786+
6787+
bool keywordp (object* obj) {
6788+
if (obj == nil) return false;
6789+
if (builtin_keywordp(obj)) return true;
6790+
symbol_t name = obj->name;
6791+
if ((name & 3) != 0) return false; // Packed symbols are never keywords
6792+
object* first_chunk = (object*)name;
6793+
if (!first_chunk) return false;
6794+
return (((first_chunk->chars) >> ((sizeof(int) - 1) * 8)) & 255) == ':';
67846795
}
67856796

67866797
// Main evaluator
@@ -6789,22 +6800,22 @@ bool keywordp (object* obj) {
67896800
eval - the main Lisp evaluator
67906801
*/
67916802
object* eval (object* form, object* env) {
6792-
int TC=0;
6803+
bool tailcall = false;
67936804
EVAL:
67946805
// Enough space?
67956806
if (Freespace <= WORKSPACESIZE>>4) gc(form, env);
67966807
// Escape
67976808
if (tstflag(ESCAPE)) { clrflag(ESCAPE); error2(PSTR("escape!"));}
67986809
if (!tstflag(NOESC)) testescape();
67996810
// Stack overflow check
6800-
if (abs(static_cast<int*>(StackBottom) - &TC) > MAX_STACK) error(PSTR("C stack overflow"), form);
6811+
if (abs(static_cast<bool*>(StackBottom) - &tailcall) > MAX_STACK) error(PSTR("C stack overflow"), form);
68016812

68026813
if (form == NULL) return nil;
68036814

6804-
if (form->type >= NUMBER && form->type <= STRING) return form;
6815+
if (form->type >= NUMBER && form->type <= STRING) return form; // Literal
68056816

68066817
if (symbolp(form)) {
6807-
if (nthchar(princtostring(form), 0) == ':') return form; // Keyword
6818+
if (keywordp(form)) return form; // Keyword
68086819
symbol_t name = form->name;
68096820
object* pair = value(name, env);
68106821
if (pair != NULL) return cdr(pair);
@@ -6829,7 +6840,7 @@ object* eval (object* form, object* env) {
68296840
builtin_t name = builtin(function->name);
68306841

68316842
if ((name == LET) || (name == LETSTAR)) {
6832-
int TCstart = TC;
6843+
bool old_tailcall = tailcall;
68336844
if (args == NULL) error2(noargument);
68346845
object* assigns = first(args);
68356846
if (!listp(assigns)) error(notalist, assigns);
@@ -6838,17 +6849,17 @@ object* eval (object* form, object* env) {
68386849
protect(newenv);
68396850
while (assigns != NULL) {
68406851
object* assign = car(assigns);
6841-
if (!consp(assign)) push(cons(assign,nil), newenv);
6842-
else if (cdr(assign) == NULL) push(cons(first(assign),nil), newenv);
6843-
else push(cons(first(assign),eval(second(assign),env)), newenv);
6852+
if (!consp(assign)) push(cons(assign, nil), newenv);
6853+
else if (cdr(assign) == NULL) push(cons(first(assign), nil), newenv);
6854+
else push(cons(first(assign), eval(second(assign), env)), newenv);
68446855
car(GCStack) = newenv;
68456856
if (name == LETSTAR) env = newenv;
68466857
assigns = cdr(assigns);
68476858
}
68486859
env = newenv;
68496860
unprotect();
68506861
form = tf_progn(forms,env);
6851-
TC = TCstart;
6862+
tailcall = old_tailcall;
68526863
goto EVAL;
68536864
}
68546865

@@ -6861,7 +6872,7 @@ object* eval (object* form, object* env) {
68616872
if (pair != NULL) push(pair, envcopy);
68626873
env = cdr(env);
68636874
}
6864-
return cons(bsymbol(CLOSURE), cons(envcopy,args));
6875+
return cons(bsymbol(CLOSURE), cons(envcopy, args));
68656876
}
68666877
uint8_t ft = fntype(getminmax(name));
68676878

@@ -6875,23 +6886,23 @@ object* eval (object* form, object* env) {
68756886
Context = name;
68766887
checkargs(args);
68776888
form = ((fn_ptr_type)lookupfn(name))(args, env);
6878-
TC = 1;
6889+
tailcall = true;
68796890
goto EVAL;
68806891
}
68816892
if (ft == OTHER_FORMS) error(PSTR("can't be used as a function"), function);
68826893
}
68836894

68846895
// Evaluate the parameters - result in head
68856896
object* fname = car(form);
6886-
int TCstart = TC;
6897+
bool old_tailcall = tailcall;
68876898
object* head = cons(eval(fname, env), NULL);
68886899
protect(head); // Don't GC the result list
68896900
object* tail = head;
68906901
form = cdr(form);
68916902
int nargs = 0;
68926903

68936904
while (form != NULL){
6894-
object* obj = cons(eval(car(form),env),NULL);
6905+
object* obj = cons(eval(car(form), env), NULL);
68956906
cdr(tail) = obj;
68966907
tail = obj;
68976908
form = cdr(form);
@@ -6903,7 +6914,7 @@ object* eval (object* form, object* env) {
69036914

69046915
if (symbolp(function)) {
69056916
builtin_t bname = builtin(function->name);
6906-
if (!builtinp(function->name)) error(PSTR("not valid here"), fname);
6917+
if (!builtinp(function->name)) error(PSTR("can't call a symbol"), fname);
69076918
Context = bname;
69086919
checkminmax(bname, nargs);
69096920
object* result = ((fn_ptr_type)lookupfn(bname))(args, env);
@@ -6916,7 +6927,7 @@ object* eval (object* form, object* env) {
69166927
if (!listp(fname)) name = fname->name;
69176928

69186929
if (isbuiltin(car(function), LAMBDA)) {
6919-
form = closure(TCstart, name, function, args, &env);
6930+
form = closure(old_tailcall, name, function, args, &env);
69206931
unprotect();
69216932
int trace = tracing(fname->name);
69226933
if (trace) {
@@ -6928,21 +6939,23 @@ object* eval (object* form, object* env) {
69286939
printobject(result, pserial); pln(pserial);
69296940
return result;
69306941
} else {
6931-
TC = 1;
6942+
tailcall = true;
69326943
goto EVAL;
69336944
}
69346945
}
69356946

69366947
if (isbuiltin(car(function), CLOSURE)) {
69376948
function = cdr(function);
6938-
form = closure(TCstart, name, function, args, &env);
6949+
form = closure(old_tailcall, name, function, args, &env);
69396950
unprotect();
6940-
TC = 1;
6951+
tailcall = true;
69416952
goto EVAL;
69426953
}
69436954

69446955
}
6945-
error(PSTR("illegal function"), fname); return nil;
6956+
error(PSTR("illegal function"), fname);
6957+
// unreachable
6958+
return nil;
69466959
}
69476960

69486961
// Print functions

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy