mirror of
https://github.com/janet-lang/janet
synced 2024-12-25 07:50: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. */
|
||||
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.");
|
||||
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;
|
||||
|
@ -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
176
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, ' ');
|
||||
}
|
||||
|
28
value.c
28
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");
|
||||
|
2
vm.c
2
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;
|
||||
|
Loading…
Reference in New Issue
Block a user