mirror of
https://github.com/janet-lang/janet
synced 2024-12-23 06:50:26 +00:00
Add vararg support to compiler. Seems to be leak in parser.
This commit is contained in:
parent
6adc2a5268
commit
7b83247c07
4
Makefile
4
Makefile
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
48
core/parse.c
48
core/parse.c
@ -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}
|
||||
};
|
||||
|
||||
|
30
core/stl.c
30
core/stl.c
@ -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},
|
||||
|
12
libs/pp.gst
12
libs/pp.gst
@ -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)
|
||||
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user