klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

commit 72d5129b0105a16cc9370a358fdf8a601307c144
parent e3539cf770682df26b98bc7ae9b84e4774dc9dcd
Author: Andres Navarro <canavarro82@gmail.com>
Date:   Tue,  6 Dec 2011 19:59:00 -0300

Added Keyword constructor and simple methods. possible GC bugfix in symbol constructor, where the symbols itself was resucitated if needed, but the underlying string was not.

Diffstat:
Msrc/Makefile | 13++++++++-----
Msrc/kbytevector.c | 20++++++++------------
Asrc/kkeyword.c | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/kkeyword.h | 31+++++++++++++++++++++++++++++++
Msrc/kstring.c | 38++++++++++++++++++++------------------
Msrc/ksymbol.c | 21+++++++++------------
6 files changed, 174 insertions(+), 47 deletions(-)

diff --git a/src/Makefile b/src/Makefile @@ -36,11 +36,12 @@ CORE_O= kobject.o ktoken.o kpair.o kstring.o ksymbol.o kread.o \ kcontinuation.o koperative.o kapplicative.o keval.o krepl.o \ kencapsulation.o kpromise.o kport.o kinteger.o krational.o ksystem.o \ kreal.o ktable.o kgc.o imath.o imrat.o kbytevector.o kvector.o \ - kchar.o kground.o kghelpers.o kgbooleans.o kgeqp.o kgequalp.o \ - kgsymbols.o kgcontrol.o kgpairs_lists.o kgpair_mut.o kgenvironments.o \ - kgenv_mut.o kgcombiners.o kgcontinuations.o kgencapsulations.o \ - kgpromises.o kgkd_vars.o kgks_vars.o kgports.o kgchars.o kgnumbers.o \ - kgstrings.o kgbytevectors.o kgvectors.o kgsystem.o kgerrors.o \ + kchar.o ksymbol.o kground.o kghelpers.o kgbooleans.o kgeqp.o \ + kgequalp.o kgsymbols.o kgcontrol.o kgpairs_lists.o kgpair_mut.o \ + kgenvironments.o kgenv_mut.o kgcombiners.o kgcontinuations.o \ + kgencapsulations.o kgpromises.o kgkd_vars.o kgks_vars.o kgports.o \ + kgchars.o kgnumbers.o kgstrings.o kgbytevectors.o kgvectors.o \ + kgsystem.o kgerrors.o \ $(if $(USE_LIBFFI),kgffi.o) # TEMP: in klisp there is no distinction between core & lib @@ -281,6 +282,8 @@ kstring.o: kstring.c kstring.h kobject.h klimits.h klisp.h klispconf.h \ kstate.h ktoken.h kmem.h kgc.h ksymbol.o: ksymbol.c ksymbol.h kobject.h klimits.h klisp.h klispconf.h \ kstate.h kmem.h kstring.h kgc.h +kkeyword.o: kkeyword.c kkeyword.h kobject.h klimits.h klisp.h klispconf.h \ + kstate.h kmem.h kstring.h kgc.h ksystem.o: ksystem.c kobject.h klimits.h klisp.h klispconf.h kstate.h \ ktoken.h kmem.h kerror.h kpair.h kgc.h ksystem.h ksystem.posix.o: ksystem.posix.c kobject.h klimits.h klisp.h klispconf.h \ diff --git a/src/kbytevector.c b/src/kbytevector.c @@ -32,7 +32,6 @@ TValue kbytevector_new_bs_g(klisp_State *K, bool m, const uint8_t *buf, TValue kbytevector_new_bs_imm(klisp_State *K, const uint8_t *buf, uint32_t size) { /* first check to see if it's in the stringtable */ - GCObject *o; uint32_t h = size; /* seed */ size_t step = (size>>5)+1; /* if bytevector is too long, don't hash all its bytes */ @@ -40,17 +39,14 @@ TValue kbytevector_new_bs_imm(klisp_State *K, const uint8_t *buf, uint32_t size) for (size1 = size; size1 >= step; size1 -= step) /* compute hash */ h = h ^ ((h<<5)+(h>>2)+ buf[size1-1]); - for (o = K->strt.hash[lmod(h, K->strt.size)]; - o != NULL; o = o->gch.next) { - Bytevector *tb = NULL; - if (o->gch.tt == K_TBYTEVECTOR) { - tb = (Bytevector *) o; - } else if (o->gch.tt == K_TSYMBOL || o->gch.tt == K_TSTRING) { - continue; - } else { - /* only symbols, immutable bytevectors and immutable strings */ - klisp_assert(0); - } + for (GCObject *o = K->strt.hash[lmod(h, K->strt.size)]; + o != NULL; o = o->gch.next) { + klisp_assert(o->gch.tt == K_TKEYWORD || o->gch.tt == K_TSYMBOL || + o->gch.tt == K_TSTRING || o->gch.tt == K_TBYTEVECTOR); + + if (o->gch.tt != K_TBYTEVECTOR) continue; + + Bytevector *tb = (Bytevector *) o; if (tb->size == size && (memcmp(buf, tb->b, size) == 0)) { /* bytevector may be dead */ if (isdead(K, o)) changewhite(o); diff --git a/src/kkeyword.c b/src/kkeyword.c @@ -0,0 +1,98 @@ +/* +** kkeywrod.c +** Kernel Keywords +** See Copyright Notice in klisp.h +*/ + +#include <string.h> + +#include "kkeyword.h" +#include "kobject.h" +#include "kstate.h" +#include "kmem.h" +#include "kgc.h" +/* for immutable table */ +#include "kstring.h" + +/* No case folding is performed by these constructors */ +TValue kkeyword_new_bs(klisp_State *K, const char *buf, int32_t size) +{ + /* First calculate the hash */ + uint32_t h = size; /* seed */ + size_t step = (size>>5)+1; /* if string is too long, don't hash all + its chars */ + size_t size1; + for (size1 = size; size1 >= step; size1 -= step) /* compute hash */ + h = h ^ ((h<<5)+(h>>2)+ ((unsigned char) buf[size1-1])); + + h ^= (uint32_t) 0x55555555; + /* keyword hash should be different from string & symbol hash + otherwise keywords and their respective immutable string + would always fall in the same bucket */ + /* look for it in the table */ + for (GCObject *o = K->strt.hash[lmod(h, K->strt.size)]; o != NULL; + o = o->gch.next) { + klisp_assert(o->gch.tt == K_TKEYWORD || o->gch.tt == K_TSYMBOL || + o->gch.tt == K_TSTRING || o->gch.tt == K_TBYTEVECTOR); + + if (o->gch.tt != K_TKEYWORD) continue; + + String *ts = tv2str(((Keyword *) o)->str); + if (ts->size == size && (memcmp(buf, ts->b, size) == 0)) { + /* keyword and/or string may be dead */ + if (isdead(K, o)) changewhite(o); + if (isdead(K, (Object *) ts)) changewhite((Object *) ts); + return gc2keyw(o); + } + } + /* REFACTOR: move this to a new function */ + /* Didn't find it, alloc new immutable string and save in keyword table, + note that the hash value remained in h */ + TValue new_str = kstring_new_bs_imm(K, buf, size); + krooted_tvs_push(K, new_str); + Keyword *new_keyw = klispM_new(K, Keyword); + TValue ret_tv = gc2keyw(new_keyw); + krooted_tvs_pop(K); + + /* header + gc_fields */ + /* can't use klispC_link, because strings use the next pointer + differently */ + new_keyw->gct = klispC_white(K); + new_keyw->tt = K_TKEYWORD; + new_keyw->kflags = 0; + new_keyw->si = NULL; + + /* keyword specific fields */ + new_keyw->str = new_str; + new_keyw->hash = h; + + /* add to the string/keyword table (and link it) */ + stringtable *tb; + tb = &K->strt; + h = lmod(h, tb->size); + new_keyw->next = tb->hash[h]; /* chain new entry */ + tb->hash[h] = (GCObject *)(new_keyw); + tb->nuse++; + if (tb->nuse > ((uint32_t) tb->size) && tb->size <= INT32_MAX / 2) { + krooted_tvs_push(K, ret_tv); /* save in case of gc */ + klispS_resize(K, tb->size*2); /* too crowded */ + krooted_tvs_pop(K); + } + return ret_tv; +} + +/* for c strings with unknown size */ +TValue kkeyword_new_b(klisp_State *K, const char *buf) +{ + int32_t size = (int32_t) strlen(buf); + return kkeyword_new_bs(K, buf, size); +} + +/* for string->keyword & symbol->keyword */ +/* GC: assumes str is rooted */ +TValue kkeyword_new_str(klisp_State *K, TValue str) +{ + return kkeyword_new_bs(K, kstring_buf(str), kstring_size(str)); +} + +bool kkeywordp(TValue obj) { return ttiskeyword(obj); } diff --git a/src/kkeyword.h b/src/kkeyword.h @@ -0,0 +1,31 @@ +/* +** kkeywrod.h +** Kernel Keywords +** See Copyright Notice in klisp.h +*/ + +#ifndef kkeyword_h +#define kkeyword_h + +#include "kobject.h" +#include "kstate.h" +#include "kstring.h" +#include "kmem.h" + +/* All keywords are interned */ +/* No case folding is performed by these constructors */ + +/* buffer + size, may contain nulls */ +TValue kkeyword_new_bs(klisp_State *K, const char *buf, int32_t size); +/* null terminated buffer */ +TValue kkeyword_new_b(klisp_State *K, const char *buf); +/* copies str if not immutable */ +TValue kkeyword_new_str(klisp_State *K, TValue str); + +#define kkeyword_str(tv_) (tv2keyw(tv_)->str) +#define kkeyword_buf(tv_) (kstring_buf(tv2keyw(tv_)->str)) +#define kkeyword_size(tv_) (kstring_size(tv2keyw(tv_)->str)) + +bool kkeywordp(TValue obj); + +#endif diff --git a/src/kstring.c b/src/kstring.c @@ -33,17 +33,23 @@ void klispS_resize (klisp_State *K, int32_t newsize) /* imm string, imm bytevectors & symbols aren't chained with all other objs, but with each other in strt */ GCObject *next = p->gch.next; /* save next */ - uint32_t h = 0; + klisp_assert(p->gch.tt == K_TKEYWORD || p->gch.tt == K_TSYMBOL || + p->gch.tt == K_TSTRING || p->gch.tt == K_TBYTEVECTOR); - if (p->gch.tt == K_TSYMBOL) { + switch(p->gch.tt) { + case K_TSYMBOL: h = ((Symbol *) p)->hash; - } else if (p->gch.tt == K_TSTRING) { + break; + case K_TSTRING: h = ((String *) p)->hash; - } else if (p->gch.tt == K_TBYTEVECTOR) { + break; + case K_TBYTEVECTOR: h = ((Bytevector *) p)->hash; - } else { - klisp_assert(0); + break; + case K_TKEYWORD: + h = ((Keyword *) p)->hash; + break; } int32_t h1 = lmod(h, newsize); /* new position */ @@ -74,7 +80,6 @@ TValue kstring_new_bs_g(klisp_State *K, bool m, const char *buf, TValue kstring_new_bs_imm(klisp_State *K, const char *buf, uint32_t size) { /* first check to see if it's in the stringtable */ - GCObject *o; uint32_t h = size; /* seed */ size_t step = (size>>5)+1; /* if string is too long, don't hash all its chars */ @@ -82,17 +87,14 @@ TValue kstring_new_bs_imm(klisp_State *K, const char *buf, uint32_t size) for (size1 = size; size1 >= step; size1 -= step) /* compute hash */ h = h ^ ((h<<5)+(h>>2)+ ((unsigned char) buf[size1-1])); - for (o = K->strt.hash[lmod(h, K->strt.size)]; - o != NULL; o = o->gch.next) { - String *ts = NULL; - if (o->gch.tt == K_TSTRING) { - ts = (String *) o; - } else if (o->gch.tt == K_TSYMBOL || o->gch.tt == K_TBYTEVECTOR) { - continue; - } else { - /* only symbols, immutable bytevectors and immutable strings */ - klisp_assert(0); - } + for (GCObject *o = K->strt.hash[lmod(h, K->strt.size)]; + o != NULL; o = o->gch.next) { + klisp_assert(o->gch.tt == K_TKEYWORD || o->gch.tt == K_TSYMBOL || + o->gch.tt == K_TSTRING || o->gch.tt == K_TBYTEVECTOR); + + if (o->gch.tt != K_TSTRING) continue; + + String *ts = (String *) o; if (ts->size == size && (memcmp(buf, ts->b, size) == 0)) { /* string may be dead */ if (isdead(K, o)) changewhite(o); diff --git a/src/ksymbol.c b/src/ksymbol.c @@ -38,21 +38,18 @@ TValue ksymbol_new_bs(klisp_State *K, const char *buf, int32_t size, TValue si) would always fall in the same bucket */ /* look for it in the table only if it doesn't have source info */ if (ttisnil(si)) { - GCObject *o; - for (o = K->strt.hash[lmod(h, K->strt.size)]; + for (GCObject *o = K->strt.hash[lmod(h, K->strt.size)]; o != NULL; o = o->gch.next) { - String *ts = NULL; - if (o->gch.tt == K_TSTRING || o->gch.tt == K_TBYTEVECTOR) { - continue; - } else if (o->gch.tt == K_TSYMBOL) { - ts = tv2str(((Symbol *) o)->str); - } else { - /* only symbols, immutable bytevectors and immutable strings */ - klisp_assert(0); - } + klisp_assert(o->gch.tt == K_TKEYWORD || o->gch.tt == K_TSYMBOL || + o->gch.tt == K_TSTRING || o->gch.tt == K_TBYTEVECTOR); + + if (o->gch.tt != K_TSYMBOL) continue; + + String *ts = tv2str(((Symbol *) o)->str); if (ts->size == size && (memcmp(buf, ts->b, size) == 0)) { - /* symbol may be dead */ + /* symbol and/or string may be dead */ if (isdead(K, o)) changewhite(o); + if (isdead(K, (GCObject *) ts)) changewhite((GCObject *) ts); return gc2sym(o); } }