summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt5
-rw-r--r--chunk.h28
-rw-r--r--compiler.c33
-rw-r--r--lexer.c77
-rw-r--r--lexer.h6
-rw-r--r--lib.c52
-rw-r--r--lib/uci.c14
-rw-r--r--main.c9
-rw-r--r--source.h10
-rw-r--r--tests/cram/test_basic.t5
-rw-r--r--types.c11
-rw-r--r--types.h144
-rw-r--r--util.h2
-rw-r--r--value.c2
-rw-r--r--value.h15
-rw-r--r--vm.c37
-rw-r--r--vm.h49
17 files changed, 278 insertions, 221 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c6bfec9..0d5fe54 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -107,8 +107,9 @@ IF(UNIT_TESTING)
LIST(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure")
IF(CMAKE_C_COMPILER_ID STREQUAL "Clang")
- ADD_EXECUTABLE(ucode-san ${UCODE_SOURCES})
- TARGET_LINK_LIBRARIES(ucode-san ${json})
+ ADD_EXECUTABLE(ucode-san ${UCODE_SOURCES})
+ SET_PROPERTY(TARGET ucode-san PROPERTY ENABLE_EXPORTS 1)
+ TARGET_LINK_LIBRARIES(ucode-san ${json})
TARGET_COMPILE_OPTIONS(ucode-san PRIVATE -g -fno-omit-frame-pointer -fsanitize=undefined,address,leak -fno-sanitize-recover=all)
TARGET_LINK_OPTIONS(ucode-san PRIVATE -fsanitize=undefined,address,leak)
ENDIF()
diff --git a/chunk.h b/chunk.h
index cad00f7..2a8fa3a 100644
--- a/chunk.h
+++ b/chunk.h
@@ -22,38 +22,12 @@
#include "value.h"
#include "util.h"
-
-
-typedef struct {
- size_t from, to, target, slot;
-} uc_ehrange;
-
-typedef struct {
- size_t from, to, slot, nameidx;
-} uc_varrange;
-
-uc_declare_vector(uc_ehranges, uc_ehrange);
-uc_declare_vector(uc_variables, uc_varrange);
-uc_declare_vector(uc_offsetinfo, uint8_t);
-
-typedef struct {
- size_t count;
- uint8_t *entries;
- uc_value_list constants;
- uc_ehranges ehranges;
- struct {
- uc_variables variables;
- uc_value_list varnames;
- uc_offsetinfo offsets;
- } debuginfo;
-} uc_chunk;
+#include "types.h"
void uc_chunk_init(uc_chunk *chunk);
void uc_chunk_free(uc_chunk *chunk);
size_t uc_chunk_add(uc_chunk *chunk, uint8_t byte, size_t line);
-typedef struct uc_value_t uc_value_t;
-
ssize_t uc_chunk_add_constant(uc_chunk *chunk, uc_value_t *value);
uc_value_t *uc_chunk_get_constant(uc_chunk *chunk, size_t idx);
void uc_chunk_pop(uc_chunk *chunk);
diff --git a/compiler.c b/compiler.c
index 04ff8ee..fd5b3af 100644
--- a/compiler.c
+++ b/compiler.c
@@ -468,7 +468,12 @@ uc_compiler_emit_s32(uc_compiler *compiler, size_t srcpos, int32_t n)
{
uc_chunk *chunk = uc_compiler_current_chunk(compiler);
size_t lineoff = uc_compiler_set_srcpos(compiler, srcpos);
- uint32_t v = n + 0x7fffffff;
+ uint32_t v;
+
+ if (n <= 0)
+ v = n + 0x7fffffff;
+ else
+ v = (uint32_t)n + 0x7fffffff;
uc_chunk_add(chunk, v / 0x1000000, lineoff);
uc_chunk_add(chunk, (v / 0x10000) % 0x100, 0);
@@ -555,9 +560,9 @@ uc_compiler_get_jmpaddr(uc_compiler *compiler, size_t off)
assert(off + 4 < chunk->count);
return (
- chunk->entries[off + 1] * 0x1000000 +
- chunk->entries[off + 2] * 0x10000 +
- chunk->entries[off + 3] * 0x100 +
+ chunk->entries[off + 1] * 0x1000000UL +
+ chunk->entries[off + 2] * 0x10000UL +
+ chunk->entries[off + 3] * 0x100UL +
chunk->entries[off + 4]
) - 0x7fffffff;
}
@@ -1065,7 +1070,7 @@ static bool
uc_compiler_compile_arrowfn(uc_compiler *compiler, uc_value_t *args, bool restarg)
{
bool array = (ucv_type(args) == UC_ARRAY);
- uc_compiler fncompiler = {};
+ uc_compiler fncompiler = { 0 };
size_t i, pos, load_off;
uc_function_t *fn;
ssize_t slot;
@@ -1283,7 +1288,7 @@ static void
uc_compiler_compile_call(uc_compiler *compiler, bool assignable)
{
uc_chunk *chunk = uc_compiler_current_chunk(compiler);
- uc_jmplist spreads = {};
+ uc_jmplist spreads = { 0 };
enum insn_type type;
size_t i, nargs = 0;
@@ -1422,7 +1427,7 @@ uc_compiler_compile_delimitted_block(uc_compiler *compiler, uc_tokentype_t endty
static void
uc_compiler_compile_function(uc_compiler *compiler, bool assignable)
{
- uc_compiler fncompiler = {};
+ uc_compiler fncompiler = { 0 };
uc_value_t *name = NULL;
ssize_t slot = -1, pos;
uc_tokentype_t type;
@@ -1891,7 +1896,7 @@ uc_compiler_compile_if(uc_compiler *compiler)
uc_chunk *chunk = uc_compiler_current_chunk(compiler);
size_t jmpz_off, jmp_off, i;
bool expect_endif = false;
- uc_jmplist elifs = {};
+ uc_jmplist elifs = { 0 };
uc_tokentype_t type;
/* parse & compile condition expression */
@@ -1996,7 +2001,7 @@ uc_compiler_compile_while(uc_compiler *compiler)
{
uc_chunk *chunk = uc_compiler_current_chunk(compiler);
size_t cond_off, jmpz_off, end_off;
- uc_patchlist p = {};
+ uc_patchlist p = { 0 };
p.parent = compiler->patchlist;
compiler->patchlist = &p;
@@ -2044,7 +2049,7 @@ uc_compiler_compile_for_in(uc_compiler *compiler, bool local, uc_token *kvar, uc
{
uc_chunk *chunk = uc_compiler_current_chunk(compiler);
size_t skip_jmp, test_jmp, key_slot, val_slot;
- uc_patchlist p = {};
+ uc_patchlist p = { 0 };
p.parent = compiler->patchlist;
compiler->patchlist = &p;
@@ -2154,7 +2159,7 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var)
{
uc_chunk *chunk = uc_compiler_current_chunk(compiler);
size_t test_off = 0, incr_off, skip_off, cond_off = 0;
- uc_patchlist p = {};
+ uc_patchlist p = { 0 };
p.parent = compiler->patchlist;
compiler->patchlist = &p;
@@ -2254,7 +2259,7 @@ uc_compiler_compile_for_count(uc_compiler *compiler, bool local, uc_token *var)
static void
uc_compiler_compile_for(uc_compiler *compiler)
{
- uc_token keyvar = {}, valvar = {};
+ uc_token keyvar = { 0 }, valvar = { 0 };
bool local;
uc_compiler_parse_consume(compiler, TK_LPAREN);
@@ -2309,8 +2314,8 @@ uc_compiler_compile_switch(uc_compiler *compiler)
size_t i, test_jmp, skip_jmp, next_jmp, value_slot, default_off = 0;
uc_chunk *chunk = uc_compiler_current_chunk(compiler);
uc_locals *locals = &compiler->locals;
- uc_jmplist cases = {};
- uc_patchlist p = {};
+ uc_jmplist cases = { 0 };
+ uc_patchlist p = { 0 };
p.parent = compiler->patchlist;
compiler->patchlist = &p;
diff --git a/lexer.c b/lexer.c
index 74e0c4d..aaba314 100644
--- a/lexer.c
+++ b/lexer.c
@@ -38,7 +38,7 @@ struct keyword {
union {
double d;
bool b;
- };
+ } u;
};
struct token {
@@ -46,7 +46,7 @@ struct token {
union {
uint32_t patn;
char pat[4];
- };
+ } u;
unsigned plen;
uc_token *(*parse)(uc_lexer *, bool);
};
@@ -135,33 +135,33 @@ static const struct token tokens[] = {
};
static const struct keyword reserved_words[] = {
- { TK_ENDFUNC, "endfunction", 11, {} },
+ { TK_ENDFUNC, "endfunction", 11, { 0 } },
{ TK_DOUBLE, "Infinity", 8, { .d = INFINITY } },
- { TK_CONTINUE, "continue", 8, {} },
- { TK_ENDWHILE, "endwhile", 8, {} },
- { TK_FUNC, "function", 8, {} },
- { TK_DEFAULT, "default", 7, {} },
- { TK_RETURN, "return", 6, {} },
- { TK_ENDFOR, "endfor", 6, {} },
- { TK_SWITCH, "switch", 6, {} },
- { TK_LOCAL, "local", 5, {} },
- { TK_ENDIF, "endif", 5, {} },
- { TK_WHILE, "while", 5, {} },
- { TK_BREAK, "break", 5, {} },
- { TK_CATCH, "catch", 5, {} },
+ { TK_CONTINUE, "continue", 8, { 0 } },
+ { TK_ENDWHILE, "endwhile", 8, { 0 } },
+ { TK_FUNC, "function", 8, { 0 } },
+ { TK_DEFAULT, "default", 7, { 0 } },
+ { TK_RETURN, "return", 6, { 0 } },
+ { TK_ENDFOR, "endfor", 6, { 0 } },
+ { TK_SWITCH, "switch", 6, { 0 } },
+ { TK_LOCAL, "local", 5, { 0 } },
+ { TK_ENDIF, "endif", 5, { 0 } },
+ { TK_WHILE, "while", 5, { 0 } },
+ { TK_BREAK, "break", 5, { 0 } },
+ { TK_CATCH, "catch", 5, { 0 } },
{ TK_BOOL, "false", 5, { .b = false } },
{ TK_BOOL, "true", 4, { .b = true } },
- { TK_ELIF, "elif", 4, {} },
- { TK_ELSE, "else", 4, {} },
- { TK_THIS, "this", 4, {} },
- { TK_NULL, "null", 4, {} },
- { TK_CASE, "case", 4, {} },
+ { TK_ELIF, "elif", 4, { 0 } },
+ { TK_ELSE, "else", 4, { 0 } },
+ { TK_THIS, "this", 4, { 0 } },
+ { TK_NULL, "null", 4, { 0 } },
+ { TK_CASE, "case", 4, { 0 } },
{ TK_DOUBLE, "NaN", 3, { .d = NAN } },
- { TK_TRY, "try", 3, {} },
- { TK_FOR, "for", 3, {} },
- { TK_LOCAL, "let", 3, {} },
- { TK_IF, "if", 2, {} },
- { TK_IN, "in", 2, {} },
+ { TK_TRY, "try", 3, { 0 } },
+ { TK_FOR, "for", 3, { 0 } },
+ { TK_LOCAL, "let", 3, { 0 } },
+ { TK_IF, "if", 2, { 0 } },
+ { TK_IN, "in", 2, { 0 } },
};
@@ -362,7 +362,7 @@ parse_comment(uc_lexer *lex, bool no_regexp)
if (!buf_remaining(lex))
return emit_op(lex, lex->lastoff, TK_ERROR, ucv_string_new("Unterminated comment"));
- if (!strcmp(tok->pat, "//")) {
+ if (!strcmp(tok->u.pat, "//")) {
end = "\n";
elen = 1;
}
@@ -400,7 +400,7 @@ static uc_token *
parse_string(uc_lexer *lex, bool no_regexp)
{
const struct token *tok = lex->tok;
- char q = tok->pat[0];
+ char q = tok->u.pat[0];
char *ptr, *c;
uc_token *rv;
int code;
@@ -438,7 +438,7 @@ parse_string(uc_lexer *lex, bool no_regexp)
default:
lex->is_escape = false;
- c = strchr("a\ab\be\ef\fn\nr\rt\tv\v", *ptr);
+ c = strchr("a\ab\be\033f\fn\nr\rt\tv\v", *ptr);
if (c && *c >= 'a') {
lookbehind_append(lex, c + 1, 1);
@@ -725,7 +725,7 @@ parse_label(uc_lexer *lex, bool no_regexp)
size_t i;
if (!lex->lookbehind && tok->plen)
- lookbehind_append(lex, tok->pat, tok->plen);
+ lookbehind_append(lex, tok->u.pat, tok->plen);
if (!buf_remaining(lex) || (lex->bufstart[0] != '_' && !isalnum(lex->bufstart[0]))) {
for (i = 0, word = &reserved_words[0]; i < ARRAY_SIZE(reserved_words); i++, word = &reserved_words[i]) {
@@ -734,11 +734,11 @@ parse_label(uc_lexer *lex, bool no_regexp)
switch (word->type) {
case TK_DOUBLE:
- rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_double_new(word->d));
+ rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_double_new(word->u.d));
break;
case TK_BOOL:
- rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_boolean_new(word->b));
+ rv = emit_op(lex, lex->source->off - word->plen, word->type, ucv_boolean_new(word->u.b));
break;
default:
@@ -803,7 +803,7 @@ parse_number(uc_lexer *lex, bool no_regexp)
if (*e == '.' || *e == 'e' || *e == 'E') {
d = strtod(lex->lookbehind, &e);
- if (tok->pat[0] == '-')
+ if (tok->u.pat[0] == '-')
d = -d;
if (e > lex->lookbehind && *e == 0)
@@ -812,7 +812,7 @@ parse_number(uc_lexer *lex, bool no_regexp)
rv = emit_op(lex, lex->source->off - (lex->lookbehindlen - (e - lex->lookbehind) - 1), TK_ERROR, ucv_string_new("Invalid number literal"));
}
else if (*e == 0) {
- if (tok->pat[0] == '-')
+ if (tok->u.pat[0] == '-')
n = (errno == ERANGE) ? INT64_MIN : -n;
rv = emit_op(lex, lex->source->off - (e - lex->lookbehind), TK_NUMBER, ucv_int64_new(n));
@@ -857,7 +857,8 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp)
rem = lex->bufend - lex->bufstart;
- memcpy(lex->buf, lex->bufstart, rem);
+ if (rem)
+ memcpy(lex->buf, lex->bufstart, rem);
rlen = fread(lex->buf + rem, 1, lex->buflen - rem, fp);
@@ -1042,8 +1043,8 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp)
c = buf_remaining(lex) ? lex->bufstart[0] : 0;
- if (tok->plen ? ((search.n & masks[tok->plen]) == tok->patn)
- : (c >= tok->pat[0] && c <= tok->pat[1])) {
+ if (tok->plen ? ((search.n & masks[tok->plen]) == tok->u.patn)
+ : (c >= tok->u.pat[0] && c <= tok->u.pat[1])) {
lex->lastoff = lex->source->off;
/* token has a parse method, switch state */
@@ -1067,7 +1068,7 @@ lex_step(uc_lexer *lex, FILE *fp, bool no_regexp)
else if ((lex->block == STATEMENTS && tok->type == TK_RSTM) ||
(lex->block == EXPRESSION && tok->type == TK_REXP)) {
/* strip whitespace after block */
- if (tok->pat[0] == '-')
+ if (tok->u.pat[0] == '-')
lex->modifier = MINUS;
/* strip newline after statement block */
@@ -1207,7 +1208,7 @@ uc_get_tokenname(unsigned type)
if (tokens[i].type != type)
continue;
- snprintf(buf, sizeof(buf), "'%s'", tokens[i].pat);
+ snprintf(buf, sizeof(buf), "'%s'", tokens[i].u.pat);
return buf;
}
diff --git a/lexer.h b/lexer.h
index f023fb6..069e9e0 100644
--- a/lexer.h
+++ b/lexer.h
@@ -127,12 +127,6 @@ typedef struct {
} uc_token;
typedef struct {
- bool lstrip_blocks;
- bool trim_blocks;
- bool strict_declarations;
-} uc_parse_config;
-
-typedef struct {
uc_lex_state_t state;
uc_parse_config *config;
uc_source *source;
diff --git a/lib.c b/lib.c
index 80c1386..5d6235d 100644
--- a/lib.c
+++ b/lib.c
@@ -35,6 +35,7 @@
#include "compiler.h"
#include "vm.h"
#include "lib.h"
+#include "source.h"
static void
format_context_line(uc_stringbuf_t *buf, const char *line, size_t off, bool compact)
@@ -454,9 +455,11 @@ static uc_value_t *
uc_delete(uc_vm *vm, size_t nargs)
{
uc_value_t *obj = uc_get_arg(0);
+ uc_value_t *key = NULL;
uc_value_t *rv = NULL;
- const char *key;
+ bool freeable;
size_t i;
+ char *k;
if (ucv_type(obj) != UC_OBJECT)
return NULL;
@@ -464,10 +467,14 @@ uc_delete(uc_vm *vm, size_t nargs)
for (i = 1; i < nargs; i++) {
ucv_put(rv);
- key = ucv_string_get(uc_get_arg(i));
- rv = ucv_get(ucv_object_get(obj, key ? key : "null", NULL));
+ key = uc_get_arg(i);
+ k = uc_cast_string(vm, &key, &freeable);
+ rv = ucv_get(ucv_object_get(obj, k, NULL));
+
+ ucv_object_delete(obj, k);
- ucv_object_delete(obj, key ? key : "null");
+ if (freeable)
+ free(k);
}
return rv;
@@ -482,7 +489,7 @@ uc_die(uc_vm *vm, size_t nargs)
s = msg ? uc_cast_string(vm, &msg, &freeable) : "Died";
- uc_vm_raise_exception(vm, EXCEPTION_USER, s);
+ uc_vm_raise_exception(vm, EXCEPTION_USER, "%s", s);
if (freeable)
free(s);
@@ -494,13 +501,19 @@ static uc_value_t *
uc_exists(uc_vm *vm, size_t nargs)
{
uc_value_t *obj = uc_get_arg(0);
- const char *key = ucv_string_get(uc_get_arg(1));
- bool found;
+ uc_value_t *key = uc_get_arg(1);
+ bool found, freeable;
+ char *k;
if (ucv_type(obj) != UC_OBJECT)
return false;
- ucv_object_get(obj, key ? key : "null", &found);
+ k = uc_cast_string(vm, &key, &freeable);
+
+ ucv_object_get(obj, k, &found);
+
+ if (freeable)
+ free(k);
return ucv_boolean_new(found);
}
@@ -516,8 +529,9 @@ uc_exit(uc_vm *vm, size_t nargs)
static uc_value_t *
uc_getenv(uc_vm *vm, size_t nargs)
{
- const char *key = ucv_string_get(uc_get_arg(0));
- char *val = key ? getenv(key) : NULL;
+ uc_value_t *key = uc_get_arg(0);
+ char *k = ucv_string_get(key);
+ char *val = k ? getenv(k) : NULL;
return val ? ucv_string_new(val) : NULL;
}
@@ -562,16 +576,18 @@ uc_filter(uc_vm *vm, size_t nargs)
static uc_value_t *
uc_hex(uc_vm *vm, size_t nargs)
{
- const char *val = ucv_string_get(uc_get_arg(0));
+ uc_value_t *val = uc_get_arg(0);
+ char *e, *v;
int64_t n;
- char *e;
- if (!val || !isxdigit(*val))
+ v = ucv_string_get(val);
+
+ if (!v || !isxdigit(*v))
return ucv_double_new(NAN);
- n = strtoll(val, &e, 16);
+ n = strtoll(v, &e, 16);
- if (e == val || *e)
+ if (e == v || *e)
return ucv_double_new(NAN);
return ucv_int64_new(n);
@@ -622,8 +638,10 @@ uc_keys(uc_vm *vm, size_t nargs)
arr = ucv_array_new(vm);
- ucv_object_foreach(obj, key, val)
+ ucv_object_foreach(obj, key, val) {
+ (void)val;
ucv_array_push(arr, ucv_string_new(key));
+ }
return arr;
}
@@ -1423,7 +1441,7 @@ uc_require_so(uc_vm *vm, const char *path, uc_value_t **res)
return true;
}
- init = dlsym(dlh, "uc_module_entry");
+ *(void **)(&init) = dlsym(dlh, "uc_module_entry");
if (!init) {
uc_vm_raise_exception(vm, EXCEPTION_RUNTIME,
diff --git a/lib/uci.c b/lib/uci.c
index fba7dad..00a451c 100644
--- a/lib/uci.c
+++ b/lib/uci.c
@@ -255,7 +255,7 @@ uc_uci_get_any(uc_vm *vm, size_t nargs, bool all)
uc_value_t *conf = uc_get_arg(0);
uc_value_t *sect = uc_get_arg(1);
uc_value_t *opt = uc_get_arg(2);
- struct uci_ptr ptr = {};
+ struct uci_ptr ptr = { 0 };
int rv;
if (!c || !*c)
@@ -330,7 +330,7 @@ uc_uci_get_first(uc_vm *vm, size_t nargs)
struct uci_package *p = NULL;
struct uci_section *sc;
struct uci_element *e;
- struct uci_ptr ptr = {};
+ struct uci_ptr ptr = { 0 };
int rv;
if (ucv_type(conf) != UC_STRING ||
@@ -465,7 +465,7 @@ uc_uci_set(uc_vm *vm, size_t nargs)
uc_value_t *conf = uc_get_arg(0);
uc_value_t *sect = uc_get_arg(1);
uc_value_t *opt = NULL, *val = NULL;
- struct uci_ptr ptr = {};
+ struct uci_ptr ptr = { 0 };
bool is_list = false;
size_t i;
int rv;
@@ -570,7 +570,7 @@ uc_uci_delete(uc_vm *vm, size_t nargs)
uc_value_t *conf = uc_get_arg(0);
uc_value_t *sect = uc_get_arg(1);
uc_value_t *opt = uc_get_arg(2);
- struct uci_ptr ptr = {};
+ struct uci_ptr ptr = { 0 };
int rv;
if (ucv_type(conf) != UC_STRING ||
@@ -605,7 +605,7 @@ uc_uci_rename(uc_vm *vm, size_t nargs)
uc_value_t *conf = uc_get_arg(0);
uc_value_t *sect = uc_get_arg(1);
uc_value_t *opt = NULL, *val = NULL;
- struct uci_ptr ptr = {};
+ struct uci_ptr ptr = { 0 };
int rv;
if (ucv_type(conf) != UC_STRING ||
@@ -665,7 +665,7 @@ uc_uci_reorder(uc_vm *vm, size_t nargs)
uc_value_t *conf = uc_get_arg(0);
uc_value_t *sect = uc_get_arg(1);
uc_value_t *val = uc_get_arg(2);
- struct uci_ptr ptr = {};
+ struct uci_ptr ptr = { 0 };
int64_t n;
int rv;
@@ -705,7 +705,7 @@ uc_uci_pkg_command(uc_vm *vm, size_t nargs, enum pkg_cmd cmd)
uc_value_t *conf = uc_get_arg(0);
struct uci_element *e, *tmp;
struct uci_package *p;
- struct uci_ptr ptr = {};
+ struct uci_ptr ptr = { 0 };
int rv, res = UCI_OK;
if (cmd != CMD_REVERT && conf)
diff --git a/main.c b/main.c
index 618d5e4..d291447 100644
--- a/main.c
+++ b/main.c
@@ -98,7 +98,7 @@ parse(uc_parse_config *config, uc_source *src,
{
uc_value_t *globals = NULL;
uc_function_t *entry;
- uc_vm vm = {};
+ uc_vm vm = { 0 };
int c, c2, rc = 0;
char *err;
@@ -285,7 +285,12 @@ main(int argc, char **argv)
if (source)
fprintf(stderr, "Options -i and -s are exclusive\n");
- source = uc_source_new_buffer("[-s argument]", xstrdup(optarg), strlen(optarg));
+ c = xstrdup(optarg);
+ source = uc_source_new_buffer("[-s argument]", c, strlen(c));
+
+ if (!source)
+ free(c);
+
break;
case 'S':
diff --git a/source.h b/source.h
index 4ca01b3..6557a48 100644
--- a/source.h
+++ b/source.h
@@ -22,17 +22,9 @@
#include <stdio.h>
#include "util.h"
+#include "types.h"
-uc_declare_vector(uc_lineinfo, uint8_t);
-
-typedef struct {
- char *filename, *buffer;
- FILE *fp;
- size_t usecount, off;
- uc_lineinfo lineinfo;
-} uc_source;
-
uc_source *uc_source_new_file(const char *path);
uc_source *uc_source_new_buffer(const char *name, char *buf, size_t len);
diff --git a/tests/cram/test_basic.t b/tests/cram/test_basic.t
index 982d58a..3d4cd9e 100644
--- a/tests/cram/test_basic.t
+++ b/tests/cram/test_basic.t
@@ -35,7 +35,7 @@ check that ucode provides proper error messages:
One of -i or -s is required
[1]
- $ ucode -m foo -s ''
+ $ ucode -m foo -s ' '
Runtime error: No module named 'foo' could be found
At start of program
@@ -53,6 +53,7 @@ check that ucode can load fs module:
One of -i or -s is required
[1]
- $ ucode -m fs -s ''
+ $ ucode -m fs -s ' '
+ (no-eol)
$ touch moo; ucode -m fs -i moo
diff --git a/types.c b/types.c
index e786fb1..3ed8aaa 100644
--- a/types.c
+++ b/types.c
@@ -927,7 +927,7 @@ ucv_closure_new(uc_vm *vm, uc_function_t *function, bool arrow_fn)
closure->header.refcount = 1;
closure->function = function;
closure->is_arrow = arrow_fn;
- closure->upvals = function->nupvals ? ((void *)closure + ALIGN(sizeof(*closure))) : NULL;
+ closure->upvals = function->nupvals ? (uc_upvalref_t **)((uintptr_t)closure + ALIGN(sizeof(*closure))) : NULL;
if (vm)
ucv_ref(&vm->values, &closure->ref);
@@ -1590,8 +1590,8 @@ ucv_to_stringbuf(uc_vm *vm, uc_stringbuf_t *pb, uc_value_t *uv, bool json)
ucv_stringbuf_printf(pb, "%sfunction%s%s(...) { [native code] }%s",
json ? "\"" : "",
- cfunction->name ? " " : "",
- cfunction->name ? cfunction->name : "",
+ cfunction->name[0] ? " " : "",
+ cfunction->name[0] ? cfunction->name : "",
json ? "\"" : "");
break;
@@ -1739,6 +1739,7 @@ ucv_equal(uc_value_t *uv1, uc_value_t *uv2)
}
ucv_object_foreach(uv2, key2, val2) {
+ (void)val2;
ucv_object_get(uv1, key2, &b1);
if (!b1)
@@ -1772,7 +1773,7 @@ ucv_gc(uc_vm *vm, bool final)
/* unref unreachable objects */
for (ref = vm->values.next; ref != &vm->values; ref = ref->next) {
- val = (void *)ref - offsetof(uc_array_t, ref);
+ val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref));
if (ucv_is_marked(val))
ucv_clear_mark(val);
@@ -1782,7 +1783,7 @@ ucv_gc(uc_vm *vm, bool final)
/* free destroyed objects */
for (ref = vm->values.next, tmp = ref->next; ref != &vm->values; ref = tmp, tmp = tmp->next) {
- val = (void *)ref - offsetof(uc_array_t, ref);
+ val = (uc_value_t *)((uintptr_t)ref - offsetof(uc_array_t, ref));
if (val->type == UC_NULL) {
ucv_unref(ref);
diff --git a/types.h b/types.h
index a8962da..9dab246 100644
--- a/types.h
+++ b/types.h
@@ -22,8 +22,10 @@
#include <regex.h>
#include <json-c/json.h>
-#include "source.h"
-#include "chunk.h"
+#include "util.h"
+
+
+/* Value types and generic value header */
typedef enum uc_type_t {
UC_NULL,
@@ -48,6 +50,58 @@ typedef struct uc_value_t {
uint32_t refcount:26;
} uc_value_t;
+
+/* Constant list defintions */
+
+typedef struct {
+ size_t isize;
+ size_t dsize;
+ uint64_t *index;
+ char *data;
+} uc_value_list;
+
+
+/* Source buffer defintions */
+
+uc_declare_vector(uc_lineinfo, uint8_t);
+
+typedef struct {
+ char *filename, *buffer;
+ FILE *fp;
+ size_t usecount, off;
+ uc_lineinfo lineinfo;
+} uc_source;
+
+
+/* Bytecode chunk defintions */
+
+typedef struct {
+ size_t from, to, target, slot;
+} uc_ehrange;
+
+typedef struct {
+ size_t from, to, slot, nameidx;
+} uc_varrange;
+
+uc_declare_vector(uc_ehranges, uc_ehrange);
+uc_declare_vector(uc_variables, uc_varrange);
+uc_declare_vector(uc_offsetinfo, uint8_t);
+
+typedef struct {
+ size_t count;
+ uint8_t *entries;
+ uc_value_list constants;
+ uc_ehranges ehranges;
+ struct {
+ uc_variables variables;
+ uc_value_list varnames;
+ uc_offsetinfo offsets;
+ } debuginfo;
+} uc_chunk;
+
+
+/* Value type structures */
+
typedef struct uc_weakref_t {
struct uc_weakref_t *prev;
struct uc_weakref_t *next;
@@ -144,6 +198,69 @@ typedef struct {
uc_declare_vector(uc_ressource_types_t, uc_ressource_type_t);
+
+/* Parser definitions */
+
+typedef struct {
+ bool lstrip_blocks;
+ bool trim_blocks;
+ bool strict_declarations;
+} uc_parse_config;
+
+
+/* VM definitions */
+
+typedef enum {
+ EXCEPTION_NONE,
+ EXCEPTION_SYNTAX,
+ EXCEPTION_RUNTIME,
+ EXCEPTION_TYPE,
+ EXCEPTION_REFERENCE,
+ EXCEPTION_USER
+} uc_exception_type_t;
+
+typedef struct {
+ uc_exception_type_t type;
+ uc_value_t *stacktrace;
+ char *message;
+} uc_exception;
+
+typedef struct {
+ uint8_t *ip;
+ uc_closure_t *closure;
+ uc_cfunction_t *cfunction;
+ size_t stackframe;
+ uc_value_t *ctx;
+ bool mcall;
+} uc_callframe;
+
+uc_declare_vector(uc_callframes, uc_callframe);
+uc_declare_vector(uc_stack, uc_value_t *);
+
+struct uc_vm {
+ uc_stack stack;
+ uc_exception exception;
+ uc_callframes callframes;
+ uc_upvalref_t *open_upvals;
+ uc_parse_config *config;
+ uc_value_t *globals;
+ uc_source *sources;
+ uc_weakref_t values;
+ union {
+ uint32_t u32;
+ int32_t s32;
+ uint16_t u16;
+ int16_t s16;
+ uint8_t u8;
+ int8_t s8;
+ } arg;
+ size_t spread_values;
+ uint8_t trace;
+};
+
+
+/* Value API */
+
typedef struct printbuf uc_stringbuf_t;
void ucv_free(uc_value_t *, bool);
@@ -162,7 +279,7 @@ uc_value_t *ucv_string_new_length(const char *, size_t);
size_t ucv_string_length(uc_value_t *);
char *_ucv_string_get(uc_value_t **);
-#define ucv_string_get(uv) ({ uc_value_t * volatile p = (uv); _ucv_string_get((uc_value_t **)&p); })
+#define ucv_string_get(uv) _ucv_string_get((uc_value_t **)&uv)
uc_stringbuf_t *ucv_stringbuf_new(void);
uc_value_t *ucv_stringbuf_finish(uc_stringbuf_t *);
@@ -200,16 +317,17 @@ bool ucv_object_add(uc_value_t *, const char *, uc_value_t *);
bool ucv_object_delete(uc_value_t *, const char *);
size_t ucv_object_length(uc_value_t *);
-#define ucv_object_foreach(obj, key, val) \
- char *key; \
- uc_value_t *val __attribute__((__unused__)); \
- for (struct lh_entry *entry ## key = (ucv_type(obj) == UC_OBJECT) ? ((uc_object_t *)obj)->table->head : NULL, *entry_next ## key = NULL; \
- ({ if (entry ## key) { \
- key = (char *)entry ## key->k; \
- val = (uc_value_t *)entry ## key->v; \
- entry_next ## key = entry ## key->next; \
- } ; entry ## key; }); \
- entry ## key = entry_next ## key)
+#define ucv_object_foreach(obj, key, val) \
+ char *key = NULL; \
+ uc_value_t *val = NULL; \
+ struct lh_entry *entry##key; \
+ struct lh_entry *entry_next##key = NULL; \
+ for (entry##key = (ucv_type(obj) == UC_OBJECT) ? ((uc_object_t *)obj)->table->head : NULL; \
+ (entry##key ? (key = (char *)lh_entry_k(entry##key), \
+ val = (uc_value_t *)lh_entry_v(entry##key), \
+ entry_next##key = entry##key->next, entry##key) \
+ : 0); \
+ entry##key = entry_next##key)
uc_value_t *ucv_function_new(const char *, size_t, uc_source *);
size_t ucv_function_srcpos(uc_value_t *, size_t);
diff --git a/util.h b/util.h
index a62ccc4..c4ea087 100644
--- a/util.h
+++ b/util.h
@@ -218,6 +218,7 @@ static inline struct json_tokener *xjs_new_tokener(void) {
return tok;
}
+__attribute__((format(printf, 2, 0)))
static inline int xasprintf(char **strp, const char *fmt, ...) {
va_list ap;
int len;
@@ -234,6 +235,7 @@ static inline int xasprintf(char **strp, const char *fmt, ...) {
return len;
}
+__attribute__((format(printf, 2, 0)))
static inline int xvasprintf(char **strp, const char *fmt, va_list ap) {
int len = vasprintf(strp, fmt, ap);
diff --git a/value.c b/value.c
index e53e317..0827038 100644
--- a/value.c
+++ b/value.c
@@ -260,7 +260,7 @@ uc_cmp(int how, uc_value_t *v1, uc_value_t *v2)
}
else {
if (t1 == t2 && !ucv_is_scalar(v1)) {
- delta = (void *)v1 - (void *)v2;
+ delta = (intptr_t)v1 - (intptr_t)v2;
}
else {
t1 = uc_cast_number(v1, &n1, &d1);
diff --git a/value.h b/value.h
index 770279e..a3abfc6 100644
--- a/value.h
+++ b/value.h
@@ -29,6 +29,8 @@
#include <stdio.h>
+#include "types.h"
+
typedef enum {
TAG_INVAL = 0,
TAG_NUM = 1,
@@ -39,24 +41,11 @@ typedef enum {
TAG_PTR = 6
} uc_value_type_t;
-typedef struct {
- size_t isize;
- size_t dsize;
- uint64_t *index;
- char *data;
-} uc_value_list;
-
-typedef struct uc_value_t uc_value_t;
-
bool uc_cmp(int how, uc_value_t *v1, uc_value_t *v2);
bool uc_val_is_truish(uc_value_t *val);
-typedef enum uc_type_t uc_type_t;
-typedef struct uc_value_t uc_value_t;
uc_type_t uc_cast_number(uc_value_t *v, int64_t *n, double *d);
-typedef struct uc_vm uc_vm;
-
uc_value_t *uc_getval(uc_vm *, uc_value_t *scope, uc_value_t *key);
uc_value_t *uc_setval(uc_vm *, uc_value_t *scope, uc_value_t *key, uc_value_t *val);
diff --git a/vm.c b/vm.c
index 7d60805..ee73265 100644
--- a/vm.c
+++ b/vm.c
@@ -232,9 +232,9 @@ uc_vm_decode_insn(uc_vm *vm, uc_callframe *frame, uc_chunk *chunk)
case -4:
vm->arg.s32 = (
- frame->ip[0] * 0x1000000 +
- frame->ip[1] * 0x10000 +
- frame->ip[2] * 0x100 +
+ frame->ip[0] * 0x1000000UL +
+ frame->ip[1] * 0x10000UL +
+ frame->ip[2] * 0x100UL +
frame->ip[3]
) - 0x7fffffff;
frame->ip += 4;
@@ -247,9 +247,9 @@ uc_vm_decode_insn(uc_vm *vm, uc_callframe *frame, uc_chunk *chunk)
case 4:
vm->arg.u32 = (
- frame->ip[0] * 0x1000000 +
- frame->ip[1] * 0x10000 +
- frame->ip[2] * 0x100 +
+ frame->ip[0] * 0x1000000UL +
+ frame->ip[1] * 0x10000UL +
+ frame->ip[2] * 0x100UL +
frame->ip[3]
);
frame->ip += 4;
@@ -307,7 +307,7 @@ uc_vm_frame_dump(uc_vm *vm, uc_callframe *frame)
ref = closure->upvals[i];
v = uc_chunk_debug_get_variable(chunk, 0, i, true);
s = ucv_to_string(NULL, v);
- fprintf(stderr, " [%zu] <%p> %s ", i, ref, s);
+ fprintf(stderr, " [%zu] <%p> %s ", i, (void *)ref, s);
free(s);
if (ref->closed) {
@@ -588,13 +588,13 @@ uc_dump_insn(uc_vm *vm, uint8_t *pos, enum insn_type insn)
case -2:
fprintf(stderr, " {%c0x%hx}",
vm->arg.s16 < 0 ? '-' : '+',
- vm->arg.s16 < 0 ? -(unsigned)vm->arg.s16 : (unsigned)vm->arg.s16);
+ (uint16_t)(vm->arg.s16 < 0 ? -vm->arg.s16 : vm->arg.s16));
break;
case -4:
fprintf(stderr, " {%c0x%x}",
vm->arg.s32 < 0 ? '-' : '+',
- vm->arg.s32 < 0 ? -(unsigned)vm->arg.s32 : (unsigned)vm->arg.s32);
+ (uint32_t)(vm->arg.s32 < 0 ? -vm->arg.s32 : vm->arg.s32));
break;
case 1:
@@ -1035,7 +1035,7 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot)
if (curr && curr->slot == slot) {
if (vm->trace) {
s = ucv_to_string(NULL, vm->stack.entries[slot]);
- fprintf(stderr, " {+%zu} <%p> %s\n", slot, curr, s);
+ fprintf(stderr, " {+%zu} <%p> %s\n", slot, (void *)curr, s);
free(s);
}
@@ -1047,7 +1047,7 @@ uc_vm_capture_upval(uc_vm *vm, size_t slot)
if (vm->trace) {
s = ucv_to_string(NULL, vm->stack.entries[slot]);
- fprintf(stderr, " {*%zu} <%p> %s\n", slot, created, s);
+ fprintf(stderr, " {*%zu} <%p> %s\n", slot, (void *)created, s);
free(s);
}
@@ -1072,7 +1072,7 @@ uc_vm_close_upvals(uc_vm *vm, size_t slot)
if (vm->trace) {
s = ucv_to_string(NULL, ref->value);
- fprintf(stderr, " {!%zu} <%p> %s\n", ref->slot, ref, s);
+ fprintf(stderr, " {!%zu} <%p> %s\n", ref->slot, (void *)ref, s);
free(s);
}
@@ -1528,11 +1528,13 @@ static void
uc_vm_insn_sobj(uc_vm *vm, enum insn_type insn)
{
uc_value_t *obj = uc_vm_stack_peek(vm, vm->arg.u32);
+ uc_value_t *val;
size_t idx;
for (idx = 0; idx < vm->arg.u32; idx += 2) {
+ val = uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1);
ucv_object_add(obj,
- ucv_string_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 1)),
+ ucv_string_get(val),
ucv_get(uc_vm_stack_peek(vm, vm->arg.u32 - idx - 2)));
}
@@ -1972,6 +1974,8 @@ uc_vm_callframe_pop(uc_vm *vm)
static void
uc_vm_output_exception(uc_vm *vm)
{
+ uc_value_t *ctx;
+
if (vm->exception.type == EXCEPTION_USER)
fprintf(stderr, "%s\n", vm->exception.message);
else
@@ -1979,10 +1983,9 @@ uc_vm_output_exception(uc_vm *vm)
exception_type_strings[vm->exception.type] ? exception_type_strings[vm->exception.type] : "Error",
vm->exception.message);
- fprintf(stderr, "%s\n\n",
- ucv_string_get(
- ucv_object_get(
- ucv_array_get(vm->exception.stacktrace, 0), "context", NULL)));
+ ctx = ucv_object_get(ucv_array_get(vm->exception.stacktrace, 0), "context", NULL);
+
+ fprintf(stderr, "%s\n\n", ucv_string_get(ctx));
}
static uc_vm_status_t
diff --git a/vm.h b/vm.h
index e4de4f9..0f7b805 100644
--- a/vm.h
+++ b/vm.h
@@ -23,6 +23,7 @@
#include "chunk.h"
#include "util.h"
#include "lexer.h"
+#include "types.h"
#define __insns \
__insn(NOOP) \
@@ -104,54 +105,6 @@ typedef struct {
} uc_insn_definition;
typedef enum {
- EXCEPTION_NONE,
- EXCEPTION_SYNTAX,
- EXCEPTION_RUNTIME,
- EXCEPTION_TYPE,
- EXCEPTION_REFERENCE,
- EXCEPTION_USER
-} uc_exception_type_t;
-
-typedef struct {
- uc_exception_type_t type;
- uc_value_t *stacktrace;
- char *message;
-} uc_exception;
-
-typedef struct {
- uint8_t *ip;
- uc_closure_t *closure;
- uc_cfunction_t *cfunction;
- size_t stackframe;
- uc_value_t *ctx;
- bool mcall;
-} uc_callframe;
-
-uc_declare_vector(uc_callframes, uc_callframe);
-uc_declare_vector(uc_stack, uc_value_t *);
-
-typedef struct uc_vm {
- uc_stack stack;
- uc_exception exception;
- uc_callframes callframes;
- uc_upvalref_t *open_upvals;
- uc_parse_config *config;
- uc_value_t *globals;
- uc_source *sources;
- uc_weakref_t values;
- union {
- uint32_t u32;
- int32_t s32;
- uint16_t u16;
- int16_t s16;
- uint8_t u8;
- int8_t s8;
- } arg;
- size_t spread_values;
- uint8_t trace;
-} uc_vm;
-
-typedef enum {
STATUS_OK,
ERROR_COMPILE,
ERROR_RUNTIME