diff --git a/.gitignore b/.gitignore
index 4d0826a..bb39ecf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-cmake-build-*
\ No newline at end of file
+cmake-build-*
+.idea/*
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 13566b8..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/.idea/ink.iml b/.idea/ink.iml
deleted file mode 100644
index f08604b..0000000
--- a/.idea/ink.iml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 79b3c94..0000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 0df1c94..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 65bbea2..eaf6b50 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,16 @@ project(ink C)
set(CMAKE_C_STANDARD 90)
add_library(ink lib.c ink.h)
+
+# Uncomment to disable the redundant arithmetic
+# add_definitions(-DNOEXTRAARITHMETIC)
+
+# Uncomment to disable array types
+# add_definitions(-DNOARRAYLIB)
+
+# Ensures the interpreter doesn't use the standard C library functions
+# add_definitions(-DNOSTDLIB)
+
add_executable(ink_exe main.c)
target_link_libraries(ink_exe PUBLIC ink)
diff --git a/README.md b/README.md
index bcf101b..7d0c706 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# `ink`
-`ink` is a minimalistic interpreted programming language, tentatively implemented exclusively in C98. It features
-coroutines and can currently only manipulate integers. Part of the code may not be compliant with C98 and I will try to
+`ink` is a minimalistic interpreted programming language, tentatively implemented exclusively in C89. It features
+coroutines and can currently only manipulate integers. Part of the code may not be compliant with C89 and I will try to
fix that in time.
It is fully self-contained and doesn't rely on a working standard library beyond the following:
@@ -13,8 +13,8 @@ It is fully self-contained and doesn't rely on a working standard library beyond
To make the library not use the standard library, build it with `NOSTDLIB` defined as a preprocessor directive.
-All of these functions need to work for `ink` to work. It is easy to add new functions to the interpreter. In the
-future, I will add a garbage collector to handle cleaning dynamically allocated resources.
+All of these functions need to work for `ink` to work. It is easy to add new functions to the interpreter. I added a
+garbage collector to handle cleaning dynamically allocated resources.
It is possible to segregate unsafe allocations (allocations that should be hidden from the interpreter) by setting the
`inner_` versions of the library functions to different allocation functions.
diff --git a/ink.h b/ink.h
index 22afddc..e77d8ee 100644
--- a/ink.h
+++ b/ink.h
@@ -94,6 +94,9 @@ struct ink_collection_list {
int count;
};
+/**
+ * Contains the data and metadata of an embedded element including the pointer to the element
+ */
struct element_slab {
void* data;
int uses;
@@ -247,7 +250,7 @@ int ink_step_everyone(struct context *pContext);
* @param pContext The context to execute the code in
* @param buffer The buffer that contains the source as a NULL terminated string
*/
-void ink_compile(struct context *pContext, char *buffer);
+void ink_compile(struct context *pContext, const char *buffer);
/**
* Includes the standard library in the specified context
diff --git a/lib.c b/lib.c
index 42100ea..538d4c7 100644
--- a/lib.c
+++ b/lib.c
@@ -514,7 +514,7 @@ int ink_make_routine(struct context* ctx) {
int new_count;
void* renewed;
new_count = (ctx->routines_capacity + ctx->routines_capacity/2);
- renewed = ctx->inner_realloc(ctx->routines, sizeof(struct stack_frame) * new_count);
+ renewed = ctx->inner_realloc(ctx->routines, sizeof(struct ink_routine) * new_count);
if(renewed == NULL) {
return -99;
} else {
@@ -770,7 +770,7 @@ int ink_step(struct context *pContext) {
return 1;
}
-void ink_compile(struct context *pContext, char* buffer) {
+void ink_compile(struct context *pContext, const char* buffer) {
int routine, saved, executable_buffer_top;
/* Main function has a size limit of 256 (need to know that for REPL */
struct elem executable_buffer[256];
@@ -1012,6 +1012,8 @@ void ink_gc(struct context* ctx) {
}
}
+ /* TODO: Mark objects contained within function code */
+
/* Mark the rest of the data */
do {
marked = 0;
@@ -1171,6 +1173,46 @@ static void div_int(struct context* ctx) {
currentRoutine->stack[currentRoutine->top-1].value = b.value / a.value;
}
+static void is_equal(struct context* ctx) {
+ struct ink_routine* currentRoutine;
+ struct elem a;
+ struct elem b;
+ struct elem ret;
+ currentRoutine = ctx->routines + ctx->routine_current;
+ if(currentRoutine->top < 2) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ a = currentRoutine->stack[currentRoutine->top-1];
+ b = currentRoutine->stack[currentRoutine->top-2];
+ ink_pop(ctx);
+ ink_pop(ctx);
+ ret.type = INK_INTEGER;
+ ret.value = a.value == b.value && a.type == b.type;
+
+}
+
+static void is_different(struct context* ctx) {
+ struct ink_routine* currentRoutine;
+ struct elem a;
+ struct elem b;
+ struct elem ret;
+ currentRoutine = ctx->routines + ctx->routine_current;
+ if(currentRoutine->top < 2) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ a = currentRoutine->stack[currentRoutine->top-1];
+ b = currentRoutine->stack[currentRoutine->top-2];
+ ink_pop(ctx);
+ ink_pop(ctx);
+ ret.type = INK_INTEGER;
+ ret.value = !(a.value == b.value && a.type == b.type);
+
+}
+
+#ifndef NOEXTRAARITHMETIC
+
static void rem_int(struct context* ctx) {
struct ink_routine* currentRoutine;
struct elem a;
@@ -1190,6 +1232,84 @@ static void rem_int(struct context* ctx) {
currentRoutine->stack[currentRoutine->top-1].value = b.value % a.value;
}
+static void gt_int(struct context* ctx) {
+ struct ink_routine* currentRoutine;
+ struct elem a;
+ struct elem b;
+ currentRoutine = ctx->routines + ctx->routine_current;
+ if(currentRoutine->top < 2) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ a = currentRoutine->stack[currentRoutine->top-1];
+ b = currentRoutine->stack[currentRoutine->top-2];
+ if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ ink_pop(ctx);
+ currentRoutine->stack[currentRoutine->top-1].value = b.value > a.value;
+}
+
+static void gte_int(struct context* ctx) {
+ struct ink_routine* currentRoutine;
+ struct elem a;
+ struct elem b;
+ currentRoutine = ctx->routines + ctx->routine_current;
+ if(currentRoutine->top < 2) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ a = currentRoutine->stack[currentRoutine->top-1];
+ b = currentRoutine->stack[currentRoutine->top-2];
+ if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ ink_pop(ctx);
+ currentRoutine->stack[currentRoutine->top-1].value = b.value >= a.value;
+}
+
+static void lte_int(struct context* ctx) {
+ struct ink_routine* currentRoutine;
+ struct elem a;
+ struct elem b;
+ currentRoutine = ctx->routines + ctx->routine_current;
+ if(currentRoutine->top < 2) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ a = currentRoutine->stack[currentRoutine->top-1];
+ b = currentRoutine->stack[currentRoutine->top-2];
+ if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ ink_pop(ctx);
+ currentRoutine->stack[currentRoutine->top-1].value = b.value <= a.value;
+}
+
+#endif // NOEXTRAARITHMETIC
+
+static void lt_int(struct context* ctx) {
+ struct ink_routine* currentRoutine;
+ struct elem a;
+ struct elem b;
+ currentRoutine = ctx->routines + ctx->routine_current;
+ if(currentRoutine->top < 2) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ a = currentRoutine->stack[currentRoutine->top-1];
+ b = currentRoutine->stack[currentRoutine->top-2];
+ if(!(a.type == INK_INTEGER && b.type == INK_INTEGER)) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ ink_pop(ctx);
+ currentRoutine->stack[currentRoutine->top-1].value = b.value < a.value;
+}
+
static void dupe_elem(struct context* ctx) {
struct ink_routine* currentRoutine;
struct elem a;
@@ -1348,12 +1468,6 @@ static void print_as_utf8(struct context* ctx) {
ink_pop(ctx);
}
-struct ink_array {
- int top;
- int capacity;
- struct elem* elements;
-};
-
static int get_type_by_name(struct context* ctx, const char* name) {
int i;
for(i = 0; i < ctx->types_top; ++i) {
@@ -1364,20 +1478,50 @@ static int get_type_by_name(struct context* ctx, const char* name) {
return -1;
}
+static void run_gc(struct context* ctx) {
+ ink_gc(ctx);
+}
+
+static void clear_stack(struct context* ctx) {
+ struct ink_routine* currentRoutine;
+ currentRoutine = ctx->routines + ctx->routine_current;
+ while (currentRoutine->top >= 1) {
+ ink_pop(ctx);
+ }
+ return;
+}
+
+static void collect_noop(struct context* _1, void* _2) {}
+
+static struct ink_collection_list gc_noop(struct context* _1, void* _2) {
+ struct ink_collection_list c;
+ c.elements = NULL;
+ c.count = 0;
+ return c;
+}
+
+#ifndef NOARRAYLIB
+
+struct ink_array {
+ int top;
+ int capacity;
+ struct elem* elements;
+};
+
static void collect_array(struct context* ctx, void* array) {
- struct ink_array* ary;
+ struct ink_array* ary;
ary = array;
- if(ary->elements != NULL) ctx->free(ary->elements);
+ if(ary->elements != NULL) ctx->free(ary->elements);
}
static struct ink_collection_list gc_array(struct context* ctx, void* array) {
- struct ink_array* ary;
- struct ink_collection_list c;
+ struct ink_array* ary;
+ struct ink_collection_list c;
ary = array;
- c.elements = ctx->inner_malloc(sizeof(struct elem)*ary->top);
- c.count = ary->top;
- memcpy(c.elements, ary->elements, sizeof(struct elem)*ary->top);
- return c;
+ c.elements = ctx->inner_malloc(sizeof(struct elem)*ary->top);
+ c.count = ary->top;
+ memcpy(c.elements, ary->elements, sizeof(struct elem)*ary->top);
+ return c;
}
static void new_array(struct context* ctx) {
@@ -1527,6 +1671,33 @@ static void index_array(struct context* ctx) {
ink_push(ctx, ary->elements[idx.value]);
}
+static void get_size_array(struct context* ctx) {
+ int tid;
+ struct ink_routine *currentRoutine;
+ struct elem a;
+ struct ink_array *ary;
+ struct elem sz;
+
+ tid = get_type_by_name(ctx, "array");
+ currentRoutine = ctx->routines + ctx->routine_current;
+ if (currentRoutine->top < 1 || currentRoutine->stack[currentRoutine->top - 1].type != tid) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ a = currentRoutine->stack[currentRoutine->top - 1];
+ ary = ink_get_value(ctx, a);
+ if (ary == NULL) {
+ currentRoutine->panic = -1;
+ return;
+ }
+ ink_pop(ctx);
+
+ sz.type = INK_INTEGER;
+ sz.value = ary->top;
+
+ ink_push(ctx, sz);
+}
+
static void print_array_of_codepoints(struct context* ctx) {
int tid, i;
struct ink_routine *currentRoutine;
@@ -1556,19 +1727,6 @@ static void print_array_of_codepoints(struct context* ctx) {
}
}
-static void run_gc(struct context* ctx) {
- ink_gc(ctx);
-}
-
-static void clear_stack(struct context* ctx) {
- struct ink_routine* currentRoutine;
- currentRoutine = ctx->routines + ctx->routine_current;
- while (currentRoutine->top >= 1) {
- ink_pop(ctx);
- }
- return;
-}
-
static void arrayify_stack(struct context* ctx) {
struct ink_routine* currentRoutine;
struct elem array_ref;
@@ -1594,27 +1752,11 @@ static void arrayify_stack(struct context* ctx) {
return;
}
-
-static void collect_noop(struct context*, void*) {}
-
-static struct ink_collection_list gc_noop(struct context*, void*) {
- struct ink_collection_list c;
- c.elements = NULL;
- c.count = 0;
- return c;
-}
+#endif // NOARRAYLIB
int ink_std_library(struct context* ctx) {
int v;
v = 0;
- ink_new_type(ctx, "array", sizeof(struct ink_array), collect_array, gc_array);
- ink_new_type(ctx, "array_marker", 0, collect_noop, gc_noop);
- v += ink_add_native(ctx, "[", push_array_stack_delim);
- v += ink_add_native(ctx, "]", push_delimited_array);
- v += ink_add_native(ctx, "array.new", new_array);
- v += ink_add_native(ctx, "array.push", push_array);
- v += ink_add_native(ctx, "array.index", index_array);
- v += ink_add_native(ctx, "array.print_utf8", print_array_of_codepoints);
v += ink_add_native(ctx, "sys.trace", print_stacktrace);
v += ink_add_native(ctx, "sys.gc", run_gc);
v += ink_add_native(ctx, "print_int", print_int);
@@ -1623,14 +1765,35 @@ int ink_std_library(struct context* ctx) {
v += ink_add_native(ctx, "-", sub_int);
v += ink_add_native(ctx, "*", mult_int);
v += ink_add_native(ctx, "/", div_int);
- v += ink_add_native(ctx, "%", rem_int);
+ v += ink_add_native(ctx, "==", is_equal);
+ v += ink_add_native(ctx, "!=", is_different);
+ v += ink_add_native(ctx, "<", lt_int);
v += ink_add_native(ctx, "swap", swap_elem);
v += ink_add_native(ctx, "dup", dupe_elem);
v += ink_add_native(ctx, "drop", drop_elem);
v += ink_add_native(ctx, "stack.clear", clear_stack);
- v += ink_add_native(ctx, "stack.to_array", arrayify_stack);
v += ink_add_native(ctx, "pluck", pluck_elem);
v += ink_add_native(ctx, "return_if", return_if);
v += ink_add_native(ctx, "jump_if", jump_if);
+#ifndef NOEXTRAARITHMETIC
+ v += ink_add_native(ctx, ">", gt_int);
+ v += ink_add_native(ctx, ">=", gte_int);
+ v += ink_add_native(ctx, "=<", lte_int);
+ v += ink_add_native(ctx, "%", rem_int);
+#endif // NOEXTRAARITHMETIC
+#ifndef NOARRAYLIB
+ ink_new_type(ctx, "array", sizeof(struct ink_array), collect_array, gc_array);
+ ink_new_type(ctx, "array_marker", 0, collect_noop, gc_noop);
+ v += ink_add_native(ctx, "[", push_array_stack_delim);
+ v += ink_add_native(ctx, "]", push_delimited_array);
+ v += ink_add_native(ctx, "array.new", new_array);
+ v += ink_add_native(ctx, "array.push", push_array);
+ v += ink_add_native(ctx, "array.index", index_array);
+ v += ink_add_native(ctx, "array.size", get_size_array);
+ v += ink_add_native(ctx, "array.print_utf8", print_array_of_codepoints);
+ v += ink_add_native(ctx, "stack.to_array", arrayify_stack);
+#endif // NOARRAYLIB
+
return v;
-}
\ No newline at end of file
+}
+