diff --git a/Makefile b/Makefile index ed0e1093..f91590ba 100644 --- a/Makefile +++ b/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) diff --git a/client/main.c b/client/main.c index 9bf21a48..f64cda0d 100644 --- a/client/main.c +++ b/client/main.c @@ -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) diff --git a/core/compile.c b/core/compile.c index 407c6fe1..10354a6d 100644 --- a/core/compile.c +++ b/core/compile.c @@ -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)); diff --git a/core/parse.c b/core/parse.c index 506d150d..4544bd30 100644 --- a/core/parse.c +++ b/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} }; diff --git a/core/stl.c b/core/stl.c index 1026bc5a..5b8888e8 100644 --- a/core/stl.c +++ b/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}, diff --git a/libs/pp.gst b/libs/pp.gst index 0fbed1d8..734b15e3 100644 --- a/libs/pp.gst +++ b/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) + +)