906 lines
22 KiB
C
906 lines
22 KiB
C
/*
|
|
* $Id$
|
|
*/
|
|
|
|
#include "stx.h"
|
|
#include <qse/cmn/str.h>
|
|
|
|
struct class_info_t
|
|
{
|
|
const qse_char_t* name;
|
|
const qse_char_t* superclass;
|
|
const qse_char_t* instance_variables;
|
|
const qse_char_t* class_variables;
|
|
const qse_char_t* pool_dictionaries;
|
|
const int spec;
|
|
};
|
|
|
|
typedef struct class_info_t class_info_t;
|
|
|
|
static class_info_t class_info[] =
|
|
{
|
|
{
|
|
QSE_T("Object"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_T("classvar1 classvar2")/*QSE_NULL TODO: delete this.....*/,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("UndefinedObject"),
|
|
QSE_T("Object"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Behavior"),
|
|
QSE_T("Object"),
|
|
QSE_T("spec methods superclass subclasses"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Class"),
|
|
QSE_T("Behavior"),
|
|
QSE_T("name variables classVariables poolDictionaries"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Metaclass"),
|
|
QSE_T("Behavior"),
|
|
QSE_T("instanceClass"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Block"),
|
|
QSE_T("Object"),
|
|
QSE_T("context argCount argLoc bytePointer"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Boolean"),
|
|
QSE_T("Object"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("True"),
|
|
QSE_T("Boolean"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("False"),
|
|
QSE_T("Boolean"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Context"),
|
|
QSE_T("Object"),
|
|
QSE_T("stack stackTop receiver pc method"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Method"),
|
|
QSE_T("Object"),
|
|
QSE_T("text selector bytecodes tmpCount argCount"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_VARIABLE_WORD
|
|
},
|
|
{
|
|
QSE_T("Magnitude"),
|
|
QSE_T("Object"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Association"),
|
|
QSE_T("Magnitude"),
|
|
QSE_T("key value"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Character"),
|
|
QSE_T("Magnitude"),
|
|
QSE_T("value"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Number"),
|
|
QSE_T("Magnitude"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Integer"),
|
|
QSE_T("Number"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("SmallInteger"),
|
|
QSE_T("Integer"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("LargeInteger"),
|
|
QSE_T("Integer"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_VARIABLE_BYTE
|
|
},
|
|
{
|
|
QSE_T("Collection"),
|
|
QSE_T("Magnitude"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("IndexedCollection"),
|
|
QSE_T("Collection"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_T("Array"),
|
|
QSE_T("IndexedCollection"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_VARIABLE_WORD
|
|
},
|
|
{
|
|
QSE_T("ByteArray"),
|
|
QSE_T("IndexedCollection"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_VARIABLE_BYTE
|
|
},
|
|
{
|
|
QSE_T("SystemSymbolTable"),
|
|
QSE_T("IndexedCollection"),
|
|
QSE_T("tally"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_VARIABLE_WORD
|
|
},
|
|
{
|
|
QSE_T("Dictionary"),
|
|
QSE_T("IndexedCollection"),
|
|
QSE_T("tally"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_VARIABLE_WORD
|
|
},
|
|
|
|
{
|
|
QSE_T("SystemDictionary"),
|
|
QSE_T("Dictionary"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_VARIABLE_WORD
|
|
},
|
|
{
|
|
QSE_T("PoolDictionary"),
|
|
QSE_T("Dictionary"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_VARIABLE_WORD
|
|
},
|
|
{
|
|
QSE_T("String"),
|
|
QSE_T("IndexedCollection"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_VARIABLE_CHAR
|
|
},
|
|
{
|
|
QSE_T("Symbol"),
|
|
QSE_T("String"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_VARIABLE_CHAR
|
|
},
|
|
{
|
|
QSE_T("Link"),
|
|
QSE_T("Object"),
|
|
QSE_T("link"),
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
},
|
|
{
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
QSE_NULL,
|
|
SPEC_FIXED_WORD
|
|
}
|
|
};
|
|
|
|
qse_word_t QSE_INLINE new_string (qse_stx_t* stx, const qse_char_t* str)
|
|
{
|
|
QSE_ASSERT (REFISIDX(stx,stx->ref.class_string));
|
|
QSE_ASSERT (!ISNIL(stx,stx->ref.class_string));
|
|
|
|
return qse_stx_instantiate (
|
|
stx, stx->ref.class_string, QSE_NULL, str, qse_strlen(str));
|
|
}
|
|
|
|
qse_word_t QSE_INLINE new_array (qse_stx_t* stx, qse_word_t capa)
|
|
{
|
|
QSE_ASSERT (REFISIDX(stx,stx->ref.class_array));
|
|
QSE_ASSERT (!ISNIL(stx,stx->ref.class_array));
|
|
|
|
return qse_stx_instantiate (
|
|
stx, stx->ref.class_array, QSE_NULL, QSE_NULL, capa);
|
|
}
|
|
|
|
qse_word_t QSE_INLINE new_systemdictionary (qse_stx_t* stx, qse_word_t capa)
|
|
{
|
|
QSE_ASSERT (REFISIDX(stx,stx->ref.class_systemdictionary));
|
|
QSE_ASSERT (!ISNIL(stx,stx->ref.class_systemdictionary));
|
|
|
|
/* the system dictionary uses 1 slot dedicated for nil.
|
|
* so we request to allocate 1 more slot than the given */
|
|
return qse_stx_instantiate (
|
|
stx, stx->ref.class_systemdictionary,
|
|
QSE_NULL, QSE_NULL, capa + 1);
|
|
}
|
|
|
|
qse_word_t new_class (qse_stx_t* stx, const qse_char_t* name)
|
|
{
|
|
qse_word_t meta, class, assoc;
|
|
qse_word_t class_name;
|
|
|
|
QSE_ASSERT (REFISIDX(stx,stx->ref.class_metaclass));
|
|
|
|
meta = qse_stx_allocwordobj (
|
|
stx, QSE_NULL, QSE_STX_METACLASS_SIZE, QSE_NULL, 0);
|
|
if (ISNIL(stx,meta)) return stx->ref.nil;
|
|
OBJCLASS(stx,meta) = stx->ref.class_metaclass;
|
|
|
|
/* the spec of the metaclass must be the spec of its
|
|
* instance. so the QSE_STX_CLASS_SIZE is set */
|
|
WORDAT(stx,meta,QSE_STX_METACLASS_SPEC) =
|
|
INTTOREF(stx,SPEC_MAKE(QSE_STX_CLASS_SIZE,SPEC_FIXED_WORD));
|
|
|
|
/* the spec of the class is set later in __create_builtin_classes */
|
|
class = qse_stx_allocwordobj (
|
|
stx, QSE_NULL, QSE_STX_CLASS_SIZE, QSE_NULL, 0);
|
|
OBJCLASS(stx,class) = meta;
|
|
|
|
class_name = qse_stx_newsymbol (stx, name);
|
|
if (ISNIL(stx,class_name)) return stx->ref.nil;
|
|
|
|
WORDAT(stx,class,QSE_STX_CLASS_NAME) = class_name;
|
|
WORDAT(stx,class,QSE_STX_CLASS_SPEC) = stx->ref.nil;
|
|
|
|
assoc = qse_stx_putdic (stx, stx->ref.sysdic, class_name, class);
|
|
return (ISNIL(stx,assoc))? stx->ref.nil: class;
|
|
}
|
|
|
|
qse_word_t find_class (qse_stx_t* stx, const qse_char_t* name)
|
|
{
|
|
qse_word_t assoc, meta, value;
|
|
|
|
/* look up the system dictionary for the name given */
|
|
assoc = qse_stx_lookupdic (stx, stx->ref.sysdic, name);
|
|
if (ISNIL(stx,assoc))
|
|
{
|
|
/*qse_stx_seterrnum (stx, QSE_STX_ENOCLASS, QSE_NULL);*/
|
|
return stx->ref.nil;
|
|
}
|
|
|
|
/* get the value part in the association for the name */
|
|
value = WORDAT(stx,assoc,QSE_STX_ASSOCIATION_VALUE);
|
|
|
|
/* check if its class is Metaclass because the class of
|
|
* a class object must be Metaclass. */
|
|
meta = OBJCLASS(stx,value);
|
|
if (OBJCLASS(stx,meta) != stx->ref.class_metaclass)
|
|
{
|
|
/*qse_stx_seterrnum (stx, QSE_STX_ENOTCLASS, QSE_NULL);*/
|
|
return stx->ref.nil;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static qse_word_t count_names (const qse_char_t* str)
|
|
{
|
|
qse_word_t n = 0;
|
|
const qse_char_t* p = str;
|
|
|
|
do
|
|
{
|
|
while (*p == QSE_T(' ') ||
|
|
*p == QSE_T('\t')) p++;
|
|
if (*p == QSE_T('\0')) break;
|
|
|
|
n++;
|
|
while (*p != QSE_T(' ') &&
|
|
*p != QSE_T('\t') &&
|
|
*p != QSE_T('\0')) p++;
|
|
}
|
|
while (1);
|
|
|
|
return n;
|
|
}
|
|
|
|
static qse_word_t count_subclasses (const qse_char_t* str)
|
|
{
|
|
class_info_t* p;
|
|
qse_word_t n = 0;
|
|
|
|
for (p = class_info; p->name != QSE_NULL; p++)
|
|
{
|
|
if (p->superclass == QSE_NULL) continue;
|
|
if (qse_strcmp (str, p->superclass) == 0) n++;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
static void set_subclasses (
|
|
qse_stx_t* stx, qse_word_t* array, const qse_char_t* str)
|
|
{
|
|
class_info_t* p;
|
|
qse_word_t n = 0, class;
|
|
|
|
for (p = class_info; p->name != QSE_NULL; p++)
|
|
{
|
|
if (p->superclass == QSE_NULL) continue;
|
|
if (qse_strcmp (str, p->superclass) != 0) continue;
|
|
class = find_class (stx, p->name);
|
|
QSE_ASSERT (!ISNIL(stx,class));
|
|
array[n++] = class;
|
|
}
|
|
}
|
|
|
|
static void set_metaclass_subclasses (
|
|
qse_stx_t* stx, qse_word_t* array, const qse_char_t* str)
|
|
{
|
|
class_info_t* p;
|
|
qse_word_t n = 0, class;
|
|
|
|
for (p = class_info; p->name != QSE_NULL; p++)
|
|
{
|
|
if (p->superclass == QSE_NULL) continue;
|
|
if (qse_strcmp (str, p->superclass) != 0) continue;
|
|
class = find_class (stx, p->name);
|
|
QSE_ASSERT (!ISNIL(stx,class));
|
|
array[n++] = OBJCLASS(stx,class);
|
|
}
|
|
}
|
|
|
|
static qse_word_t make_classvar_dic (
|
|
qse_stx_t* stx, qse_word_t class, const qse_char_t* names)
|
|
{
|
|
qse_word_t dic, symbol, assoc;
|
|
const qse_char_t* p = names;
|
|
const qse_char_t* name;
|
|
|
|
/* TODO: how to implement temporary GC prevention....???? */
|
|
dic = new_systemdictionary (stx, count_names(names));
|
|
if (ISNIL(stx,dic)) return stx->ref.nil;
|
|
|
|
do
|
|
{
|
|
while (*p == QSE_T(' ') ||
|
|
*p == QSE_T('\t')) p++;
|
|
if (*p == QSE_T('\0')) break;
|
|
|
|
name = p;
|
|
while (*p != QSE_T(' ') &&
|
|
*p != QSE_T('\t') &&
|
|
*p != QSE_T('\0')) p++;
|
|
|
|
symbol = qse_stx_newsymbolx (stx, name, p - name);
|
|
if (ISNIL(stx,symbol)) return stx->ref.nil;
|
|
|
|
assoc = qse_stx_putdic (stx, dic, symbol, stx->ref.nil);
|
|
if (ISNIL(stx,assoc)) return stx->ref.nil;
|
|
}
|
|
while (1);
|
|
|
|
return dic;
|
|
}
|
|
|
|
static int sketch_nil (qse_stx_t* stx)
|
|
{
|
|
qse_stx_objidx_t idx;
|
|
qse_word_t ref;
|
|
qse_stx_wordobj_t* ptr;
|
|
|
|
/* nil contains no member fields. allocate space for
|
|
* an object header */
|
|
idx = qse_stx_allocmem (stx, QSE_SIZEOF(qse_stx_objhdr_t));
|
|
if (idx == QSE_STX_OBJIDX_INVALID) return -1;
|
|
|
|
ref = IDXTOREF(stx,idx);
|
|
ptr = (qse_stx_wordobj_t*)PTRBYIDX(stx,idx);
|
|
|
|
/* store the nil reference first */
|
|
stx->ref.nil = ref;
|
|
|
|
/* nil is a word object containing no member fields.
|
|
* initialize it accordingly */
|
|
ptr->h._type = QSE_STX_WORDOBJ;
|
|
ptr->h._mark = 0;
|
|
ptr->h._refcnt = 0;
|
|
ptr->h._size = 0;
|
|
ptr->h._class = stx->ref.nil; /* the class is yet to be set */
|
|
ptr->h._backref = ref;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define ALLOC_WORDOBJ_TO(stx,var,nflds,nvflds) QSE_BLOCK (\
|
|
var = qse_stx_allocwordobj ((stx), QSE_NULL, (nflds), QSE_NULL, nvflds); \
|
|
if (ISNIL(stx,(var))) return -1; \
|
|
)
|
|
|
|
#define ADD_TO_SYSDIC(stx,key,value) QSE_BLOCK (\
|
|
if (qse_stx_putdic ((stx), (stx)->ref.sysdic, (key), (value)) == (stx)->ref.nil) return -1; \
|
|
)
|
|
|
|
#define NEW_SYMBOL_TO(stx,var,name) QSE_BLOCK (\
|
|
var = qse_stx_newsymbol ((stx), name); \
|
|
if (ISNIL(stx,(var))) return -1; \
|
|
)
|
|
|
|
#define NEW_CLASS_TO(stx,var,name) QSE_BLOCK (\
|
|
var = new_class ((stx), name); \
|
|
if (ISNIL(stx,(var))) return -1; \
|
|
)
|
|
|
|
static int sketch_key_objects (qse_stx_t* stx)
|
|
{
|
|
qse_word_t class_SymbolMeta;
|
|
qse_word_t class_MetaclassMeta;
|
|
qse_word_t class_AssociationMeta;
|
|
qse_word_t symbol_symbol;
|
|
qse_word_t symbol_metaclass;
|
|
qse_word_t symbol_association;
|
|
|
|
QSE_ASSERT (REFISIDX(stx,stx->ref.nil));
|
|
|
|
/* Create a symbol table partially initialized.
|
|
* Especially, the class of the symbol table is not set yet.
|
|
* It must be corrected later */
|
|
/* TODO: initial symbol table size */
|
|
ALLOC_WORDOBJ_TO (stx, stx->ref.symtab, 1, SYMTAB_INIT_CAPA);
|
|
/* Set tally to 0. */
|
|
WORDAT(stx,stx->ref.symtab,QSE_STX_SYSTEMSYMBOLTABLE_TALLY) = INTTOREF(stx,0);
|
|
|
|
/* Create a global system dictionary partially initialized.
|
|
* Especially, the class of the system dictionary is not set yet.
|
|
* It must be corrected later */
|
|
/* TODO: initial dictionary size */
|
|
ALLOC_WORDOBJ_TO (stx, stx->ref.sysdic, 1, SYSDIC_INIT_CAPA);
|
|
/* Set tally to 0 */
|
|
WORDAT(stx,stx->ref.sysdic,QSE_STX_SYSTEMDICTIONARY_TALLY) = INTTOREF(stx,0);
|
|
|
|
/* Create a few critical class objects needed for maintaining
|
|
* the symbol table and the system dictionary. At this point,
|
|
* new_class() cannot be used yet. So the process is
|
|
* pretty mundane as shown below. */
|
|
|
|
/* Symbol */
|
|
ALLOC_WORDOBJ_TO (stx, stx->ref.class_symbol, QSE_STX_CLASS_SIZE, 0);
|
|
/* Metaclass */
|
|
ALLOC_WORDOBJ_TO (stx, stx->ref.class_metaclass, QSE_STX_CLASS_SIZE, 0);
|
|
/* Association */
|
|
ALLOC_WORDOBJ_TO (stx, stx->ref.class_association, QSE_STX_CLASS_SIZE, 0);
|
|
|
|
/* Metaclass is a class so it has the same structure
|
|
* as a normal class. "Metaclass class" is an instance of
|
|
* Metaclass. */
|
|
|
|
/* Symbol class */
|
|
ALLOC_WORDOBJ_TO (stx, class_SymbolMeta, QSE_STX_METACLASS_SIZE, 0);
|
|
/* Metaclass class */
|
|
ALLOC_WORDOBJ_TO (stx, class_MetaclassMeta, QSE_STX_METACLASS_SIZE, 0);
|
|
/* Association class */
|
|
ALLOC_WORDOBJ_TO (stx, class_AssociationMeta, QSE_STX_METACLASS_SIZE, 0);
|
|
|
|
/* (Symbol class) setClass: Metaclass */
|
|
OBJCLASS(stx,class_SymbolMeta) = stx->ref.class_metaclass;
|
|
/* (Metaclass class) setClass: Metaclass */
|
|
OBJCLASS(stx,class_MetaclassMeta) = stx->ref.class_metaclass;
|
|
/* (Association class) setClass: Metaclass */
|
|
OBJCLASS(stx,class_AssociationMeta) = stx->ref.class_metaclass;
|
|
|
|
/* Symbol setClass: (Symbol class) */
|
|
OBJCLASS(stx,stx->ref.class_symbol) = class_SymbolMeta;
|
|
/* Metaclass setClass: (Metaclass class) */
|
|
OBJCLASS(stx,stx->ref.class_metaclass) = class_MetaclassMeta;
|
|
/* Association setClass: (Association class) */
|
|
OBJCLASS(stx,stx->ref.class_association) = class_AssociationMeta;
|
|
|
|
/* (Symbol class) setSpec: CLASS_SIZE */
|
|
WORDAT(stx,class_SymbolMeta,QSE_STX_CLASS_SPEC) =
|
|
INTTOREF (stx, SPEC_MAKE(QSE_STX_CLASS_SIZE,SPEC_FIXED_WORD));
|
|
/* (Metaclass class) setSpec: CLASS_SIZE */
|
|
WORDAT(stx,class_MetaclassMeta,QSE_STX_CLASS_SPEC) =
|
|
INTTOREF (stx, SPEC_MAKE(QSE_STX_CLASS_SIZE,SPEC_FIXED_WORD));
|
|
/* (Association class) setSpec: CLASS_SIZE */
|
|
WORDAT(stx,class_AssociationMeta,QSE_STX_CLASS_SPEC) =
|
|
INTTOREF (stx, SPEC_MAKE(QSE_STX_CLASS_SIZE,SPEC_FIXED_WORD));
|
|
|
|
/* specs for class_metaclass, class_association,
|
|
* class_symbol are set later in make_intrinsic_classes */
|
|
|
|
/* #Symbol */
|
|
NEW_SYMBOL_TO (stx, symbol_symbol, QSE_T("Symbol"));
|
|
/* #Metaclass */
|
|
NEW_SYMBOL_TO (stx, symbol_metaclass, QSE_T("Metaclass"));
|
|
/* #Association */
|
|
NEW_SYMBOL_TO (stx, symbol_association, QSE_T("Association"));
|
|
|
|
/* Symbol setName: #Symbol */
|
|
WORDAT(stx,stx->ref.class_symbol,QSE_STX_CLASS_NAME) = symbol_symbol;
|
|
/* Metaclass setName: #Metaclass */
|
|
WORDAT(stx,stx->ref.class_metaclass,QSE_STX_CLASS_NAME) = symbol_metaclass;
|
|
/* Association setName: #Association */
|
|
WORDAT(stx,stx->ref.class_association,QSE_STX_CLASS_NAME) = symbol_association;
|
|
|
|
/* propagte the spec field in advance */
|
|
WORDAT(stx,stx->ref.class_symbol,QSE_STX_CLASS_SPEC) =
|
|
INTTOREF (stx, SPEC_MAKE(0,SPEC_VARIABLE_CHAR));
|
|
WORDAT(stx,stx->ref.class_metaclass,QSE_STX_CLASS_SPEC) =
|
|
INTTOREF (stx, SPEC_MAKE(QSE_STX_METACLASS_SIZE,SPEC_FIXED_WORD));
|
|
WORDAT(stx,stx->ref.class_association,QSE_STX_CLASS_SPEC) =
|
|
INTTOREF (stx, SPEC_MAKE(QSE_STX_ASSOCIATION_SIZE,SPEC_FIXED_WORD));
|
|
|
|
/* register class names into the system dictionary */
|
|
ADD_TO_SYSDIC (stx, symbol_symbol, stx->ref.class_symbol);
|
|
ADD_TO_SYSDIC (stx, symbol_metaclass, stx->ref.class_metaclass);
|
|
ADD_TO_SYSDIC (stx, symbol_association, stx->ref.class_association);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int make_key_classes (qse_stx_t* stx)
|
|
{
|
|
/* object, class, and array are precreated for easier instantiation
|
|
* of intrinsic classes. */
|
|
NEW_CLASS_TO (stx, stx->ref.class_object, QSE_T("Object"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_undefinedobject, QSE_T("UndefinedObject"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_class, QSE_T("Class"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_array, QSE_T("Array"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_bytearray, QSE_T("ByteArray"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_string, QSE_T("String"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_character, QSE_T("Character"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_context, QSE_T("Context"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_systemsymboltable, QSE_T("SystemSymbolTable"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_systemdictionary, QSE_T("SystemDictionary"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_method, QSE_T("Method"));
|
|
NEW_CLASS_TO (stx, stx->ref.class_smallinteger, QSE_T("SmallInteger"));
|
|
|
|
/* set the spec field in advance so that new_string() and new_array()
|
|
* can call qse_stx_instantiate() from this point onwards */
|
|
WORDAT(stx,stx->ref.class_string,QSE_STX_CLASS_SPEC) =
|
|
INTTOREF (stx, SPEC_MAKE(0,SPEC_VARIABLE_CHAR));
|
|
WORDAT(stx,stx->ref.class_array,QSE_STX_CLASS_SPEC) =
|
|
INTTOREF (stx, SPEC_MAKE(0,SPEC_VARIABLE_WORD));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void set_class_of_more_key_objects (qse_stx_t* stx)
|
|
{
|
|
/* nil setClass: UndefinedObject */
|
|
OBJCLASS(stx,stx->ref.nil) = stx->ref.class_undefinedobject;
|
|
|
|
/* sysdic(Smalltalk) setClass: SystemDictionary */
|
|
OBJCLASS(stx,stx->ref.sysdic) = stx->ref.class_systemdictionary;
|
|
|
|
/* symtab setClass: SystemSymbolTable */
|
|
OBJCLASS(stx,stx->ref.symtab) = stx->ref.class_systemsymboltable;
|
|
}
|
|
|
|
static int make_intrinsic_classes (qse_stx_t* stx)
|
|
{
|
|
class_info_t* p;
|
|
|
|
QSE_ASSERT (!ISNIL(stx,stx->ref.class_array));
|
|
|
|
for (p = class_info; p->name != QSE_NULL; p++)
|
|
{
|
|
qse_word_t classref;
|
|
qse_stx_class_t* classptr;
|
|
qse_word_t nfixed;
|
|
qse_word_t spec;
|
|
|
|
classref = find_class(stx, p->name);
|
|
if (ISNIL(stx,classref))
|
|
{
|
|
classref = new_class (stx, p->name);
|
|
if (ISNIL(stx,classref)) return stx->ref.nil;
|
|
}
|
|
|
|
classptr = (qse_stx_class_t*)PTRBYREF(stx,classref);
|
|
if (p->superclass)
|
|
{
|
|
classptr->superclass = find_class(stx,p->superclass);
|
|
QSE_ASSERT (!ISNIL(stx,classptr->superclass));
|
|
}
|
|
|
|
nfixed = 0;
|
|
|
|
/* resolve the number of fixed fields in the superclass chain */
|
|
if (p->superclass)
|
|
{
|
|
qse_word_t superref;
|
|
qse_stx_class_t* superptr;
|
|
|
|
qse_word_t metaref;
|
|
qse_stx_metaclass_t* metaptr;
|
|
|
|
superref = find_class (stx, p->superclass);
|
|
QSE_ASSERT (!ISNIL(stx,superref));
|
|
|
|
metaref = OBJCLASS(stx,classref);
|
|
metaptr = (qse_stx_metaclass_t*)PTRBYREF(stx,metaref);
|
|
metaptr->superclass = OBJCLASS(stx,superref);
|
|
metaptr->instance_class = classref;
|
|
|
|
do
|
|
{
|
|
superptr = (qse_stx_class_t*)PTRBYREF(stx,superref);
|
|
nfixed += SPEC_GETFIXED(REFTOINT(stx,superptr->spec));
|
|
superref = superptr->superclass;
|
|
}
|
|
while (!ISNIL(stx,superref));
|
|
}
|
|
|
|
/* add the number of instance variables to the number of
|
|
* fixed fields */
|
|
if (p->instance_variables)
|
|
{
|
|
nfixed += count_names (p->instance_variables);
|
|
classptr->variables =
|
|
new_string (stx, p->instance_variables);
|
|
if (ISNIL(stx,classptr->variables)) return -1;
|
|
}
|
|
|
|
QSE_ASSERT (
|
|
nfixed <= 0 ||
|
|
(nfixed > 0 && (p->spec == SPEC_FIXED_WORD ||
|
|
p->spec == SPEC_VARIABLE_WORD)));
|
|
|
|
spec = INTTOREF (stx, SPEC_MAKE (nfixed, p->spec));
|
|
|
|
QSE_ASSERTX (ISNIL(stx,classptr->spec) || classptr->spec == spec,
|
|
"If the specfication field is already set before this function, "
|
|
"the specification in the class information table must match it. "
|
|
"Otherwise, something is very wrong");
|
|
|
|
classptr->spec = spec;
|
|
}
|
|
|
|
/* make class variable dictionaries and pool dictionaries */
|
|
for (p = class_info; p->name; p++)
|
|
{
|
|
qse_word_t classref;
|
|
qse_stx_class_t* classptr;
|
|
|
|
classref = find_class (stx, p->name);
|
|
QSE_ASSERT (!ISNIL(stx,classref));
|
|
|
|
classptr = (qse_stx_class_t*)PTRBYREF(stx,classref);
|
|
|
|
if (p->class_variables)
|
|
{
|
|
classptr->class_variables =
|
|
make_classvar_dic(stx, classref, p->class_variables);
|
|
if (ISNIL(stx,classptr->class_variables)) return stx->ref.nil;
|
|
}
|
|
|
|
/*
|
|
TODO:
|
|
if (p->pool_dictionaries != QSE_NULL) {
|
|
classptr->pool_dictionaries =
|
|
__make_pool_dictionary(stx, class, p->pool_dictionaries);
|
|
}
|
|
*/
|
|
}
|
|
|
|
/* fill subclasses */
|
|
for (p = class_info; p->name != QSE_NULL; p++)
|
|
{
|
|
qse_word_t classref;
|
|
qse_stx_class_t* classptr;
|
|
qse_word_t array;
|
|
qse_word_t n;
|
|
|
|
n = count_subclasses (p->name);
|
|
array = new_array (stx, n);
|
|
if (ISNIL(stx,array)) return -1;
|
|
|
|
set_subclasses (stx, &WORDAT(stx,array,0), p->name);
|
|
|
|
classref = find_class (stx, p->name);
|
|
QSE_ASSERT (!ISNIL(stx,classref));
|
|
|
|
classptr = (qse_stx_class_t*)PTRBYREF(stx,classref);
|
|
classptr->subclasses = array;
|
|
}
|
|
|
|
/* fill subclasses for metaclasses */
|
|
for (p = class_info; p->name != QSE_NULL; p++)
|
|
{
|
|
qse_word_t classref;
|
|
|
|
qse_word_t metaref;
|
|
qse_stx_metaclass_t* metaptr;
|
|
|
|
qse_word_t array;
|
|
qse_word_t n;
|
|
|
|
n = count_subclasses (p->name);
|
|
array = new_array (stx, n);
|
|
if (ISNIL(stx,array)) return -1;
|
|
|
|
set_metaclass_subclasses (stx, &WORDAT(stx,array,0), p->name);
|
|
|
|
classref = find_class (stx, p->name);
|
|
QSE_ASSERT (!ISNIL(stx,classref));
|
|
|
|
metaref = OBJCLASS(stx,classref);
|
|
metaptr = (qse_stx_metaclass_t*)PTRBYREF(stx,metaref);
|
|
metaptr->subclasses = array;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void make_metaclass_top_hierarchy (qse_stx_t* stx)
|
|
{
|
|
qse_word_t metaclass_of_object;
|
|
|
|
/* make the superclass of Object class to be Class */
|
|
|
|
/* metaclass_of_object := Object class */
|
|
metaclass_of_object = OBJCLASS (stx, stx->ref.class_object);
|
|
|
|
/* (Object class) setSuperclass: Class */
|
|
WORDAT(stx,metaclass_of_object,QSE_STX_METACLASS_SUPERCLASS) = stx->ref.class_class;
|
|
|
|
/* Set the instance class for Object here as it is not
|
|
* set in make_intrisic_classes */
|
|
WORDAT(stx,metaclass_of_object,QSE_STX_METACLASS_INSTANCE_CLASS) = stx->ref.class_object;
|
|
}
|
|
|
|
|
|
static int make_key_objects_accessible_by_name (qse_stx_t* stx)
|
|
{
|
|
qse_word_t tmp;
|
|
|
|
#if 0
|
|
/* create #nil, #true, #false */
|
|
NEW_SYMBOL_TO (stx, tmp, QSE_T("nil"));
|
|
NEW_SYMBOL_TO (stx, tmp, QSE_T("true"));
|
|
NEW_SYMBOL_TO (stx, tmp, QSE_T("false"));
|
|
#endif
|
|
|
|
NEW_SYMBOL_TO (stx, tmp, QSE_T("Smalltalk"));
|
|
/* Smalltalk at: #Smalltalk put: stx->ref.sysdic */
|
|
ADD_TO_SYSDIC (stx, tmp, stx->ref.sysdic);
|
|
|
|
NEW_SYMBOL_TO (stx, tmp, QSE_T("SymbolTable"));
|
|
/* Smalltalk at: #SymbolTable put: stx->ref.sysdic */
|
|
ADD_TO_SYSDIC (stx, tmp, stx->ref.symtab);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int make_true_and_false (qse_stx_t* stx)
|
|
{
|
|
stx->ref.true = qse_stx_instantiate (
|
|
stx, find_class(stx,QSE_T("True")),
|
|
QSE_NULL, QSE_NULL, 0
|
|
);
|
|
if (ISNIL(stx,stx->ref.true)) return -1;
|
|
|
|
stx->ref.false = qse_stx_instantiate (
|
|
stx, find_class(stx,QSE_T("False")),
|
|
QSE_NULL, QSE_NULL, 0
|
|
);
|
|
if (ISNIL(stx,stx->ref.false)) return -1;
|
|
return 0;
|
|
}
|
|
|
|
static void filein_kernel_source (qse_stx_t* stx)
|
|
{
|
|
class_info_t* p;
|
|
|
|
for (p = class_info; p->name != QSE_NULL; p++)
|
|
{
|
|
/* TODO: */
|
|
}
|
|
}
|
|
|
|
int qse_stx_boot (qse_stx_t* stx)
|
|
{
|
|
/* you must not call this function more than once... */
|
|
QSE_ASSERTX (
|
|
stx->ref.nil == 0 &&
|
|
stx->ref.true == 0 &&
|
|
stx->ref.false == 0,
|
|
"You must not call qse_stx_boot() more than once"
|
|
);
|
|
|
|
if (sketch_nil (stx) <= -1) return -1;
|
|
|
|
if (sketch_key_objects (stx) <= -1) return -1;
|
|
|
|
if (make_key_classes (stx) <= -1) return -1;
|
|
|
|
set_class_of_more_key_objects (stx);
|
|
|
|
if (make_intrinsic_classes (stx) <= -1) return -1;
|
|
|
|
make_metaclass_top_hierarchy (stx);
|
|
|
|
if (make_key_objects_accessible_by_name (stx) <= -1) return -1;
|
|
|
|
if (make_true_and_false (stx) <= -1) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* for debugging for the time begin ... */
|
|
qse_word_t qse_stx_findclass (qse_stx_t* stx, const qse_char_t* name)
|
|
{
|
|
return find_class (stx, name);
|
|
}
|