aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexis Lockwood2021-07-09 19:16:41 -0600
committerAlexis Lockwood2021-07-09 19:16:41 -0600
commit4abc365bb3e5569c037379a9905e5aaafa433779 (patch)
tree11bdfc532bd778ddf23ceb6e0598393891a11a9b
parentafd926c4f788cdded01f2511ddc79555cde5df22 (diff)
Prepare for adding more types
-rw-r--r--lib/ls.c31
-rw-r--r--lib/ls_expr.c10
-rw-r--r--lib/ls_internal.c98
-rw-r--r--lib/ls_internal.h27
-rw-r--r--lib/ls_kw_impl.c4
-rw-r--r--lib/ls_kw_impl_GOSUB_RETURN.c8
-rw-r--r--lib/ls_kw_impl_LOOPS.c21
-rw-r--r--lib/ls_kw_impl_PRINT.c3
-rw-r--r--lib/ls_kws.c2
-rw-r--r--lib/ls_kws.h2
-rw-r--r--lib/ls_types.h23
-rw-r--r--test/test_internal.c18
12 files changed, 103 insertions, 144 deletions
diff --git a/lib/ls.c b/lib/ls.c
index e0a1be4..5afe990 100644
--- a/lib/ls.c
+++ b/lib/ls.c
@@ -70,30 +70,6 @@ ls_print_value(FILE * stream, ls_value_t * value, ls_value_t * first)
fprintf(stream, "[int ] %"PRId32,
value->body.integer.value);
break;
- case LS_TY_STR:
- memcpy(buf, value->body.str.value, 4);
- buf[4] = 0;
- fprintf(stream,
- "[str ] len = %"PRIu16", chunk = <"POOL_F">, val = %s",
- value->body.str.length,
- TO_POOL_N(value->body.str.chunk),
- buf
- );
- break;
- case LS_TY_LIST:
- fprintf(stream,
- "[list ] len = %"PRIu16", first = <"POOL_F">, memo = %"PRIu16" @ <"POOL_F">",
- value->body.list.length,
- TO_POOL_N(value->body.list.first),
- value->body.list.memo_i,
- TO_POOL_N(value->body.list.memo)
- );
- break;
- case LS_TY_STR_CHUNK:
- memcpy(buf, value->body.str_chunk.value, 8);
- buf[8] = 0;
- fprintf(stream, "[strchunk] %s", buf);
- break;
case LS_TY_INT_VAR:
memcpy(buf, value->body.int_var.ident, LS_IDENT_LEN);
buf[LS_IDENT_LEN] = 0;
@@ -101,13 +77,6 @@ ls_print_value(FILE * stream, ls_value_t * value, ls_value_t * first)
buf, value->body.int_var.value
);
break;
- case LS_TY_VAR:
- memcpy(buf, value->body.var.ident, LS_IDENT_LEN);
- buf[LS_IDENT_LEN] = 0;
- fprintf(stream, "[var ] %s = <"POOL_F">",
- buf, TO_POOL_N(value->body.var.value)
- );
- break;
case LS_TY_LABEL:
memcpy(buf, value->body.label.ident, LS_IDENT_LEN);
buf[LS_IDENT_LEN] = 0;
diff --git a/lib/ls_expr.c b/lib/ls_expr.c
index 3c5581b..4d77907 100644
--- a/lib/ls_expr.c
+++ b/lib/ls_expr.c
@@ -296,13 +296,15 @@ _handle_number(ls_shuntingyard_t * yard)
static void
_handle_word(ls_shuntingyard_t * yard)
{
- ls_value_t * var = ls_find_var(yard->self, yard->self->_token.word);
+ ls_value_t * var = ls_find_var(yard->self, yard->self->_token.word,
+ false);
- if (!var)
- ls_throw_err(yard->self, LS_UNDEFINED_VARIABLE);
+ ls_value_t val;
+ ls_read_scalar_var(yard->self, var, &val);
// TODO: types
- yard->self->_token.number = ls_read_int_var(yard->self, var);
+ ls_coerce_int(yard->self, &val);
+ yard->self->_token.number = val.body.integer.value;
}
static ls_token_t
diff --git a/lib/ls_internal.c b/lib/ls_internal.c
index 1c20820..5098f75 100644
--- a/lib/ls_internal.c
+++ b/lib/ls_internal.c
@@ -238,12 +238,6 @@ ls_free_val(ls_t * self, ls_value_t * v)
switch (v->ty)
{
- case LS_TY_STR:
- child = v->body.str.chunk;
- break;
- case LS_TY_LIST:
- child = v->body.list.first;
- break;
case LS_TY_SCTX_CALL:
case LS_TY_SCTX_FOR:
case LS_TY_SCTX_WHILE:
@@ -255,10 +249,13 @@ ls_free_val(ls_t * self, ls_value_t * v)
// and didn't need a next pointer.
child = v->next;
break;
+
+ /* TODO scalar vars will work like this
case LS_TY_VAR:
ls_free_val(self, v->body.var.value);
child = NULL;
break;
+ */
default:
child = NULL;
break;
@@ -290,24 +287,33 @@ ls_mem_avail(ls_t * self)
}
ls_value_t *
-ls_find_var(ls_t * self, char const * name)
+ls_find_var(ls_t * self, char const * name, bool create)
{
for (ls_value_t * scope = self->_callstack; scope; scope = scope->prev)
{
for (ls_value_t * var = scope->next; var; var = var->next)
{
char const * ident;
- if (var->ty == LS_TY_INT_VAR)
+ // This switch should optimize out - these are all at
+ // the same address
+ switch (var->ty)
+ {
+ case LS_TY_INT_VAR:
ident = var->body.int_var.ident;
- else
- ident = var->body.var.ident;
+ break;
+ default:
+ ls_throw_err(self, LS_INTERNAL_ERROR);
+ }
if (!strncmp(ident, name, LS_IDENT_LEN))
return var;
}
}
- return NULL;
+ if (create)
+ return ls_new_var(self, name);
+ else
+ ls_throw_err(self, LS_UNDEFINED_VARIABLE);
}
ls_value_t *
@@ -327,51 +333,48 @@ ls_new_var(ls_t * self, char const * name)
return var;
}
-ls_int_t
-ls_read_int_var(ls_t * self, ls_value_t * var)
+void
+ls_read_scalar_var(ls_t * self, ls_value_t const * var, ls_value_t * val)
{
- if (var->ty == LS_TY_INT_VAR)
- return var->body.int_var.value;
- else
- ls_throw_err(self, LS_TYPE_MISMATCH);
+ switch (var->ty)
+ {
+ case LS_TY_INT_VAR:
+ val->ty = LS_TY_INT;
+ val->body.integer.value = var->body.int_var.value;
+ break;
+ default:
+ ls_throw_err(self, LS_INTERNAL_ERROR);
+ }
}
void
-ls_write_int_var(ls_t * self, ls_value_t * var, ls_int_t val)
+ls_write_scalar_var(ls_t * self, ls_value_t * var, ls_value_t * const val)
{
- if (var->ty == LS_TY_VAR)
+ // TODO - when vector vars are implemented, make sure their children
+ // get freed here.
+
+ switch (val->ty)
{
- if (var->body.var.value)
- ls_free(self, var->body.var.value);
+ case LS_TY_INT:
var->ty = LS_TY_INT_VAR;
- }
-
- if (var->ty != LS_TY_INT_VAR)
- ls_throw_err(self, LS_INTERNAL_ERROR);
+ var->body.int_var.value = val->body.integer.value;
+ break;
- var->body.int_var.value = val;
+ default:
+ ls_throw_err(self, LS_TYPE_MISMATCH);
+ }
}
void
-ls_write_var(ls_t * self, ls_value_t * var, ls_value_t * val)
+ls_coerce_int(ls_t * self, ls_value_t * value)
{
- if (val->ty == LS_TY_INT)
+ switch (value->ty)
{
- ls_write_int_var(self, var, val->body.integer.value);
- }
- else
- {
- if (var->ty == LS_TY_INT_VAR)
- {
- var->ty = LS_TY_VAR;
- var->body.var.value = NULL;
- }
-
- if (var->body.var.value)
- ls_free_val(self, var->body.var.value);
+ case LS_TY_INT:
+ return;
- var->body.var.value = ls_alloc(self);
- memcpy(var->body.var.value, val, sizeof(ls_value_t));
+ default:
+ ls_throw_err(self, LS_TYPE_MISMATCH);
}
}
@@ -413,21 +416,14 @@ ls_exec_statement(ls_t * self, ls_token_t tok)
// Now both implicit and explicit LET can be handled
if (tok == LS_TOK_WORD)
{
- ls_value_t * var = ls_find_var(self, self->_token.word);
-
- if (!var)
- var = ls_new_var(self, self->_token.word);
+ ls_value_t * var = ls_find_var(self, self->_token.word, true);
if (ls_lex(self) != LS_OP_EQ)
ls_throw_err(self, LS_SYNTAX_ERROR);
ls_value_t val;
ls_eval_expr(self, &val, LS_TOK_NONE);
-
- if (val.ty != LS_TY_INT)
- ls_throw_err(self, LS_TYPE_MISMATCH);
-
- ls_write_int_var(self, var, val.body.integer.value);
+ ls_write_scalar_var(self, var, &val);
}
else if (LS_TOK_KEYWORD(tok))
{
diff --git a/lib/ls_internal.h b/lib/ls_internal.h
index 831d1d2..b2daf86 100644
--- a/lib/ls_internal.h
+++ b/lib/ls_internal.h
@@ -173,27 +173,30 @@ void ls_free_val(ls_t * self, ls_value_t * v);
/// Count the number of free blocks
size_t ls_mem_avail(ls_t * self);
-/// Find and return a variable by name.
+/// Find and return a variable by name. This function always returns a
+/// variable:
///
-/// @retval NULL if the variable does not exist
-ls_value_t * ls_find_var(ls_t * self, char const * name);
+/// - If it can be found, return it.
+/// - If it cannot:
+/// - If @a create is false, throw LS_UNDEFINED_VARIABLE.
+/// - If @a create is true, create and return it, or throw LS_OUT_OF_MEMORY.
+///
+/// @param create - if true, the variable will be created if it does not exist.
+ls_value_t * ls_find_var(ls_t * self, char const * name, bool create);
/// Create a new variable in the current scope.
///
/// @return the variable
ls_value_t * ls_new_var(ls_t * self, char const * name);
-/// Read an integer variable. If the variable does not contain an integer,
-/// throw LS_TYPE_MISMATCH.
-ls_int_t ls_read_int_var(ls_t * self, ls_value_t * var);
+/// Read a scalar variable.
+void ls_read_scalar_var(ls_t * self, ls_value_t const * var, ls_value_t * val);
-/// Write an integer variable. If the variable contains a different type, its
-/// type will be changed.
-void ls_write_int_var(ls_t * self, ls_value_t * var, ls_int_t val);
+/// Write a scalar value into a variable.
+void ls_write_scalar_var(ls_t * self, ls_value_t * var, ls_value_t * const val);
-/// Write a variable of any type. val is not consumed and is assumed not
-/// to live in the pool (space is allocated as needed).
-void ls_write_var(ls_t * self, ls_value_t * var, ls_value_t * val);
+/// Coerce a value into an LS_TY_INT. If not possible, throw LS_TYPE_MISMATCH.
+void ls_coerce_int(ls_t * self, ls_value_t * value);
/// Execute one line.
///
diff --git a/lib/ls_kw_impl.c b/lib/ls_kw_impl.c
index ed54939..59851dc 100644
--- a/lib/ls_kw_impl.c
+++ b/lib/ls_kw_impl.c
@@ -52,9 +52,7 @@ ls_kw_fun_IF(ls_t * self)
ls_value_t cond;
ls_eval_expr(self, &cond, LS_TOK_NONE);
-
- if (cond.ty != LS_TY_INT)
- ls_throw_err(self, LS_TYPE_MISMATCH);
+ ls_coerce_int(self, &cond);
if (cond.body.integer.value == 0)
{
diff --git a/lib/ls_kw_impl_GOSUB_RETURN.c b/lib/ls_kw_impl_GOSUB_RETURN.c
index 90bae09..f4a64f5 100644
--- a/lib/ls_kw_impl_GOSUB_RETURN.c
+++ b/lib/ls_kw_impl_GOSUB_RETURN.c
@@ -111,10 +111,8 @@ ls_kw_fun_RETURN(ls_t * self)
if (!no_value)
{
// TODO hmm this is getting long
- ls_value_t * var = ls_find_var(self, self->_token.word);
- if (!var)
- var = ls_new_var(self, self->_token.word);
- ls_write_var(self, var, &val);
+ ls_value_t * var = ls_find_var(self, self->_token.word, true);
+ ls_write_scalar_var(self, var, &val);
}
}
else if (tok == LS_OP_LPAREN)
@@ -159,7 +157,7 @@ static void _parse_args(ls_t * self)
self->_callstack = self->_callstack->prev;
ls_value_t val;
ls_eval_expr(self, &val, LS_TOK_NONE);
- ls_write_var(self, var, &val);
+ ls_write_scalar_var(self, var, &val);
self->_callstack = frame;
}
else if (tok != LS_OP_RPAREN && tok != LS_TOK_COMMA)
diff --git a/lib/ls_kw_impl_LOOPS.c b/lib/ls_kw_impl_LOOPS.c
index b42531f..0b9119a 100644
--- a/lib/ls_kw_impl_LOOPS.c
+++ b/lib/ls_kw_impl_LOOPS.c
@@ -61,16 +61,14 @@ ls_kw_fun_FOR(ls_t * self)
// FOR ident = <<a TO b>> STEP c
ls_value_t val;
ls_eval_expr(self, &val, LS_TOK_NONE);
- if (val.ty != LS_TY_INT)
- goto type_err;
+ ls_coerce_int(self, &val);
iterator->body.int_var.value = val.body.integer.value;
if (ls_lex(self) != LS_KW_TO)
goto syntax_err;
ls_eval_expr(self, &val, LS_TOK_NONE);
- if (val.ty != LS_TY_INT)
- goto type_err;
+ ls_coerce_int(self, &val);
ctx->body.sctx_for.term = val.body.integer.value;
// FOR ident = a TO b <<STEP c>>
@@ -79,8 +77,7 @@ ls_kw_fun_FOR(ls_t * self)
if (tok == LS_KW_STEP)
{
ls_eval_expr(self, &val, LS_TOK_NONE);
- if (val.ty != LS_TY_INT)
- goto type_err;
+ ls_coerce_int(self, &val);
if (val.body.integer.value > INT16_MAX ||
val.body.integer.value < INT16_MIN)
@@ -96,10 +93,10 @@ ls_kw_fun_FOR(ls_t * self)
return;
}
else
+ goto syntax_err;
+
syntax_err:
ls_throw_err(self, LS_SYNTAX_ERROR);
-type_err:
- ls_throw_err(self, LS_TYPE_MISMATCH);
}
void
@@ -148,9 +145,7 @@ ls_kw_fun_WHILE(ls_t * self)
ls_value_t cond;
ls_eval_expr(self, &cond, LS_TOK_NONE);
-
- if (cond.ty != LS_TY_INT)
- ls_throw_err(self, LS_TYPE_MISMATCH);
+ ls_coerce_int(self, &cond);
if (cond.body.integer.value != 0)
{
@@ -216,9 +211,7 @@ ls_kw_fun_WEND(ls_t * self)
ls_value_t cond;
ls_eval_expr(self, &cond, LS_TOK_NONE);
-
- if (cond.ty != LS_TY_INT)
- ls_throw_err(self, LS_TYPE_MISMATCH);
+ ls_coerce_int(self, &cond);
if (cond.body.integer.value == 0)
{
diff --git a/lib/ls_kw_impl_PRINT.c b/lib/ls_kw_impl_PRINT.c
index 739f93b..6803edf 100644
--- a/lib/ls_kw_impl_PRINT.c
+++ b/lib/ls_kw_impl_PRINT.c
@@ -102,9 +102,6 @@ _print_value(FILE * f, ls_value_t const * value)
_print_value(f, &intval);
break;
}
- case LS_TY_VAR:
- _print_value(f, value->body.var.value);
- break;
default:
fprintf(f, "<unknown type>");
break;
diff --git a/lib/ls_kws.c b/lib/ls_kws.c
index 8f60061..6b8d3e7 100644
--- a/lib/ls_kws.c
+++ b/lib/ls_kws.c
@@ -1,4 +1,4 @@
-// This code was generated by gen_kws.py at Thu 08 Jul 2021 07:38:18 PM MDT
+// This code was generated by gen_kws.py at Fri 09 Jul 2021 07:16:09 PM MDT
#include "ls_internal.h"
const LS_PROGMEM uint8_t ls_kw_hashmap_indices[] = {
diff --git a/lib/ls_kws.h b/lib/ls_kws.h
index 6f2487b..2214d40 100644
--- a/lib/ls_kws.h
+++ b/lib/ls_kws.h
@@ -1,4 +1,4 @@
-// This code was generated by gen_kws.py at Thu 08 Jul 2021 07:38:18 PM MDT
+// This code was generated by gen_kws.py at Fri 09 Jul 2021 07:16:09 PM MDT
#ifndef LS_TYPES_H
# error "ls_kws.h should not be included directly! Include ls_types.h instead."
#endif
diff --git a/lib/ls_types.h b/lib/ls_types.h
index 15ef207..659b047 100644
--- a/lib/ls_types.h
+++ b/lib/ls_types.h
@@ -99,6 +99,11 @@ typedef struct {
// --- COMPLEX TYPES -----------------------------------------------------------
+/* TODO - I'm changing this to "scalar" and "vector" variables. There will be
+ * ls_ty_int_var_t, ls_ty_float_var_t, and ls_ty_vect_var_t + ls_ty_str_var_t
+ * (the last two identical in structure). The general idea of these two types
+ * will probably be retained.
+ *
/// String variable. This contains eight bytes at a time in chunks (the head
/// contains fewer bytes, so it can fit more information in the same 8).
typedef struct {
@@ -121,15 +126,18 @@ typedef struct {
uint16_t memo_i;
uint16_t length;
} ls_ty_list_t;
+*/
// --- CHILD TYPES -------------------------------------------------------------
+/*
/// String chunk. Used by ls_ty_str_t. The PREV and NEXT pointers are used to
/// link up the chunks. The first chunk should point back at the string head,
/// and the last chunk should point forward to NULL.
typedef struct {
char value[8];
} ls_ty_str_chunk_t;
+*/
// --- INTERNAL TYPES ----------------------------------------------------------
@@ -141,14 +149,6 @@ typedef struct {
ls_int_t value;
} ls_ty_int_var_t;
-/// Generic variable. This points at a subtype. It should never be used for
-/// integers (integer code assumes non-TY_INT_VAR variables do not contain
-/// ints, as an optimization).
-typedef struct {
- char ident[LS_IDENT_LEN];
- struct ls_value_s * value;
-} ls_ty_var_t;
-
/// Label. This points to the PC of the start of the line just after the label.
typedef struct {
char ident[LS_IDENT_LEN];
@@ -213,7 +213,6 @@ typedef enum {
LS_TY_STR_CHUNK = LS_TY_CHILD_START,
LS_TY_INT_VAR = LS_TY_INTERNAL_START,
- LS_TY_VAR,
LS_TY_LABEL,
LS_TY_SCTX_CALL,
LS_TY_SCTX_FOR,
@@ -238,13 +237,7 @@ typedef struct ls_value_s {
union {
ls_ty_int_t integer;
- ls_ty_str_t str;
- ls_ty_list_t list;
-
- ls_ty_str_chunk_t str_chunk;
-
ls_ty_int_var_t int_var;
- ls_ty_var_t var;
ls_ty_label_t label;
ls_ty_sctx_call_t sctx_call;
ls_ty_sctx_for_t sctx_for;
diff --git a/test/test_internal.c b/test/test_internal.c
index 39b38fd..3ee368f 100644
--- a/test/test_internal.c
+++ b/test/test_internal.c
@@ -224,11 +224,15 @@ DECLTEST(_ls_lookup_var)
ls._callstack->body.sctx_call.pc = LS_ADDR_NULL;
ls._callstack->body.sctx_call.readptr = LS_ADDR_NULL;
+ ls_value_t val = {.ty = LS_TY_INT};
+
ls_value_t * var_foo = ls_new_var(&ls, "foo");
- ls_write_int_var(&ls, var_foo, 20);
+ val.body.integer.value = 20;
+ ls_write_scalar_var(&ls, var_foo, &val);
ls_value_t * var_bar = ls_new_var(&ls, "bar");
- ls_write_int_var(&ls, var_bar, 4);
+ val.body.integer.value = 4;
+ ls_write_scalar_var(&ls, var_foo, &val);
ls_value_t val;
size_t sz_pool = ls_mem_avail(&ls);
@@ -270,7 +274,10 @@ DECLTEST(_ls_let)
ls_exec_line(&ls);
ls_value_t * var_z = ls_find_var(&ls, "z");
- munit_assert_int(ls_read_int_var(&ls, var_z), ==, 1337);
+ ls_value_t val;
+ ls_read_scalar_var(self, var_z, &val);
+ ls_coerce_int(self, &val);
+ munit_assert_int(val.body.integer.value, ==, 1337);
return MUNIT_OK;
}
@@ -290,7 +297,10 @@ DECLTEST(_ls_run)
dammit_assert_enum(e, ==, LS_OK);
ls_value_t * var_z = ls_find_var(&ls, "z");
- munit_assert_int(ls_read_int_var(&ls, var_z), ==, 1337);
+ ls_value_t val;
+ ls_read_scalar_var(self, var_z, &val);
+ ls_coerce_int(self, &val);
+ munit_assert_int(var_z.body.integer.value, ==, 1337);
/*
fprintf(stdout, "\n");
for (size_t i = 0; i < 16; i++)