Finish removing FORM type as well as symbol type.

This commit is contained in:
Calvin Rose 2017-02-13 18:58:56 -05:00
parent 9cbe36cb01
commit d28a7174af
5 changed files with 112 additions and 226 deletions

130
compile.c
View File

@ -318,7 +318,7 @@ static uint16_t CompilerAddLiteral(Compiler * c, Scope * scope, Value x) {
/* Declare a symbol in a given scope. */
static uint16_t CompilerDeclareSymbol(Compiler * c, Scope * scope, Value sym) {
if (sym.type != TYPE_SYMBOL) {
if (sym.type != TYPE_STRING) {
CError(c, "Expected symbol");
}
Value x;
@ -449,47 +449,6 @@ static Slot CompileSymbol(Compiler * c, FormOptions opts, Value sym) {
return ret;
}
/* Compile a dictionary literal. The order of compilation
* is undefined, although a key is evalated before its value,
* assuming the dictionary is unchanged by macros. */
static Slot CompileDict(Compiler * c, FormOptions opts, Dictionary * dict) {
Scope * scope = c->tail;
Buffer * buffer = c->buffer;
Slot ret;
FormOptions subOpts = FormOptionsDefault();
DictionaryIterator iter;
DictBucket * bucket;
SlotTracker tracker;
/* Calculate sub flags */
subOpts.resultUnused = opts.resultUnused;
/* Compile all of the arguments */
CompilerTrackerInit(c, &tracker);
DictIterate(dict, &iter);
while (DictIterateNext(&iter, &bucket)) {
Slot keySlot = CompileValue(c, subOpts, bucket->key);
if (subOpts.resultUnused) CompilerDropSlot(c, scope, keySlot);
Slot valueSlot = CompileValue(c, subOpts, bucket->value);
if (subOpts.resultUnused) CompilerDropSlot(c, scope, valueSlot);
if (!subOpts.resultUnused) {
CompilerTrackerPush(c, &tracker, keySlot);
CompilerTrackerPush(c, &tracker, valueSlot);
}
}
/* Free up slots */
CompilerTrackerFree(c, scope, &tracker);
if (opts.resultUnused) {
ret = NilSlot();
} else {
ret = CompilerGetTarget(c, opts);
BufferPushUInt16(c->vm, buffer, VM_OP_DIC);
BufferPushUInt16(c->vm, buffer, ret.index);
BufferPushUInt16(c->vm, buffer, dict->count * 2);
}
/* Write the location of all of the arguments */
CompilerTrackerWrite(c, &tracker, 0);
return ret;
}
/* Compile values in an array sequentail and track the returned slots.
* If the result is unused, immediately drop slots we don't need. Can
* also ignore the end of an array. */
@ -514,30 +473,6 @@ static void CompilerTrackerInitArray(Compiler * c, FormOptions opts,
}
}
/* Compile an array literal. The array is evaluated left
* to right. Arrays are normally compiled as forms to be evaluated, however. */
static Slot CompileArray(Compiler * c, FormOptions opts, Array * array) {
Scope * scope = c->tail;
Buffer * buffer = c->buffer;
Slot ret;
SlotTracker tracker;
/* Compile contents of array */
CompilerTrackerInitArray(c, opts, &tracker, array, 0, 0);
/* Free up slots in tracker */
CompilerTrackerFree(c, scope, &tracker);
if (opts.resultUnused) {
ret = NilSlot();
} else {
ret = CompilerGetTarget(c, opts);
BufferPushUInt16(c->vm, buffer, VM_OP_ARR);
BufferPushUInt16(c->vm, buffer, ret.index);
BufferPushUInt16(c->vm, buffer, array->count);
}
/* Write the location of all of the arguments */
CompilerTrackerWrite(c, &tracker, 0);
return ret;
}
/* Compile a special form in the form of an operator. There
* are four choices for opcodes - when the operator is called
* with 0, 1, 2, or n arguments. When the operator form is
@ -567,10 +502,7 @@ static Slot CompileOperator(Compiler * c, FormOptions opts, Array * form,
if (form->count < 2) {
if (op0 < 0) {
if (opn < 0) CError(c, "This operator does not take 0 arguments.");
/* Use multiple form of op */
BufferPushUInt16(c->vm, buffer, opn);
BufferPushUInt16(c->vm, buffer, ret.index);
BufferPushUInt16(c->vm, buffer, 0);
goto opn;
} else {
BufferPushUInt16(c->vm, buffer, op0);
BufferPushUInt16(c->vm, buffer, ret.index);
@ -578,19 +510,21 @@ static Slot CompileOperator(Compiler * c, FormOptions opts, Array * form,
} else if (form->count == 2) {
if (op1 < 0) {
if (opn < 0) CError(c, "This operator does not take 1 argument.");
/* Use multiple form of op */
BufferPushUInt16(c->vm, buffer, opn);
BufferPushUInt16(c->vm, buffer, ret.index);
BufferPushUInt16(c->vm, buffer, 1);
goto opn;
} else {
BufferPushUInt16(c->vm, buffer, op1);
BufferPushUInt16(c->vm, buffer, ret.index);
}
} else if (form->count == 3) {
if (op2 < 0) CError(c, "This operator does not take 2 arguments.");
BufferPushUInt16(c->vm, buffer, op2);
BufferPushUInt16(c->vm, buffer, ret.index);
if (op2 < 0) {
if (opn < 0) CError(c, "This operator does not take 2 arguments.");
goto opn;
} else {
BufferPushUInt16(c->vm, buffer, op2);
BufferPushUInt16(c->vm, buffer, ret.index);
}
} else {
opn:
if (opn < 0) CError(c, "This operator does not take n arguments.");
BufferPushUInt16(c->vm, buffer, opn);
BufferPushUInt16(c->vm, buffer, ret.index);
@ -636,6 +570,17 @@ static Slot CompileNot(Compiler * c, FormOptions opts, Array * form) {
static Slot CompileGet(Compiler * c, FormOptions opts, Array * form) {
return CompileOperator(c, opts, form, -1, -1, VM_OP_GET, -1, 0);
}
static Slot CompileArray(Compiler * c, FormOptions opts, Array * form) {
return CompileOperator(c, opts, form, -1, -1, -1, VM_OP_ARR, 0);
}
static Slot CompileDict(Compiler * c, FormOptions opts, Array * form) {
if ((form->count % 2) == 0) {
CError(c, "Dictionary literal requires an even number of arguments");
return NilSlot();
} else {
return CompileOperator(c, opts, form, -1, -1, -1, VM_OP_DIC, 0);
}
}
/* Associative set */
static Slot CompileSet(Compiler * c, FormOptions opts, Array * form) {
@ -786,7 +731,7 @@ static Slot CompileFunction(Compiler * c, FormOptions opts, Array * form) {
params = form->data[current++].data.array;
for (i = 0; i < params->count; ++i) {
Value param = params->data[i];
if (param.type != TYPE_SYMBOL)
if (param.type != TYPE_STRING)
CError(c, "Function parameters should be symbols");
/* The compiler puts the parameter locals
* in the right place by default - at the beginning
@ -975,7 +920,7 @@ typedef Slot (*SpecialFormHelper) (Compiler * c, FormOptions opts, Array * form)
/* Dispatch to a special form */
static SpecialFormHelper GetSpecial(Array * form) {
uint8_t * name;
if (form->count < 1 || form->data[0].type != TYPE_SYMBOL)
if (form->count < 1 || form->data[0].type != TYPE_STRING)
return NULL;
name = form->data[0].data.string;
/* If we have a symbol with a zero length name, we have other
@ -1014,6 +959,16 @@ static SpecialFormHelper GetSpecial(Array * form) {
}
}
break;
case 'a':
{
if (VStringSize(name) == 5 &&
name[1] == 'r' &&
name[2] == 'r' &&
name[3] == 'a' &&
name[4] == 'y') {
return CompileArray;
}
}
case 'g':
{
if (VStringSize(name) == 3 &&
@ -1027,6 +982,11 @@ static SpecialFormHelper GetSpecial(Array * form) {
if (VStringSize(name) == 2 &&
name[1] == 'o') {
return CompileDo;
} else if (VStringSize(name) == 4 &&
name[1] == 'i' &&
name[2] == 'c' &&
name[3] == 't') {
return CompileDict;
}
}
break;
@ -1156,14 +1116,10 @@ static Slot CompileValue(Compiler * c, FormOptions opts, Value x) {
case TYPE_BOOLEAN:
case TYPE_NUMBER:
return CompileNonReferenceType(c, opts, x);
case TYPE_SYMBOL:
case TYPE_STRING:
return CompileSymbol(c, opts, x);
case TYPE_FORM:
return CompileForm(c, opts, x.data.array);
case TYPE_ARRAY:
return CompileArray(c, opts, x.data.array);
case TYPE_DICTIONARY:
return CompileDict(c, opts, x.data.dict);
return CompileForm(c, opts, x.data.array);
default:
return CompileLiteral(c, opts, x);
}
@ -1182,7 +1138,7 @@ void CompilerInit(Compiler * c, VM * vm) {
/* Register a global for the compilation environment. */
void CompilerAddGlobal(Compiler * c, const char * name, Value x) {
Value sym = ValueLoadCString(c->vm, name);
sym.type = TYPE_SYMBOL;
sym.type = TYPE_STRING;
CompilerDeclareSymbol(c, c->tail, sym);
ArrayPush(c->vm, c->env, x);
}
@ -1235,7 +1191,7 @@ Func * CompilerCompile(Compiler * c, Value form) {
* about garbage collection and other issues that would complicate both the
* runtime and the compilation. */
int CompileMacroExpand(VM * vm, Value x, Dictionary * macros, Value * out) {
while (x.type == TYPE_FORM) {
while (x.type == TYPE_ARRAY) {
Array * form = x.data.array;
Value sym, macroFn;
if (form->count == 0) break;

View File

@ -13,10 +13,8 @@ typedef enum Type {
TYPE_NUMBER,
TYPE_BOOLEAN,
TYPE_STRING,
TYPE_SYMBOL,
TYPE_ARRAY,
TYPE_THREAD,
TYPE_FORM,
TYPE_BYTEBUFFER,
TYPE_FUNCTION,
TYPE_CFUNCTION,

176
parse.c
View File

@ -5,6 +5,7 @@
#include "datatypes.h"
#include "ds.h"
#include "parse.h"
#include "value.h"
#include "vm.h"
static const char UNEXPECTED_CLOSING_DELIM[] = "Unexpected closing delimiter";
@ -12,9 +13,7 @@ static const char UNEXPECTED_CLOSING_DELIM[] = "Unexpected closing delimiter";
/* The type of a ParseState */
typedef enum ParseType {
PTYPE_ROOT,
PTYPE_ARRAY,
PTYPE_FORM,
PTYPE_DICTIONARY,
PTYPE_STRING,
PTYPE_TOKEN
} ParseType;
@ -23,12 +22,10 @@ typedef enum ParseType {
struct ParseState {
ParseType type;
union {
Array * array;
struct {
Dictionary * dict;
Value key;
int keyFound;
} dictState;
uint8_t endDelimiter;
Array * array;
} form;
struct {
Buffer * buffer;
enum {
@ -63,7 +60,7 @@ static ParseState * ParserPop(Parser * p) {
}
/* Add a new, empty ParseState to the ParseStack. */
static void ParserPush(Parser *p, ParseType type) {
static void ParserPush(Parser *p, ParseType type, uint8_t character) {
ParseState * top;
if (p->count >= p->cap) {
uint32_t newCap = 2 * p->count;
@ -83,13 +80,17 @@ static void ParserPush(Parser *p, ParseType type) {
case PTYPE_TOKEN:
top->buf.string.buffer = BufferNew(p->vm, 10);
break;
case PTYPE_ARRAY:
case PTYPE_FORM:
top->buf.array = ArrayNew(p->vm, 10);
break;
case PTYPE_DICTIONARY:
top->buf.dictState.dict = DictNew(p->vm, 10);
top->buf.dictState.keyFound = 0;
top->buf.form.array = ArrayNew(p->vm, 10);
if (character == '(') top->buf.form.endDelimiter = ')';
if (character == '[') {
top->buf.form.endDelimiter = ']';
ArrayPush(p->vm, top->buf.form.array, ValueLoadCString(p->vm, "array"));
}
if (character == '{') {
top->buf.form.endDelimiter = '}';
ArrayPush(p->vm, top->buf.form.array, ValueLoadCString(p->vm, "dict"));
}
break;
}
}
@ -103,17 +104,8 @@ static void ParserTopAppend(Parser * p, Value x) {
p->value = x;
p->status = PARSER_FULL;
break;
case PTYPE_ARRAY:
case PTYPE_FORM:
ArrayPush(p->vm, top->buf.array, x);
break;
case PTYPE_DICTIONARY:
if (top->buf.dictState.keyFound) {
DictPut(p->vm, top->buf.dictState.dict, top->buf.dictState.key, x);
} else {
top->buf.dictState.key = x;
}
top->buf.dictState.keyFound = !top->buf.dictState.keyFound;
ArrayPush(p->vm, top->buf.form.array, x);
break;
default:
PError(p, "Expected container type.");
@ -204,33 +196,6 @@ static int checkStrConst(const char * ref, const uint8_t * start, const uint8_t
return !*ref && start == end;
}
/* Handle parsing generic input */
static int ParserMainState(Parser * p, uint8_t c) {
if (c == '(') {
ParserPush(p, PTYPE_FORM);
return 1;
}
if (c == '[') {
ParserPush(p, PTYPE_ARRAY);
return 1;
}
if (c == '{') {
ParserPush(p, PTYPE_DICTIONARY);
return 1;
}
if (c == '"') {
ParserPush(p, PTYPE_STRING);
return 1;
}
if (isWhitespace(c)) return 1;
if (isSymbolChar(c)) {
ParserPush(p, PTYPE_TOKEN);
return 0;
}
PError(p, "Unexpected character.");
return 1;
}
/* Build from the token buffer */
static Value ParserBuildTokenBuffer(Parser * p, Buffer * buf) {
Value x;
@ -254,7 +219,7 @@ static Value ParserBuildTokenBuffer(Parser * p, Buffer * buf) {
PError(p, "Symbols cannot start with digits.");
x.type = TYPE_NIL;
} else {
x.type = TYPE_SYMBOL;
x.type = TYPE_STRING;
x.data.string = BufferToString(p->vm, buf);
}
}
@ -286,11 +251,16 @@ static int ParserStringState(Parser * p, uint8_t c) {
if (c == '\\') {
top->buf.string.state = STRING_STATE_ESCAPE;
} else if (c == '"') {
Value x;
/* Load a quote form to get the string literal */
Value x, array;
x.type = TYPE_STRING;
x.data.string = BufferToString(p->vm, top->buf.string.buffer);
array.type = TYPE_ARRAY;
array.data.array = ArrayNew(p->vm, 2);
ArrayPush(p->vm, array.data.array, ValueLoadCString(p->vm, "quote"));
ArrayPush(p->vm, array.data.array, x);
ParserPop(p);
ParserTopAppend(p, x);
ParserTopAppend(p, array);
} else {
BufferPush(p->vm, top->buf.string.buffer, c);
}
@ -323,72 +293,42 @@ static int ParserStringState(Parser * p, uint8_t c) {
return 1;
}
/* Handle parsing a form */
static int ParserFormState(Parser * p, uint8_t c) {
if (c == ')') {
ParseState * top = ParserPop(p);
Array * array = top->buf.array;
Value x;
x.type = TYPE_FORM;
x.data.array = array;
ParserTopAppend(p, x);
return 1;
} else if (c == ']' || c == '}') {
PError(p, UNEXPECTED_CLOSING_DELIM);
return 1;
} else {
return ParserMainState(p, c);
}
}
/* Handle parsing an array */
static int ParserArrayState(Parser * p, uint8_t c) {
if (c == ']') {
ParseState * top = ParserPop(p);
Array * array = top->buf.array;
Value x;
x.type = TYPE_ARRAY;
x.data.array = array;
ParserTopAppend(p, x);
return 1;
} else if (c == ')' || c == '}') {
PError(p, UNEXPECTED_CLOSING_DELIM);
return 1;
} else {
return ParserMainState(p, c);
}
}
/* Handle parsing a dictionary */
static int ParserDictState(Parser * p, uint8_t c) {
if (c == '}') {
ParseState * top = ParserPop(p);
if (!top->buf.dictState.keyFound) {
Value x;
x.type = TYPE_DICTIONARY;
x.data.dict = top->buf.dictState.dict;
ParserTopAppend(p, x);
return 1;
} else {
PError(p, "Odd number of items in dictionary literal.");
return 1;
}
} else if (c == ')' || c == ']') {
PError(p, UNEXPECTED_CLOSING_DELIM);
return 1;
} else {
return ParserMainState(p, c);
}
}
/* Root state of the parser */
static int ParserRootState(Parser * p, uint8_t c) {
if (c == ']' || c == ')' || c == '}') {
PError(p, UNEXPECTED_CLOSING_DELIM);
return 1;
} else {
return ParserMainState(p, c);
}
if (c == '(' || c == '[' || c == '{') {
ParserPush(p, PTYPE_FORM, c);
return 1;
}
if (c == '"') {
ParserPush(p, PTYPE_STRING, c);
return 1;
}
if (isWhitespace(c)) return 1;
if (isSymbolChar(c)) {
ParserPush(p, PTYPE_TOKEN, c);
return 0;
}
PError(p, "Unexpected character.");
return 1;
}
/* Handle parsing a form */
static int ParserFormState(Parser * p, uint8_t c) {
ParseState * top = ParserPeek(p);
if (c == top->buf.form.endDelimiter) {
Array * array = top->buf.form.array;
Value x;
x.type = TYPE_ARRAY;
x.data.array = array;
ParserPop(p);
ParserTopAppend(p, x);
return 1;
}
return ParserRootState(p, c);
}
/* Handle a character */
@ -406,15 +346,9 @@ static int ParserDispatchChar(Parser * p, uint8_t c) {
case PTYPE_FORM:
done = ParserFormState(p, c);
break;
case PTYPE_ARRAY:
done = ParserArrayState(p, c);
break;
case PTYPE_STRING:
done = ParserStringState(p, c);
break;
case PTYPE_DICTIONARY:
done = ParserDictState(p, c);
break;
}
}
++p->index;
@ -446,5 +380,5 @@ void ParserInit(Parser * p, VM * vm) {
p->error = NULL;
p->status = PARSER_PENDING;
p->value.type = TYPE_NIL;
ParserPush(p, PTYPE_ROOT);
ParserPush(p, PTYPE_ROOT, ' ');
}

28
value.c
View File

@ -62,7 +62,7 @@ static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlele
}
*c++ = '>';
VStringHash(data) = 0;
VStringSize(data) = len;
VStringSize(data) = c - data;
return data;
}
@ -80,11 +80,21 @@ uint8_t * ValueToString(VM * vm, Value x) {
case TYPE_NUMBER:
return NumberToString(vm, x.data.number);
case TYPE_ARRAY:
{
uint32_t i;
Buffer * b = BufferNew(vm, 40);
BufferPush(vm, b, '(');
for (i = 0; i < x.data.array->count; ++i) {
uint8_t * substr = ValueToString(vm, x.data.array->data[i]);
BufferAppendData(vm, b, substr, VStringSize(substr));
if (i < x.data.array->count - 1)
BufferPush(vm, b, ' ');
}
BufferPush(vm, b, ')');
return BufferToString(vm, b);
}
return StringDescription(vm, "array", 5, x.data.pointer);
case TYPE_FORM:
return StringDescription(vm, "form", 4, x.data.pointer);
case TYPE_STRING:
case TYPE_SYMBOL:
return x.data.string;
case TYPE_BYTEBUFFER:
return StringDescription(vm, "buffer", 6, x.data.pointer);
@ -128,8 +138,6 @@ int ValueEqual(Value x, Value y) {
/* Assume that when strings are created, equal strings
* are set to the same string */
case TYPE_STRING:
/* TODO: keep cache to for symbols to get quick equality. */
case TYPE_SYMBOL:
if (x.data.string == y.data.string) {
result = 1;
break;
@ -146,7 +154,6 @@ int ValueEqual(Value x, Value y) {
result = 0;
break;
case TYPE_ARRAY:
case TYPE_FORM:
case TYPE_BYTEBUFFER:
case TYPE_CFUNCTION:
case TYPE_DICTIONARY:
@ -181,7 +188,6 @@ uint32_t ValueHash(Value x) {
}
break;
/* String hashes */
case TYPE_SYMBOL:
case TYPE_STRING:
/* Assume 0 is not hashed. */
if (VStringHash(x.data.string))
@ -190,7 +196,6 @@ uint32_t ValueHash(Value x) {
hash = VStringHash(x.data.string) = djb2(x.data.string);
break;
case TYPE_ARRAY:
case TYPE_FORM:
case TYPE_BYTEBUFFER:
case TYPE_CFUNCTION:
case TYPE_DICTIONARY:
@ -232,7 +237,6 @@ int ValueCompare(Value x, Value y) {
return x.data.number > y.data.number ? 1 : -1;
}
case TYPE_STRING:
case TYPE_SYMBOL:
if (x.data.string == y.data.string) {
return 0;
} else {
@ -256,7 +260,6 @@ int ValueCompare(Value x, Value y) {
}
}
case TYPE_ARRAY:
case TYPE_FORM:
case TYPE_BYTEBUFFER:
case TYPE_CFUNCTION:
case TYPE_FUNCTION:
@ -308,7 +311,6 @@ Value ValueGet(VM * vm, Value ds, Value key) {
Value ret;
switch (ds.type) {
case TYPE_ARRAY:
case TYPE_FORM:
VMAssertType(vm, key, TYPE_NUMBER);
index = ToIndex(key.data.number, ds.data.array->count);
if (index == -1) VMError(vm, "Invalid array access");
@ -320,7 +322,6 @@ Value ValueGet(VM * vm, Value ds, Value key) {
ret.type = TYPE_NUMBER;
ret.data.number = ds.data.buffer->data[index];
break;
case TYPE_SYMBOL:
case TYPE_STRING:
VMAssertType(vm, key, TYPE_NUMBER);
index = ToIndex(key.data.number, VStringSize(ds.data.string));
@ -341,7 +342,6 @@ void ValueSet(VM * vm, Value ds, Value key, Value value) {
int32_t index;
switch (ds.type) {
case TYPE_ARRAY:
case TYPE_FORM:
VMAssertType(vm, key, TYPE_NUMBER);
index = ToIndex(key.data.number, ds.data.array->count);
if (index == -1) VMError(vm, "Invalid array access");

2
vm.c
View File

@ -97,7 +97,6 @@ static void VMMark(VM * vm, Value * x) {
break;
case TYPE_STRING:
case TYPE_SYMBOL:
GCHeader(VStringRaw(x->data.string))->color = vm->black;
break;
@ -107,7 +106,6 @@ static void VMMark(VM * vm, Value * x) {
break;
case TYPE_ARRAY:
case TYPE_FORM:
if (GCHeader(x->data.array)->color != vm->black) {
uint32_t i, count;
count = x->data.array->count;