|
diff --git a/bin/Splice b/bin/Splice
index b486ed3..6718b69 100755
Binary files a/bin/Splice and b/bin/Splice differ
diff --git a/bin/spbuild b/bin/spbuild
index 08880d9..ad769dc 100755
Binary files a/bin/spbuild and b/bin/spbuild differ
diff --git a/build.sh b/build.sh
index c5d4635..4ae474b 100755
--- a/build.sh
+++ b/build.sh
@@ -20,16 +20,16 @@ echo "Proceeding with build on $OS/$ARCH..."
echo "Building Splice runtime and native module..."
# Compile Splice runtime (with SDK globals)
-gcc -DSDK_IMPLEMENTATION -Isrc -Wall -Wextra -c src/splice.c -o "$BIN_DIR/Splice.o"
+gcc -DSDK_IMPLEMENTATION -Isrc -Wall -Wextra -c -DNDEBUG -O3 -flto src/splice.c -o "$BIN_DIR/Splice.o"
# Compile native module without SDK_IMPLEMENTATION
-gcc -Isrc -Wall -Wextra -c src/module_stubs.c -o "$BIN_DIR/module_stubs.o"
+gcc -Isrc -Wall -Wextra -c -DNDEBUG -O3 -flto src/module_stubs.c -o "$BIN_DIR/module_stubs.o"
# Link executable (local binary: Splice)
gcc "$BIN_DIR/Splice.o" "$BIN_DIR/module_stubs.o" -o "$BIN_DIR/Splice"
echo "Building spbuild (bytecode compiler)..."
-gcc -Isrc -Wall -Wextra src/build.c -o "$BIN_DIR/spbuild"
+gcc -Isrc -Wall -Wextra -DNDEBUG -O3 -flto src/build.c -o "$BIN_DIR/spbuild"
# --- Install section ---
INSTALL_DIR=""
diff --git a/docs.md b/docs.md
index 8bbc9ef..965e566 100644
--- a/docs.md
+++ b/docs.md
@@ -1,11 +1,266 @@
-# How to code in Splice
+# How to Code in Splice
-Splice is a very basic language and some of the syntax is derived from Lua, Python and a bit of it's own syntax.
+Splice is a lightweight and embeddable programming language.
+Its syntax is inspired by Lua and Python, with additional custom syntax
+designed to keep the language simple and predictable.
-## Print
+Splice programs are executed from top to bottom.
-Printing in Splice is written using
+---
-``` Splice
+## Program Structure
+
+A basic Splice program consists of statements separated by semicolons.
+
+```splice
+print("Hello, Splice");
+```
+
+---
+
+## Comments
+
+Splice supports single-line comments using `//`.
+
+```splice
+// This is a comment
+print("This line will execute");
+```
+
+---
+
+## Printing Output
+
+Printing output is done using the `print` keyword.
+
+```splice
print("Hi");
```
+
+### Printing Variables
+
+```splice
+let x = 10;
+print(x);
+```
+
+---
+
+## Variables
+
+Variables are declared using the `let` keyword.
+
+```splice
+let number = 42;
+let name = "Splice";
+let pi = 3.14;
+```
+
+Splice is dynamically typed, meaning the type is determined at runtime.
+
+---
+
+## Arithmetic Operations
+
+Splice supports basic arithmetic operations.
+
+```splice
+let a = 10;
+let b = 5;
+
+print(a + b);
+print(a - b);
+print(a * b);
+print(a / b);
+```
+
+---
+
+## Comparison Operators
+
+Splice supports standard comparison operators.
+
+```splice
+let x = 10;
+
+print(x == 10);
+print(x != 5);
+print(x > 5);
+print(x < 20);
+```
+
+---
+
+## If Statements
+
+Conditional execution is done using `if`.
+
+```splice
+let age = 18;
+
+if (age >= 18) {
+ print("You are an adult");
+}
+```
+
+---
+
+## If-Else Statements
+
+```splice
+let score = 40;
+
+if (score >= 50) {
+ print("Pass");
+} else {
+ print("Fail");
+}
+```
+
+---
+
+## While Loops
+
+The `while` loop executes as long as the condition is true.
+
+```splice
+let i = 0;
+
+while (i < 5) {
+ print(i);
+ i = i + 1;
+}
+```
+
+---
+
+## For Loops
+
+Splice supports `for` loops with a counter variable.
+
+```splice
+for (let i = 0; i < 5; i = i + 1) {
+ print(i);
+}
+```
+
+---
+
+## Functions
+
+Functions are declared using the `func` keyword.
+
+```splice
+func add(a, b) {
+ return a + b;
+}
+```
+
+### Calling Functions
+
+```splice
+let result = add(10, 20);
+print(result);
+```
+
+---
+
+## Return Statement
+
+Functions return values using `return`.
+
+```splice
+func square(x) {
+ return x * x;
+}
+
+print(square(5));
+```
+
+---
+
+## User Input
+
+Splice supports input using the `input` keyword.
+
+```splice
+let name = input("Enter your name: ");
+print(name);
+```
+
+---
+
+## Error Handling
+
+Splice provides basic error reporting at runtime.
+Errors include:
+
+- Undefined variables
+- Invalid operations
+- Syntax errors
+
+---
+
+## Execution Model (High Level)
+
+Splice executes programs by walking an Abstract Syntax Tree (AST).
+Each node represents a language construct such as variables, function calls,
+loops, or expressions.
+
+This design allows:
+
+- Easy embedding in C programs
+- Simpler debugging
+- Low memory overhead
+
+---
+
+## Embedding Splice in C
+
+Splice is designed to be embedded in C applications.
+
+```c
+#include
+
+#define ARDUINO
+#define SPLICE_EMBED 1
+
+#include "splice.h"
+
+/*
+Splice source (compiled beforehand):
+
+print("Hello from Splice");
+*/
+
+const unsigned char program[] = {
+ 'S','P','C',0x00, // magic
+ 0x01, // version
+
+ AST_PRINT,
+ AST_STRING,
+ 0x00, 0x11,
+ 'H','e','l','l','o',' ',
+ 'f','r','o','m',' ',
+ 'S','p','l','i','c','e'
+};
+
+void setup() {
+ Serial.begin(115200);
+ while (!Serial);
+
+ ASTNode *root = read_ast_from_spc_mem(
+ program,
+ sizeof(program)
+ );
+
+ interpret(root);
+}
+
+void loop() {}
+
+```
+
+---
+
+
diff --git a/examples/.DS_Store b/examples/.DS_Store
new file mode 100644
index 0000000..d0c089b
Binary files /dev/null and b/examples/.DS_Store differ
diff --git a/examples/array/array.spc b/examples/array/array.spc
deleted file mode 100644
index 0cc0ccb..0000000
Binary files a/examples/array/array.spc and /dev/null differ
diff --git a/examples/calculator/calc_test.spl b/examples/calculator/calc_test.spl
index 1676f88..fa43b30 100644
--- a/examples/calculator/calc_test.spl
+++ b/examples/calculator/calc_test.spl
@@ -1,10 +1,11 @@
func calculator(num1, num2, op) {
if (op == "+") {
- print(num1 + num2)
- } else {
- print("Invalid operator: " + op)
+ print(num1 + num2);
+ }
+ if (op == "-") {
+ print(num1 - num2);
}
}
-calculator(5, 3, "+") // prints 8
-calculator(5, 3, "%") // prints "Invalid operator: %"
+calculator(5, 3, "+");
+calculator(5, 3, "-");
diff --git a/examples/calculator/hello.spc b/examples/calculator/hello.spc
new file mode 100644
index 0000000..2416d73
Binary files /dev/null and b/examples/calculator/hello.spc differ
diff --git a/examples/forloops/for.spc b/examples/forloops/for.spc
new file mode 100644
index 0000000..36e3e3f
Binary files /dev/null and b/examples/forloops/for.spc differ
diff --git a/examples/helloworld/hello.spc b/examples/helloworld/hello.spc
index c0b4d3d..1a85573 100644
Binary files a/examples/helloworld/hello.spc and b/examples/helloworld/hello.spc differ
diff --git a/examples/helloworld/helloworld.spl b/examples/helloworld/helloworld.spl
index 44159b3..7baa068 100644
--- a/examples/helloworld/helloworld.spl
+++ b/examples/helloworld/helloworld.spl
@@ -1 +1 @@
-print("Hello world")
+print("Hello world");
diff --git a/release.md b/release.md
index 8f9260a..097300f 100644
--- a/release.md
+++ b/release.md
@@ -1,7 +1,8 @@
# Release notes
-Current Version: 1.0
+Current Version: 1.1 Beta
## Overview
-This Version of Splice Made it so now the ast Dce and all of the building is done in spbuild so vm can be use in a esp32
\ No newline at end of file
+* Major bug fixes
+* Added MAX_FUNCS **(Set 16 for embedded and 32 for Normal PC as functions excedding MAX_FUNCS cause Segmentation fault)**
\ No newline at end of file
diff --git a/splib/math.spl b/splib/math.spl
index dc0245e..a64767b 100644
--- a/splib/math.spl
+++ b/splib/math.spl
@@ -36,122 +36,3 @@ func round(x) {
return int(x - 0.5);
};
-// ---- powers & roots (native) ----
-func pow(x, y) {
- native pow(x, y);
-};
-
-func sqrt(x) {
- native sqrt(x);
-};
-
-func exp(x) {
- native exp(x);
-};
-
-func log(x) {
- native log(x);
-};
-
-func log10(x) {
- native log10(x);
-};
-
-func log2(x) {
- native log2(x);
-};
-
-// ---- trigonometry (native) ----
-func sin(x) {
- native sin(x);
-};
-
-func cos(x) {
- native cos(x);
-};
-
-func tan(x) {
- native tan(x);
-};
-
-func asin(x) {
- native asin(x);
-};
-
-func acos(x) {
- native acos(x);
-};
-
-func atan(x) {
- native atan(x);
-};
-
-func atan2(y, x) {
- native atan2(y, x);
-};
-
-// ---- angle conversion ----
-func radians(deg) {
- return deg * (pi / 180);
-};
-
-func degrees(rad) {
- return rad * (180 / pi);
-};
-
-// ---- rounding helpers (native) ----
-func floor(x) {
- native floor(x);
-};
-
-func ceil(x) {
- native ceil(x);
-};
-
-func trunc(x) {
- native trunc(x);
-};
-
-// ---- number theory ----
-func gcd(a, b) {
- a = abs(a);
- b = abs(b);
-
- if (a == 0) {
- return b;
- };
- if (b == 0) {
- return a;
- };
-
- while (a != b) {
- if (a > b) {
- a = a - b;
- } else {
- b = b - a;
- };
- };
-
- return a;
-};
-
-func lcm(a, b) {
- return abs(a * b) / gcd(a, b);
-};
-
-func factorial(n) {
- if (n < 0) {
- raise ("factorial: negative value");
- };
-
- let r = 1;
- while (n > 1) {
- r = r * n;
- n = n - 1;
- };
-
- return r;
-};
-
-
-
diff --git a/src/build.c b/src/build.c
index b2813d5..3181211 100644
--- a/src/build.c
+++ b/src/build.c
@@ -5,6 +5,13 @@
#include "splice.h"
/* uses AST types + write_ast_to_spc */
+ASTNode* ast_tuple(ASTNode** items, int count) {
+ ASTNode* node = malloc(sizeof(ASTNode));
+ node->type = AST_TUPLE;
+ node->tuple.items = items;
+ node->tuple.count = count;
+ return node;
+}
static inline int write_ast_to_spc(const char *out_file, const ASTNode *root) {
FILE *f = fopen(out_file, "wb");
@@ -306,10 +313,39 @@ static ASTNode *parse_primary(void) {
}
if (match(TK_LPAREN)) {
- ASTNode *e = parse_expression();
+ ASTNode *first = parse_expression();
+
+ /* tuple if comma appears */
+ if (match(TK_COMMA)) {
+ ASTNode **items = NULL;
+ int count = 0, cap = 0;
+
+ /* first element */
+ cap = 4;
+ items = (ASTNode**)malloc(sizeof(ASTNode*) * cap);
+ items[count++] = first;
+
+ do {
+ if (count >= cap) {
+ cap *= 2;
+ items = (ASTNode**)realloc(items, sizeof(ASTNode*) * cap);
+ }
+ items[count++] = parse_expression();
+ } while (match(TK_COMMA));
+
+ consume(TK_RPAREN, "Expected ')' after tuple");
+
+ ASTNode *t = ast_new(AST_TUPLE);
+ t->tuple.items = items;
+ t->tuple.count = count;
+ return t;
+ }
+
+ /* otherwise normal grouping */
consume(TK_RPAREN, "Expected ')'");
- return e;
+ return first;
}
+
if (match(TK_READ)) {
consume(TK_LPAREN, "Expected '(' after read");
ASTNode *e = parse_expression();
diff --git a/src/module_stubs.c b/src/module_stubs.c
index e5aba20..592055d 100644
--- a/src/module_stubs.c
+++ b/src/module_stubs.c
@@ -1,11 +1,3 @@
-/* Minimal module stubs for Splice runtime
- * This file is intentionally small: it registers a tiny example native
- * function and ensures module initializers are invoked at program
- * startup. Real native modules can be added by providing additional
- * init functions that call Splice_register_native() or by providing
- * Splice_register_module_ symbols which are looked up by the
- * import mechanism in `splice.h`.
- */
#include "splice.h"
#include
diff --git a/src/splice.h b/src/splice.h
index 5b6ab56..e828f19 100644
--- a/src/splice.h
+++ b/src/splice.h
@@ -93,7 +93,11 @@ typedef struct Value {
void *object;
} Value;
-typedef enum { OBJ_ARRAY } ObjectType;
+typedef enum {
+ OBJ_ARRAY,
+ OBJ_TUPLE
+} ObjectType;
+
typedef struct {
ObjectType type;
int count;
@@ -107,6 +111,7 @@ typedef struct {
/* =========================
AST
========================= */
+
typedef enum {
AST_NUMBER = 0,
AST_STRING,
@@ -123,6 +128,7 @@ typedef enum {
AST_INFO,
AST_WHILE,
AST_IF,
+ AST_TUPLE,
AST_STATEMENTS,
AST_FUNC_DEF,
AST_FUNCTION_CALL,
@@ -147,7 +153,10 @@ struct ASTNode {
ASTNode *left;
ASTNode *right; /* may be NULL for unary */
} binop;
-
+ struct {
+ ASTNode** items;
+ int count;
+ } tuple;
struct {
char *varname;
ASTNode *value;
@@ -216,7 +225,10 @@ struct ASTNode {
} indexassign;
};
};
-
+typedef struct {
+ ASTNode** items;
+ int count;
+} ASTTuple;
/* =========================
Env (vars + funcs)
========================= */
@@ -232,21 +244,59 @@ typedef struct {
void *obj;
} Var;
-static Var vars[32];
-static int var_count = 0;
+#define VAR_TABLE_SIZE 256 /* power of 2 = fast modulo */
+
+typedef struct {
+ char *name; /* interned or strdup */
+ VarType type;
+ double value;
+ char *str;
+ void *obj;
+ int used;
+} VarSlot;
+
+static VarSlot var_table[VAR_TABLE_SIZE];
+static inline unsigned hash_str(const char *s) {
+ unsigned h = 2166136261u;
+ while (*s) {
+ h ^= (unsigned char)*s++;
+ h *= 16777619u;
+ }
+ return h;
+}
+static inline Var* var_number(double d) {
+ Var *v = malloc(sizeof(Var));
+ v->name = NULL;
+ v->type = VAR_NUMBER;
+ v->value = d;
+ v->str = NULL;
+ v->obj = NULL;
+ return v;
+}
+
-static inline Var *get_var(const char *name) {
+static inline VarSlot *get_var(const char *name) {
if (!name) return NULL;
- for (int j = 0; j < var_count; ++j) {
- if (!vars[j].name) continue;
- if (strcmp(vars[j].name, name) == 0)
- return &vars[j];
+ unsigned h = hash_str(name);
+ unsigned idx = h & (VAR_TABLE_SIZE - 1);
+
+ for (unsigned i = 0; i < VAR_TABLE_SIZE; i++) {
+ VarSlot *v = &var_table[idx];
+
+ if (!v->used)
+ return NULL; /* empty slot = not found */
+
+ if (strcmp(v->name, name) == 0)
+ return v;
+
+ idx = (idx + 1) & (VAR_TABLE_SIZE - 1); /* linear probe */
}
return NULL;
}
+
static inline void free_object(void *obj) {
if (!obj) return;
ObjArray *oa = (ObjArray*)obj;
@@ -260,68 +310,75 @@ static inline void free_object(void *obj) {
}
static inline void set_var_object(const char *name, void *obj) {
- if (!name)
- error(0, "set_var_object called with NULL name");
-
- for (int j = 0; j < var_count; ++j) {
- if (!vars[j].name) continue;
-
- if (strcmp(vars[j].name, name) == 0) {
- if (vars[j].type == VAR_OBJECT)
- free_object(vars[j].obj);
- vars[j].type = VAR_OBJECT;
- vars[j].obj = obj;
- free(vars[j].str);
- vars[j].str = NULL;
- vars[j].value = 0;
+ if (!name) error(0, "set_var_object: NULL name");
+
+ unsigned h = hash_str(name);
+ unsigned idx = h & (VAR_TABLE_SIZE - 1);
+
+ for (;;) {
+ VarSlot *v = &var_table[idx];
+
+ if (!v->used) {
+ v->used = 1;
+ v->name = strdup(name);
+ v->type = VAR_OBJECT;
+ v->obj = obj;
+ v->str = NULL;
+ v->value = 0;
+ return;
+ }
+
+ if (strcmp(v->name, name) == 0) {
+ if (v->type == VAR_STRING) free(v->str);
+ v->type = VAR_OBJECT;
+ v->obj = obj;
return;
}
- }
- vars[var_count].name = strdup(name);
- vars[var_count].type = VAR_OBJECT;
- vars[var_count].obj = obj;
- vars[var_count].value = 0;
- vars[var_count].str = NULL;
- var_count++;
+ idx = (idx + 1) & (VAR_TABLE_SIZE - 1);
+ }
}
+
static inline void set_var(
const char *name,
VarType type,
double value,
const char *str
) {
- if (!name) {
- error(0, "set_var: NULL variable name");
- }
+ if (!name) error(0, "set_var: NULL name");
- for (int j = 0; j < var_count; ++j) {
- if (!vars[j].name) continue;
+ unsigned h = hash_str(name);
+ unsigned idx = h & (VAR_TABLE_SIZE - 1);
- if (strcmp(vars[j].name, name) == 0) {
- vars[j].type = type;
- if (type == VAR_STRING) {
- free(vars[j].str);
- vars[j].str = strdup(str ? str : "");
- } else {
- vars[j].value = value;
- free(vars[j].str);
- vars[j].str = NULL;
- }
+ for (;;) {
+ VarSlot *v = &var_table[idx];
+
+ if (!v->used) {
+ v->used = 1;
+ v->name = strdup(name);
+ v->type = type;
+ v->value = value;
+ v->str = (type == VAR_STRING) ? strdup(str ? str : "") : NULL;
+ v->obj = NULL;
+ return;
+ }
+
+ if (strcmp(v->name, name) == 0) {
+ if (v->type == VAR_STRING) free(v->str);
+ v->type = type;
+ v->value = value;
+ v->str = (type == VAR_STRING) ? strdup(str ? str : "") : NULL;
return;
}
- }
- vars[var_count].name = strdup(name);
- vars[var_count].type = type;
- vars[var_count].value = (type == VAR_NUMBER) ? value : 0;
- vars[var_count].str = (type == VAR_STRING) ? strdup(str ? str : "") : NULL;
- var_count++;
+ idx = (idx + 1) & (VAR_TABLE_SIZE - 1);
+ }
}
+
/* =========================
Forward declarations
========================= */
@@ -536,6 +593,11 @@ static inline void free_ast(ASTNode *node) {
case AST_IDENTIFIER:
free(node->string);
break;
+ case AST_TUPLE:
+ for (int i = 0; i < node->tuple.count; i++)
+ free_ast(node->tuple.items[i]);
+ free(node->tuple.items);
+ break;
case AST_BINARY_OP:
free(node->binop.op);
@@ -699,6 +761,11 @@ static void write_ast_node(FILE *f, const ASTNode *n) {
case AST_READ:
write_ast_node(f, n->read.expr);
break;
+ case AST_TUPLE:
+ w_u32(f, (unsigned int)n->tuple.count);
+ for (int i = 0; i < n->tuple.count; i++)
+ write_ast_node(f, n->tuple.items[i]);
+ break;
case AST_WRITE:
write_ast_node(f, n->write.path);
@@ -804,6 +871,15 @@ static ASTNode *read_ast_node(FILE *f) {
case AST_NUMBER:
n->number = r_double(f);
break;
+ case AST_TUPLE: {
+ unsigned int c = r_u32(f);
+ n->tuple.count = (int)c;
+ n->tuple.items =
+ (ASTNode**)calloc(c ? c : 1, sizeof(ASTNode*));
+ for (unsigned int i = 0; i < c; i++)
+ n->tuple.items[i] = read_ast_node(f);
+ break;
+ }
case AST_STRING:
case AST_IDENTIFIER:
@@ -934,6 +1010,16 @@ static inline ASTNode *read_ast_from_spc(const char *filename) {
/* =========================
Runtime eval/interpret
========================= */
+static inline void print_value(Value v) {
+ if (v.type == VAL_STRING) {
+ printf("%s\n", v.string ? v.string : "");
+ } else if (v.type == VAL_NUMBER) {
+ printf("%g\n", v.number);
+ } else {
+ printf(" |