diff --git a/compile.c b/compile.c index 0fa21eab..22aac974 100644 --- a/compile.c +++ b/compile.c @@ -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; diff --git a/datatypes.h b/datatypes.h index 0b8bb18f..6891da81 100644 --- a/datatypes.h +++ b/datatypes.h @@ -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, diff --git a/parse.c b/parse.c index 074eb9ba..8a5f6483 100644 --- a/parse.c +++ b/parse.c @@ -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, ' '); } diff --git a/value.c b/value.c index eb94a849..2dcb1799 100644 --- a/value.c +++ b/value.c @@ -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"); diff --git a/vm.c b/vm.c index 7625acee..fc9a847d 100644 --- a/vm.c +++ b/vm.c @@ -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;