1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-22 21:23:16 +00:00

Add vararg support to compiler. Seems to be leak in parser.

This commit is contained in:
Calvin Rose 2017-05-06 17:46:28 -04:00
parent 6adc2a5268
commit 7b83247c07
6 changed files with 112 additions and 46 deletions

View File

@ -27,8 +27,8 @@ $(GST_CORELIB): $(GST_CORE_OBJECTS) $(GST_HEADERS)
##############################
GST_CLIENT_SOURCES=client/main.c
GST_CLIENT_OBJECTS=$(patsubst %.c,%.o,$(GST_CLIENT_SOURCES))
$(GST_TARGET): $(GST_CLIENT_OBJECTS) $(GST_CORELIB)
$(CC) $(CFLAGS) -o $(GST_TARGET) $(GST_CLIENT_OBJECTS) $(GST_CORELIB)
$(GST_TARGET): $(GST_CLIENT_OBJECTS) $(GST_CORE_OBJECTS)
$(CC) $(CFLAGS) -o $(GST_TARGET) $(GST_CLIENT_OBJECTS) $(GST_CORE_OBJECTS)
# Compile all .c to .o
%.o : %.c $(GST_HEADERS) $(GST_INTERNAL_HEADERS)

View File

@ -66,51 +66,44 @@ int debug_run(Gst *vm, FILE *in) {
char buffer[1024] = {0};
const char *reader = buffer;
GstValue ast;
GstValue *tup;
GstArray *arr;
GstParser p;
/* Init parser */
gst_parser(&p, vm);
/* Create do struct */
arr = gst_array(vm, 10);
gst_array_push(vm, arr, gst_string_cv(vm, "do"));
/* Get and parse input until we have a full form */
while (p.status != GST_PARSER_ERROR) {
if (*reader == '\0') {
if (!fgets(buffer, sizeof(buffer), in)) {
break;
/* Check that parser is complete */
if (p.status != GST_PARSER_FULL && p.status != GST_PARSER_ROOT) {
printf("Unexpected end of source\n");
return 1;
}
return 0;
}
reader = buffer;
}
reader += gst_parse_cstring(&p, reader);
if (gst_parse_hasvalue(&p))
gst_array_push(vm, arr, gst_parse_consume(&p));
if (p.status != GST_PARSER_FULL)
reader += gst_parse_cstring(&p, reader);
if (gst_parse_hasvalue(&p)) {
ast = gst_parse_consume(&p);
debug_compile_and_run(vm, ast, gst_wrap_nil());
}
}
/* Turn array into tuple */
tup = gst_tuple_begin(vm, arr->count);
gst_memcpy(tup, arr->data, arr->count * sizeof(GstValue));
ast = gst_wrap_tuple(gst_tuple_end(vm, tup));
/* Check if file read in correctly */
if (p.error) {
printf("Parse error: %s\n", p.error);
return 1;
}
/* Check that parser is complete */
if (p.status != GST_PARSER_FULL && p.status != GST_PARSER_ROOT) {
printf("Unexpected end of source\n");
return 1;
}
return debug_compile_and_run(vm, ast, gst_wrap_nil());
return 1;
}
/* A simple repl */
int debug_repl(Gst *vm) {
const char *buffer, *reader;
GstParser p;
buffer = reader = NULL;
for (;;) {
/* Init parser */
gst_parser(&p, vm);
buffer = reader = NULL;
while (p.status != GST_PARSER_ERROR && p.status != GST_PARSER_FULL) {
gst_parse_cstring(&p, "\n");
if (p.status == GST_PARSER_ERROR || p.status == GST_PARSER_FULL)

View File

@ -572,7 +572,7 @@ static Slot compile_block(GstCompiler *c, FormOptions opts, const GstValue *form
/* Extract the last n bytes from the buffer and use them to construct
* a function definition. */
static GstFuncDef *compiler_gen_funcdef(GstCompiler *c, uint32_t lastNBytes, uint32_t arity) {
static GstFuncDef *compiler_gen_funcdef(GstCompiler *c, uint32_t lastNBytes, uint32_t arity, int varargs) {
GstScope *scope = c->tail;
GstBuffer *buffer = c->buffer;
GstFuncDef *def = gst_alloc(c->vm, sizeof(GstFuncDef));
@ -601,10 +601,20 @@ static GstFuncDef *compiler_gen_funcdef(GstCompiler *c, uint32_t lastNBytes, uin
/* Initialize the new FuncDef */
def->locals = scope->frameSize;
def->arity = arity;
def->flags = 0;
def->flags = varargs ? GST_FUNCDEF_FLAG_VARARG : 0;
return def;
}
/* Check if a string a cstring are equal */
static int equal_cstr(const uint8_t *str, const char *cstr) {
uint32_t i;
for (i = 0; i < gst_string_length(str); ++i) {
if (cstr[i] == 0) return 0;
if (str[i] != ((const uint8_t *)cstr)[i]) return 0;
}
return cstr[i] == 0;
}
/* Compile a function from a function literal source form */
static Slot compile_function(GstCompiler *c, FormOptions opts, const GstValue *form) {
GstScope *scope = c->tail;
@ -616,6 +626,8 @@ static Slot compile_function(GstCompiler *c, FormOptions opts, const GstValue *f
GstArray *params;
FormOptions subOpts = form_options_default();
Slot ret;
int varargs;
uint32_t arity;
if (opts.resultUnused) return nil_slot();
ret = compiler_get_target(c, opts);
subGstScope = compiler_push_scope(c, 0);
@ -623,10 +635,19 @@ static Slot compile_function(GstCompiler *c, FormOptions opts, const GstValue *f
if (form[current].type != GST_ARRAY)
c_error(c, "expected function arguments array");
params = form[current++].data.array;
arity = params->count;
for (i = 0; i < params->count; ++i) {
GstValue param = params->data[i];
if (param.type != GST_STRING)
c_error(c, "function parameters should be strings");
/* Check for varargs */
if (equal_cstr(param.data.string, "&")) {
if (i != params->count - 1) {
c_error(c, "& is reserved for vararg argument in function");
}
varargs = 1;
arity--;
}
/* The compiler puts the parameter locals
* in the right place by default - at the beginning
* of the stack frame. */
@ -643,7 +664,7 @@ static Slot compile_function(GstCompiler *c, FormOptions opts, const GstValue *f
{
GstValue newVal;
uint16_t literalIndex;
GstFuncDef *def = compiler_gen_funcdef(c, buffer->count - sizeBefore, params->count);
GstFuncDef *def = compiler_gen_funcdef(c, buffer->count - sizeBefore, arity, varargs);
/* Add this FuncDef as a literal in the outer scope */
newVal.type = GST_FUNCDEF;
newVal.data.def = def;
@ -1121,7 +1142,7 @@ GstFunction *gst_compiler_compile(GstCompiler *c, GstValue form) {
/* Create a scope */
opts.isTail = 1;
compiler_return(c, compile_value(c, opts, form));
def = compiler_gen_funcdef(c, c->buffer->count, 0);
def = compiler_gen_funcdef(c, c->buffer->count, 0, 0);
{
GstFuncEnv *env = gst_alloc(c->vm, sizeof(GstFuncEnv));
GstFunction *func = gst_alloc(c->vm, sizeof(GstFunction));

View File

@ -80,14 +80,11 @@ static GstParseState *parser_pop(GstParser * p) {
/* Quote a value */
static GstValue quote(GstParser *p, GstValue x) {
/* Load a quote form to get the string literal */
GstValue tuplev;
GstValue *tuple;
tuple = gst_tuple_begin(p->vm, 2);
tuple[0] = gst_string_cv(p->vm, "quote");
tuple[1] = x;
tuplev.type = GST_TUPLE;
tuplev.data.tuple = gst_tuple_end(p->vm, tuple);
return tuplev;
return gst_wrap_tuple(gst_tuple_end(p->vm, tuple));
}
/* Add a new, empty ParseState to the ParseStack. */
@ -156,7 +153,7 @@ static int is_symbol_char(uint8_t c) {
if (c >= '0' && c <= ':') return 1;
if (c >= '<' && c <= '@') return 1;
if (c >= '*' && c <= '/') return 1;
if (c >= '#' && c <= '&') return 1;
if (c >= '$' && c == '&') return 1;
if (c == '_') return 1;
if (c == '^') return 1;
if (c == '!') return 1;
@ -574,14 +571,14 @@ static const GstUserType gst_stl_parsetype = {
};
/* Create a parser */
int gst_stl_parser(Gst *vm) {
static int gst_stl_parser(Gst *vm) {
GstParser *p = gst_userdata(vm, sizeof(GstParser), &gst_stl_parsetype);
gst_parser(p, vm);
gst_c_return(vm, gst_wrap_userdata(p));
}
/* Consume a value from the parser */
int gst_stl_parser_consume(Gst *vm) {
static int gst_stl_parser_consume(Gst *vm) {
GstParser *p = gst_check_userdata(vm, 0, &gst_stl_parsetype);
if (p == NULL)
gst_c_throwc(vm, "expected parser");
@ -591,7 +588,7 @@ int gst_stl_parser_consume(Gst *vm) {
}
/* Check if the parser has a value to consume */
int gst_stl_parser_hasvalue(Gst *vm) {
static int gst_stl_parser_hasvalue(Gst *vm) {
GstParser *p = gst_check_userdata(vm, 0, &gst_stl_parsetype);
if (p == NULL)
gst_c_throwc(vm, "expected parser");
@ -599,7 +596,7 @@ int gst_stl_parser_hasvalue(Gst *vm) {
}
/* Parse a single byte. Returns if the byte was successfully parsed. */
int gst_stl_parser_byte(Gst *vm) {
static int gst_stl_parser_byte(Gst *vm) {
GstInteger b;
GstParser *p = gst_check_userdata(vm, 0, &gst_stl_parsetype);
if (p == NULL)
@ -616,7 +613,7 @@ int gst_stl_parser_byte(Gst *vm) {
/* Parse a string or buffer. Returns nil if the entire char array is parsed,
* otherwise returns the remainder of what could not be parsed. */
int gst_stl_parser_charseq(Gst *vm) {
static int gst_stl_parser_charseq(Gst *vm) {
uint32_t i;
uint32_t len;
const uint8_t *data;
@ -638,13 +635,40 @@ int gst_stl_parser_charseq(Gst *vm) {
}
}
/* Get status of parser */
static int gst_stl_parser_status(Gst *vm) {
GstParser *p = gst_check_userdata(vm, 0, &gst_stl_parsetype);
const char *cstr;
if (p == NULL)
gst_c_throwc(vm, "expected parser");
switch (p->status) {
case GST_PARSER_ERROR:
cstr = "error";
break;
case GST_PARSER_FULL:
cstr = "full";
break;
case GST_PARSER_PENDING:
cstr = "pending";
break;
case GST_PARSER_ROOT:
cstr = "root";
break;
default:
cstr = "unknown";
break;
}
gst_c_return(vm, gst_string_cv(vm, cstr));
}
/* The module */
static const GstModuleItem gst_parser_module[] = {
{"parser", gst_stl_parser},
{"parse-byte", gst_stl_parser_byte},
{"parser", gst_stl_parser},
{"parse-byte", gst_stl_parser_byte},
{"parse-consume", gst_stl_parser_consume},
{"parse-hasvalue", gst_stl_parser_hasvalue},
{"parse-charseq", gst_stl_parser_charseq},
{"parse-status", gst_stl_parser_status},
{NULL, NULL}
};

View File

@ -142,6 +142,9 @@ int gst_stl_length(Gst *vm) {
case GST_TABLE:
ret.data.integer = x.data.table->count;
break;
case GST_STRUCT:
ret.data.integer = gst_struct_length(x.data.st);
break;
}
gst_c_return(vm, ret);
}
@ -179,14 +182,17 @@ int gst_stl_slice(Gst *vm) {
int32_t from, to;
GstValue x;
const GstValue *data;
const uint8_t *cdata;
uint32_t length;
uint32_t newlength;
GstInteger num;
/* Get data */
x = gst_arg(vm, 0);
if (!gst_seq_view(x, &data, &length))
if (!gst_seq_view(x, &data, &length) &&
!gst_chararray_view(x, &cdata, &length)) {
gst_c_throwc(vm, "expected array or tuple");
}
/* Get from index */
if (count < 2) {
@ -207,7 +213,7 @@ int gst_stl_slice(Gst *vm) {
}
/* Check from bad bounds */
if (from < 0 || to < 0)
if (from < 0 || to < 0 || to < from)
gst_c_throwc(vm, "index out of bounds");
/* Build slice */
@ -216,11 +222,18 @@ int gst_stl_slice(Gst *vm) {
GstValue *tup = gst_tuple_begin(vm, newlength);
gst_memcpy(tup, data + from, newlength * sizeof(GstValue));
gst_c_return(vm, gst_wrap_tuple(gst_tuple_end(vm, tup)));
} else {
} else if (x.type == GST_ARRAY) {
GstArray *arr = gst_array(vm, newlength);
arr->count = newlength;
gst_memcpy(arr->data, data + from, newlength * sizeof(GstValue));
gst_c_return(vm, gst_wrap_array(arr));
} else if (x.type == GST_STRING) {
gst_c_return(vm, gst_wrap_string(gst_string_b(vm, x.data.string + from, newlength)));
} else { /* buffer */
GstBuffer *b = gst_buffer(vm, newlength);
gst_memcpy(b->data, x.data.buffer->data, newlength);
b->count = newlength;
gst_c_return(vm, gst_wrap_buffer(b));
}
}
@ -539,6 +552,16 @@ int gst_stl_namespace_set(Gst *vm) {
gst_c_return(vm, gst_wrap_nil());
}
/* Get the table or struct associated with a given namespace */
int gst_stl_namespace_get(Gst *vm) {
GstValue name = gst_arg(vm, 0);
GstValue check;
if (name.type != GST_STRING)
gst_c_throwc(vm, "expected string");
check = gst_table_get(vm->modules, name);
gst_c_return(vm, check);
}
/****/
/* IO */
/****/
@ -715,6 +738,7 @@ static const GstModuleItem const std_module[] = {
{"export!", gst_stl_export},
{"namespace", gst_stl_namespace},
{"namespace-set!", gst_stl_namespace_set},
{"namespace-get", gst_stl_namespace_get},
{"push!", gst_stl_push},
{"pop!", gst_stl_pop},
{"peek", gst_stl_peek},

View File

@ -1,4 +1,4 @@
# Pretty print
(do
# Declare pretty print
(: pp nil)
@ -50,7 +50,11 @@
# Define pretty print
(: pp (fn [x seen]
(: h (get handlers (type x)))
((if h h tostring) x seen)))
(: handler (get handlers (type x)))
(: handler (if handler handler tostring))
(handler x seen)))
# (print (pp [1 {4 5 6 7} 2 3]))
# Export pretty print
(export! 'pp pp)
)