mirror of
https://github.com/janet-lang/janet
synced 2024-12-26 08:20:27 +00:00
Finish removing FORM type as well as symbol type.
This commit is contained in:
parent
9cbe36cb01
commit
d28a7174af
126
compile.c
126
compile.c
@ -318,7 +318,7 @@ static uint16_t CompilerAddLiteral(Compiler * c, Scope * scope, Value x) {
|
|||||||
|
|
||||||
/* Declare a symbol in a given scope. */
|
/* Declare a symbol in a given scope. */
|
||||||
static uint16_t CompilerDeclareSymbol(Compiler * c, Scope * scope, Value sym) {
|
static uint16_t CompilerDeclareSymbol(Compiler * c, Scope * scope, Value sym) {
|
||||||
if (sym.type != TYPE_SYMBOL) {
|
if (sym.type != TYPE_STRING) {
|
||||||
CError(c, "Expected symbol");
|
CError(c, "Expected symbol");
|
||||||
}
|
}
|
||||||
Value x;
|
Value x;
|
||||||
@ -449,47 +449,6 @@ static Slot CompileSymbol(Compiler * c, FormOptions opts, Value sym) {
|
|||||||
return ret;
|
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.
|
/* Compile values in an array sequentail and track the returned slots.
|
||||||
* If the result is unused, immediately drop slots we don't need. Can
|
* If the result is unused, immediately drop slots we don't need. Can
|
||||||
* also ignore the end of an array. */
|
* 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
|
/* Compile a special form in the form of an operator. There
|
||||||
* are four choices for opcodes - when the operator is called
|
* are four choices for opcodes - when the operator is called
|
||||||
* with 0, 1, 2, or n arguments. When the operator form is
|
* 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 (form->count < 2) {
|
||||||
if (op0 < 0) {
|
if (op0 < 0) {
|
||||||
if (opn < 0) CError(c, "This operator does not take 0 arguments.");
|
if (opn < 0) CError(c, "This operator does not take 0 arguments.");
|
||||||
/* Use multiple form of op */
|
goto opn;
|
||||||
BufferPushUInt16(c->vm, buffer, opn);
|
|
||||||
BufferPushUInt16(c->vm, buffer, ret.index);
|
|
||||||
BufferPushUInt16(c->vm, buffer, 0);
|
|
||||||
} else {
|
} else {
|
||||||
BufferPushUInt16(c->vm, buffer, op0);
|
BufferPushUInt16(c->vm, buffer, op0);
|
||||||
BufferPushUInt16(c->vm, buffer, ret.index);
|
BufferPushUInt16(c->vm, buffer, ret.index);
|
||||||
@ -578,19 +510,21 @@ static Slot CompileOperator(Compiler * c, FormOptions opts, Array * form,
|
|||||||
} else if (form->count == 2) {
|
} else if (form->count == 2) {
|
||||||
if (op1 < 0) {
|
if (op1 < 0) {
|
||||||
if (opn < 0) CError(c, "This operator does not take 1 argument.");
|
if (opn < 0) CError(c, "This operator does not take 1 argument.");
|
||||||
/* Use multiple form of op */
|
goto opn;
|
||||||
BufferPushUInt16(c->vm, buffer, opn);
|
|
||||||
BufferPushUInt16(c->vm, buffer, ret.index);
|
|
||||||
BufferPushUInt16(c->vm, buffer, 1);
|
|
||||||
} else {
|
} else {
|
||||||
BufferPushUInt16(c->vm, buffer, op1);
|
BufferPushUInt16(c->vm, buffer, op1);
|
||||||
BufferPushUInt16(c->vm, buffer, ret.index);
|
BufferPushUInt16(c->vm, buffer, ret.index);
|
||||||
}
|
}
|
||||||
} else if (form->count == 3) {
|
} else if (form->count == 3) {
|
||||||
if (op2 < 0) CError(c, "This operator does not take 2 arguments.");
|
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, op2);
|
||||||
BufferPushUInt16(c->vm, buffer, ret.index);
|
BufferPushUInt16(c->vm, buffer, ret.index);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
opn:
|
||||||
if (opn < 0) CError(c, "This operator does not take n arguments.");
|
if (opn < 0) CError(c, "This operator does not take n arguments.");
|
||||||
BufferPushUInt16(c->vm, buffer, opn);
|
BufferPushUInt16(c->vm, buffer, opn);
|
||||||
BufferPushUInt16(c->vm, buffer, ret.index);
|
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) {
|
static Slot CompileGet(Compiler * c, FormOptions opts, Array * form) {
|
||||||
return CompileOperator(c, opts, form, -1, -1, VM_OP_GET, -1, 0);
|
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 */
|
/* Associative set */
|
||||||
static Slot CompileSet(Compiler * c, FormOptions opts, Array * form) {
|
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;
|
params = form->data[current++].data.array;
|
||||||
for (i = 0; i < params->count; ++i) {
|
for (i = 0; i < params->count; ++i) {
|
||||||
Value param = params->data[i];
|
Value param = params->data[i];
|
||||||
if (param.type != TYPE_SYMBOL)
|
if (param.type != TYPE_STRING)
|
||||||
CError(c, "Function parameters should be symbols");
|
CError(c, "Function parameters should be symbols");
|
||||||
/* The compiler puts the parameter locals
|
/* The compiler puts the parameter locals
|
||||||
* in the right place by default - at the beginning
|
* 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 */
|
/* Dispatch to a special form */
|
||||||
static SpecialFormHelper GetSpecial(Array * form) {
|
static SpecialFormHelper GetSpecial(Array * form) {
|
||||||
uint8_t * name;
|
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;
|
return NULL;
|
||||||
name = form->data[0].data.string;
|
name = form->data[0].data.string;
|
||||||
/* If we have a symbol with a zero length name, we have other
|
/* If we have a symbol with a zero length name, we have other
|
||||||
@ -1014,6 +959,16 @@ static SpecialFormHelper GetSpecial(Array * form) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'a':
|
||||||
|
{
|
||||||
|
if (VStringSize(name) == 5 &&
|
||||||
|
name[1] == 'r' &&
|
||||||
|
name[2] == 'r' &&
|
||||||
|
name[3] == 'a' &&
|
||||||
|
name[4] == 'y') {
|
||||||
|
return CompileArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
case 'g':
|
case 'g':
|
||||||
{
|
{
|
||||||
if (VStringSize(name) == 3 &&
|
if (VStringSize(name) == 3 &&
|
||||||
@ -1027,6 +982,11 @@ static SpecialFormHelper GetSpecial(Array * form) {
|
|||||||
if (VStringSize(name) == 2 &&
|
if (VStringSize(name) == 2 &&
|
||||||
name[1] == 'o') {
|
name[1] == 'o') {
|
||||||
return CompileDo;
|
return CompileDo;
|
||||||
|
} else if (VStringSize(name) == 4 &&
|
||||||
|
name[1] == 'i' &&
|
||||||
|
name[2] == 'c' &&
|
||||||
|
name[3] == 't') {
|
||||||
|
return CompileDict;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1156,14 +1116,10 @@ static Slot CompileValue(Compiler * c, FormOptions opts, Value x) {
|
|||||||
case TYPE_BOOLEAN:
|
case TYPE_BOOLEAN:
|
||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
return CompileNonReferenceType(c, opts, x);
|
return CompileNonReferenceType(c, opts, x);
|
||||||
case TYPE_SYMBOL:
|
case TYPE_STRING:
|
||||||
return CompileSymbol(c, opts, x);
|
return CompileSymbol(c, opts, x);
|
||||||
case TYPE_FORM:
|
|
||||||
return CompileForm(c, opts, x.data.array);
|
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
return CompileArray(c, opts, x.data.array);
|
return CompileForm(c, opts, x.data.array);
|
||||||
case TYPE_DICTIONARY:
|
|
||||||
return CompileDict(c, opts, x.data.dict);
|
|
||||||
default:
|
default:
|
||||||
return CompileLiteral(c, opts, x);
|
return CompileLiteral(c, opts, x);
|
||||||
}
|
}
|
||||||
@ -1182,7 +1138,7 @@ void CompilerInit(Compiler * c, VM * vm) {
|
|||||||
/* Register a global for the compilation environment. */
|
/* Register a global for the compilation environment. */
|
||||||
void CompilerAddGlobal(Compiler * c, const char * name, Value x) {
|
void CompilerAddGlobal(Compiler * c, const char * name, Value x) {
|
||||||
Value sym = ValueLoadCString(c->vm, name);
|
Value sym = ValueLoadCString(c->vm, name);
|
||||||
sym.type = TYPE_SYMBOL;
|
sym.type = TYPE_STRING;
|
||||||
CompilerDeclareSymbol(c, c->tail, sym);
|
CompilerDeclareSymbol(c, c->tail, sym);
|
||||||
ArrayPush(c->vm, c->env, x);
|
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
|
* about garbage collection and other issues that would complicate both the
|
||||||
* runtime and the compilation. */
|
* runtime and the compilation. */
|
||||||
int CompileMacroExpand(VM * vm, Value x, Dictionary * macros, Value * out) {
|
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;
|
Array * form = x.data.array;
|
||||||
Value sym, macroFn;
|
Value sym, macroFn;
|
||||||
if (form->count == 0) break;
|
if (form->count == 0) break;
|
||||||
|
@ -13,10 +13,8 @@ typedef enum Type {
|
|||||||
TYPE_NUMBER,
|
TYPE_NUMBER,
|
||||||
TYPE_BOOLEAN,
|
TYPE_BOOLEAN,
|
||||||
TYPE_STRING,
|
TYPE_STRING,
|
||||||
TYPE_SYMBOL,
|
|
||||||
TYPE_ARRAY,
|
TYPE_ARRAY,
|
||||||
TYPE_THREAD,
|
TYPE_THREAD,
|
||||||
TYPE_FORM,
|
|
||||||
TYPE_BYTEBUFFER,
|
TYPE_BYTEBUFFER,
|
||||||
TYPE_FUNCTION,
|
TYPE_FUNCTION,
|
||||||
TYPE_CFUNCTION,
|
TYPE_CFUNCTION,
|
||||||
|
176
parse.c
176
parse.c
@ -5,6 +5,7 @@
|
|||||||
#include "datatypes.h"
|
#include "datatypes.h"
|
||||||
#include "ds.h"
|
#include "ds.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
#include "value.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
static const char UNEXPECTED_CLOSING_DELIM[] = "Unexpected closing delimiter";
|
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 */
|
/* The type of a ParseState */
|
||||||
typedef enum ParseType {
|
typedef enum ParseType {
|
||||||
PTYPE_ROOT,
|
PTYPE_ROOT,
|
||||||
PTYPE_ARRAY,
|
|
||||||
PTYPE_FORM,
|
PTYPE_FORM,
|
||||||
PTYPE_DICTIONARY,
|
|
||||||
PTYPE_STRING,
|
PTYPE_STRING,
|
||||||
PTYPE_TOKEN
|
PTYPE_TOKEN
|
||||||
} ParseType;
|
} ParseType;
|
||||||
@ -23,12 +22,10 @@ typedef enum ParseType {
|
|||||||
struct ParseState {
|
struct ParseState {
|
||||||
ParseType type;
|
ParseType type;
|
||||||
union {
|
union {
|
||||||
Array * array;
|
|
||||||
struct {
|
struct {
|
||||||
Dictionary * dict;
|
uint8_t endDelimiter;
|
||||||
Value key;
|
Array * array;
|
||||||
int keyFound;
|
} form;
|
||||||
} dictState;
|
|
||||||
struct {
|
struct {
|
||||||
Buffer * buffer;
|
Buffer * buffer;
|
||||||
enum {
|
enum {
|
||||||
@ -63,7 +60,7 @@ static ParseState * ParserPop(Parser * p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add a new, empty ParseState to the ParseStack. */
|
/* 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;
|
ParseState * top;
|
||||||
if (p->count >= p->cap) {
|
if (p->count >= p->cap) {
|
||||||
uint32_t newCap = 2 * p->count;
|
uint32_t newCap = 2 * p->count;
|
||||||
@ -83,13 +80,17 @@ static void ParserPush(Parser *p, ParseType type) {
|
|||||||
case PTYPE_TOKEN:
|
case PTYPE_TOKEN:
|
||||||
top->buf.string.buffer = BufferNew(p->vm, 10);
|
top->buf.string.buffer = BufferNew(p->vm, 10);
|
||||||
break;
|
break;
|
||||||
case PTYPE_ARRAY:
|
|
||||||
case PTYPE_FORM:
|
case PTYPE_FORM:
|
||||||
top->buf.array = ArrayNew(p->vm, 10);
|
top->buf.form.array = ArrayNew(p->vm, 10);
|
||||||
break;
|
if (character == '(') top->buf.form.endDelimiter = ')';
|
||||||
case PTYPE_DICTIONARY:
|
if (character == '[') {
|
||||||
top->buf.dictState.dict = DictNew(p->vm, 10);
|
top->buf.form.endDelimiter = ']';
|
||||||
top->buf.dictState.keyFound = 0;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,17 +104,8 @@ static void ParserTopAppend(Parser * p, Value x) {
|
|||||||
p->value = x;
|
p->value = x;
|
||||||
p->status = PARSER_FULL;
|
p->status = PARSER_FULL;
|
||||||
break;
|
break;
|
||||||
case PTYPE_ARRAY:
|
|
||||||
case PTYPE_FORM:
|
case PTYPE_FORM:
|
||||||
ArrayPush(p->vm, top->buf.array, x);
|
ArrayPush(p->vm, top->buf.form.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;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PError(p, "Expected container type.");
|
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;
|
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 */
|
/* Build from the token buffer */
|
||||||
static Value ParserBuildTokenBuffer(Parser * p, Buffer * buf) {
|
static Value ParserBuildTokenBuffer(Parser * p, Buffer * buf) {
|
||||||
Value x;
|
Value x;
|
||||||
@ -254,7 +219,7 @@ static Value ParserBuildTokenBuffer(Parser * p, Buffer * buf) {
|
|||||||
PError(p, "Symbols cannot start with digits.");
|
PError(p, "Symbols cannot start with digits.");
|
||||||
x.type = TYPE_NIL;
|
x.type = TYPE_NIL;
|
||||||
} else {
|
} else {
|
||||||
x.type = TYPE_SYMBOL;
|
x.type = TYPE_STRING;
|
||||||
x.data.string = BufferToString(p->vm, buf);
|
x.data.string = BufferToString(p->vm, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -286,11 +251,16 @@ static int ParserStringState(Parser * p, uint8_t c) {
|
|||||||
if (c == '\\') {
|
if (c == '\\') {
|
||||||
top->buf.string.state = STRING_STATE_ESCAPE;
|
top->buf.string.state = STRING_STATE_ESCAPE;
|
||||||
} else if (c == '"') {
|
} else if (c == '"') {
|
||||||
Value x;
|
/* Load a quote form to get the string literal */
|
||||||
|
Value x, array;
|
||||||
x.type = TYPE_STRING;
|
x.type = TYPE_STRING;
|
||||||
x.data.string = BufferToString(p->vm, top->buf.string.buffer);
|
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);
|
ParserPop(p);
|
||||||
ParserTopAppend(p, x);
|
ParserTopAppend(p, array);
|
||||||
} else {
|
} else {
|
||||||
BufferPush(p->vm, top->buf.string.buffer, c);
|
BufferPush(p->vm, top->buf.string.buffer, c);
|
||||||
}
|
}
|
||||||
@ -323,72 +293,42 @@ static int ParserStringState(Parser * p, uint8_t c) {
|
|||||||
return 1;
|
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 */
|
/* Root state of the parser */
|
||||||
static int ParserRootState(Parser * p, uint8_t c) {
|
static int ParserRootState(Parser * p, uint8_t c) {
|
||||||
if (c == ']' || c == ')' || c == '}') {
|
if (c == ']' || c == ')' || c == '}') {
|
||||||
PError(p, UNEXPECTED_CLOSING_DELIM);
|
PError(p, UNEXPECTED_CLOSING_DELIM);
|
||||||
return 1;
|
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 */
|
/* Handle a character */
|
||||||
@ -406,15 +346,9 @@ static int ParserDispatchChar(Parser * p, uint8_t c) {
|
|||||||
case PTYPE_FORM:
|
case PTYPE_FORM:
|
||||||
done = ParserFormState(p, c);
|
done = ParserFormState(p, c);
|
||||||
break;
|
break;
|
||||||
case PTYPE_ARRAY:
|
|
||||||
done = ParserArrayState(p, c);
|
|
||||||
break;
|
|
||||||
case PTYPE_STRING:
|
case PTYPE_STRING:
|
||||||
done = ParserStringState(p, c);
|
done = ParserStringState(p, c);
|
||||||
break;
|
break;
|
||||||
case PTYPE_DICTIONARY:
|
|
||||||
done = ParserDictState(p, c);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++p->index;
|
++p->index;
|
||||||
@ -446,5 +380,5 @@ void ParserInit(Parser * p, VM * vm) {
|
|||||||
p->error = NULL;
|
p->error = NULL;
|
||||||
p->status = PARSER_PENDING;
|
p->status = PARSER_PENDING;
|
||||||
p->value.type = TYPE_NIL;
|
p->value.type = TYPE_NIL;
|
||||||
ParserPush(p, PTYPE_ROOT);
|
ParserPush(p, PTYPE_ROOT, ' ');
|
||||||
}
|
}
|
||||||
|
28
value.c
28
value.c
@ -62,7 +62,7 @@ static uint8_t * StringDescription(VM * vm, const char * title, uint32_t titlele
|
|||||||
}
|
}
|
||||||
*c++ = '>';
|
*c++ = '>';
|
||||||
VStringHash(data) = 0;
|
VStringHash(data) = 0;
|
||||||
VStringSize(data) = len;
|
VStringSize(data) = c - data;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,11 +80,21 @@ uint8_t * ValueToString(VM * vm, Value x) {
|
|||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
return NumberToString(vm, x.data.number);
|
return NumberToString(vm, x.data.number);
|
||||||
case TYPE_ARRAY:
|
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);
|
return StringDescription(vm, "array", 5, x.data.pointer);
|
||||||
case TYPE_FORM:
|
|
||||||
return StringDescription(vm, "form", 4, x.data.pointer);
|
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
case TYPE_SYMBOL:
|
|
||||||
return x.data.string;
|
return x.data.string;
|
||||||
case TYPE_BYTEBUFFER:
|
case TYPE_BYTEBUFFER:
|
||||||
return StringDescription(vm, "buffer", 6, x.data.pointer);
|
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
|
/* Assume that when strings are created, equal strings
|
||||||
* are set to the same string */
|
* are set to the same string */
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
/* TODO: keep cache to for symbols to get quick equality. */
|
|
||||||
case TYPE_SYMBOL:
|
|
||||||
if (x.data.string == y.data.string) {
|
if (x.data.string == y.data.string) {
|
||||||
result = 1;
|
result = 1;
|
||||||
break;
|
break;
|
||||||
@ -146,7 +154,6 @@ int ValueEqual(Value x, Value y) {
|
|||||||
result = 0;
|
result = 0;
|
||||||
break;
|
break;
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
case TYPE_FORM:
|
|
||||||
case TYPE_BYTEBUFFER:
|
case TYPE_BYTEBUFFER:
|
||||||
case TYPE_CFUNCTION:
|
case TYPE_CFUNCTION:
|
||||||
case TYPE_DICTIONARY:
|
case TYPE_DICTIONARY:
|
||||||
@ -181,7 +188,6 @@ uint32_t ValueHash(Value x) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
/* String hashes */
|
/* String hashes */
|
||||||
case TYPE_SYMBOL:
|
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
/* Assume 0 is not hashed. */
|
/* Assume 0 is not hashed. */
|
||||||
if (VStringHash(x.data.string))
|
if (VStringHash(x.data.string))
|
||||||
@ -190,7 +196,6 @@ uint32_t ValueHash(Value x) {
|
|||||||
hash = VStringHash(x.data.string) = djb2(x.data.string);
|
hash = VStringHash(x.data.string) = djb2(x.data.string);
|
||||||
break;
|
break;
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
case TYPE_FORM:
|
|
||||||
case TYPE_BYTEBUFFER:
|
case TYPE_BYTEBUFFER:
|
||||||
case TYPE_CFUNCTION:
|
case TYPE_CFUNCTION:
|
||||||
case TYPE_DICTIONARY:
|
case TYPE_DICTIONARY:
|
||||||
@ -232,7 +237,6 @@ int ValueCompare(Value x, Value y) {
|
|||||||
return x.data.number > y.data.number ? 1 : -1;
|
return x.data.number > y.data.number ? 1 : -1;
|
||||||
}
|
}
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
case TYPE_SYMBOL:
|
|
||||||
if (x.data.string == y.data.string) {
|
if (x.data.string == y.data.string) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@ -256,7 +260,6 @@ int ValueCompare(Value x, Value y) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
case TYPE_FORM:
|
|
||||||
case TYPE_BYTEBUFFER:
|
case TYPE_BYTEBUFFER:
|
||||||
case TYPE_CFUNCTION:
|
case TYPE_CFUNCTION:
|
||||||
case TYPE_FUNCTION:
|
case TYPE_FUNCTION:
|
||||||
@ -308,7 +311,6 @@ Value ValueGet(VM * vm, Value ds, Value key) {
|
|||||||
Value ret;
|
Value ret;
|
||||||
switch (ds.type) {
|
switch (ds.type) {
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
case TYPE_FORM:
|
|
||||||
VMAssertType(vm, key, TYPE_NUMBER);
|
VMAssertType(vm, key, TYPE_NUMBER);
|
||||||
index = ToIndex(key.data.number, ds.data.array->count);
|
index = ToIndex(key.data.number, ds.data.array->count);
|
||||||
if (index == -1) VMError(vm, "Invalid array access");
|
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.type = TYPE_NUMBER;
|
||||||
ret.data.number = ds.data.buffer->data[index];
|
ret.data.number = ds.data.buffer->data[index];
|
||||||
break;
|
break;
|
||||||
case TYPE_SYMBOL:
|
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
VMAssertType(vm, key, TYPE_NUMBER);
|
VMAssertType(vm, key, TYPE_NUMBER);
|
||||||
index = ToIndex(key.data.number, VStringSize(ds.data.string));
|
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;
|
int32_t index;
|
||||||
switch (ds.type) {
|
switch (ds.type) {
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
case TYPE_FORM:
|
|
||||||
VMAssertType(vm, key, TYPE_NUMBER);
|
VMAssertType(vm, key, TYPE_NUMBER);
|
||||||
index = ToIndex(key.data.number, ds.data.array->count);
|
index = ToIndex(key.data.number, ds.data.array->count);
|
||||||
if (index == -1) VMError(vm, "Invalid array access");
|
if (index == -1) VMError(vm, "Invalid array access");
|
||||||
|
2
vm.c
2
vm.c
@ -97,7 +97,6 @@ static void VMMark(VM * vm, Value * x) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
case TYPE_SYMBOL:
|
|
||||||
GCHeader(VStringRaw(x->data.string))->color = vm->black;
|
GCHeader(VStringRaw(x->data.string))->color = vm->black;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -107,7 +106,6 @@ static void VMMark(VM * vm, Value * x) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
case TYPE_FORM:
|
|
||||||
if (GCHeader(x->data.array)->color != vm->black) {
|
if (GCHeader(x->data.array)->color != vm->black) {
|
||||||
uint32_t i, count;
|
uint32_t i, count;
|
||||||
count = x->data.array->count;
|
count = x->data.array->count;
|
||||||
|
Loading…
Reference in New Issue
Block a user