From a559125a2d7af771784614b7a2092cc7fb707345 Mon Sep 17 00:00:00 2001
From: ubq323 <ubq323@ubq323.website>
Date: Wed, 26 Jun 2024 22:45:16 +0100
Subject: array literals

---
 ast.c          | 18 ++++++++++++++----
 ast.h          |  2 ++
 com.c          | 12 ++++++++++++
 dis.c          |  2 ++
 g.peg          |  6 ++++++
 tests/arr2.bth |  1 +
 tests/arr2.out |  1 +
 tests/arr3.bth |  1 +
 tests/arr3.out |  1 +
 tests/arr4.bth |  4 ++++
 tests/arr4.out |  1 +
 tests/arr5.bth |  3 +++
 tests/arr5.out |  1 +
 todo           |  5 ++++-
 vm.c           | 15 +++++++++++++++
 vm.h           |  3 +++
 16 files changed, 71 insertions(+), 5 deletions(-)
 create mode 100644 tests/arr2.bth
 create mode 100644 tests/arr2.out
 create mode 100644 tests/arr3.bth
 create mode 100644 tests/arr3.out
 create mode 100644 tests/arr4.bth
 create mode 100644 tests/arr4.out
 create mode 100644 tests/arr5.bth
 create mode 100644 tests/arr5.out

diff --git a/ast.c b/ast.c
index b6fcbcf..4fbd471 100644
--- a/ast.c
+++ b/ast.c
@@ -27,7 +27,7 @@ void astvec_append(AstVec *v, AstNode val) {
 
 void astnode_append(AstNode *l, AstNode val) {
 	// printf("   astnode_append: %d\n",l->ty);
-	assert(l->ty == AST_LIST);
+	assert(l->ty == AST_LIST || l->ty == AST_ARR);
 	astvec_append(&l->as.list, val);
 }
 
@@ -48,6 +48,14 @@ AstNode astnode_new_list() {
 		}
 	};
 }
+AstNode astnode_new_arr() {
+	return (AstNode){
+		.ty = AST_ARR,
+		.as = {
+			.list = astvec_new()
+		}
+	};
+}
 
 AstNode astnode_new_ident(const char *s) {
 	return (AstNode){
@@ -74,7 +82,8 @@ void astnode_free(AstNode *a) {
 	case AST_STRING:
 		free(a->as.str);
 		break;
-	case AST_LIST:;
+	case AST_LIST:
+	case AST_ARR:;
 		AstVec *v = &a->as.list;
 		for (int i = 0; i < v->len; i++) {
 			astnode_free(&v->vals[i]);
@@ -92,7 +101,8 @@ void astnode_disp(AstNode *a) {
 	case AST_NUM:
 		printf("%s:%d ",ast_ty_to_str(a->ty),a->as.num);
 		break;
-	case AST_LIST:;
+	case AST_LIST:
+	case AST_ARR:;
 		AstVec *v = &a->as.list;
 		printf("%s:(",ast_ty_to_str(a->ty));
 		for (int i = 0; i < v->len; i++) {
@@ -109,7 +119,7 @@ void astnode_disp(AstNode *a) {
 }
 
 const char* ty_names[] = {
-	"list", "num", "ident", "string"
+	"list", "num", "ident", "string", "arr",
 };
 const char *ast_ty_to_str(AstTy ty) {
 	return ty_names[ty];
diff --git a/ast.h b/ast.h
index ead9cc6..6896c2b 100644
--- a/ast.h
+++ b/ast.h
@@ -9,6 +9,7 @@ typedef enum {
 	AST_NUM,
 	AST_IDENT,
 	AST_STRING,
+	AST_ARR,
 } AstTy;
 
 struct _astnode;
@@ -36,6 +37,7 @@ void astnode_append(AstNode *l, AstNode val);
 
 AstNode astnode_new_num(int n);
 AstNode astnode_new_list();
+AstNode astnode_new_arr();
 AstNode astnode_new_ident(const char *s);
 AstNode astnode_new_string(const char *s);
 
diff --git a/com.c b/com.c
index 0ae79f6..695802a 100644
--- a/com.c
+++ b/com.c
@@ -38,6 +38,7 @@ static int stack_effect_of(Op opcode) {
 	case OP_NIL:
 	case OP_TRUE:
 	case OP_FALSE:
+	case OP_ARRNEW:
 		return 1;
 	case OP_SKIP:
 	case OP_REDO:
@@ -55,6 +56,7 @@ static int stack_effect_of(Op opcode) {
 	case OP_CMP:
 	case OP_EQU:
 	case OP_MOD:
+	case OP_ARRAPPEND:
 		return -1;
 
 	// these ones depend on their argument. handle them specifically
@@ -402,6 +404,16 @@ static void compile_node(Compiler *C, AstNode a) {
 		compile_byte(C, compile_constant(C, VAL_OBJ(o)));
 		break;
 	}
+	case AST_ARR: {
+		compile_opcode(C, OP_ARRNEW);
+		AstVec v = a.as.list;
+		for (int i = 0; i < v.len; i++) {
+			compile_node(C, v.vals[i]);
+			compile_opcode(C, OP_ARRAPPEND);
+		}
+		break;
+	}
+
 	case AST_LIST: {
 		AstVec l = a.as.list;
 
diff --git a/dis.c b/dis.c
index 9220b75..2939384 100644
--- a/dis.c
+++ b/dis.c
@@ -101,6 +101,8 @@ static size_t disasm_instr_h(Chunk *ch, size_t ip, int depth) {
 	SIMPLE_INSTR(OP_CMP, "cmp")
 	SIMPLE_INSTR(OP_EQU, "equ")
 	SIMPLE_INSTR(OP_HALT, "halt")
+	SIMPLE_INSTR(OP_ARRNEW, "arrnew")
+	SIMPLE_INSTR(OP_ARRAPPEND, "arrappend")
 	#undef SIMPLE_INSTR
 
 	default:
diff --git a/g.peg b/g.peg
index dccf361..056ca7a 100644
--- a/g.peg
+++ b/g.peg
@@ -29,12 +29,18 @@ expr <-
 	/ n:number { $$ = n; }
 	/ i:ident { $$ = i; }
 	/ t:string { $$ = t; }
+	/ a:array { $$ = a; }
 
 list <- { $$ = astnode_new_list(); }
 	'(' 
 	( e:expr { astnode_append(&$$, e); }
 	 )*
 	')' _ 
+array <- { $$ = astnode_new_arr(); }
+	'['
+	( e:expr { astnode_append(&$$, e); }
+	 )* 
+	 ']' _
 
 number <- < [0-9]+ > (! ident_char) _  { $$ = astnode_new_num(atoi($1)); }
 ident <- < ident_char+ > _ { $$ = astnode_new_ident($1); }
diff --git a/tests/arr2.bth b/tests/arr2.bth
new file mode 100644
index 0000000..a405bde
--- /dev/null
+++ b/tests/arr2.bth
@@ -0,0 +1 @@
+(say (append [1 2 3 4] 99))
diff --git a/tests/arr2.out b/tests/arr2.out
new file mode 100644
index 0000000..42a9264
--- /dev/null
+++ b/tests/arr2.out
@@ -0,0 +1 @@
+[ 1 2 3 4 99 ]
diff --git a/tests/arr3.bth b/tests/arr3.bth
new file mode 100644
index 0000000..c2bce88
--- /dev/null
+++ b/tests/arr3.bth
@@ -0,0 +1 @@
+(say (append [1 2 (+ 1 2) (let (x 2) (* x x))] (+ 2 3)))
diff --git a/tests/arr3.out b/tests/arr3.out
new file mode 100644
index 0000000..f5d7903
--- /dev/null
+++ b/tests/arr3.out
@@ -0,0 +1 @@
+[ 1 2 3 4 5 ]
diff --git a/tests/arr4.bth b/tests/arr4.bth
new file mode 100644
index 0000000..2521e63
--- /dev/null
+++ b/tests/arr4.bth
@@ -0,0 +1,4 @@
+(say
+	(let (A (append [1 2 3 (let (x 2) (* x x)) 5] 6))
+		(let (B (append A 7)) (append B 8))
+		(append (append A 9) 10)))
diff --git a/tests/arr4.out b/tests/arr4.out
new file mode 100644
index 0000000..c508125
--- /dev/null
+++ b/tests/arr4.out
@@ -0,0 +1 @@
+[ 1 2 3 4 5 6 7 8 9 10 ]
diff --git a/tests/arr5.bth b/tests/arr5.bth
new file mode 100644
index 0000000..79d5a7d
--- /dev/null
+++ b/tests/arr5.bth
@@ -0,0 +1,3 @@
+(set A [1 2 3])
+(let (B A) (append B 10))
+(say A)
diff --git a/tests/arr5.out b/tests/arr5.out
new file mode 100644
index 0000000..7704f22
--- /dev/null
+++ b/tests/arr5.out
@@ -0,0 +1 @@
+[ 1 2 3 10 ]
diff --git a/todo b/todo
index f724c3a..d9d819e 100644
--- a/todo
+++ b/todo
@@ -1,5 +1,8 @@
 closures, upvalues
-lists, hashes, other useful types
+arrays, hashes, other useful types
+good loops
+declarations inline
+pattern matching
 garbage collector
 macros
 
diff --git a/vm.c b/vm.c
index 679a6a5..023d2c3 100644
--- a/vm.c
+++ b/vm.c
@@ -233,8 +233,23 @@ int runvm(State *S) {
 			goto done;
 			break;
 
+		case OP_ARRNEW: {
+			ObjArr *a = objarr_new(S);
+			PUSH(VAL_OBJ(a));
+			break;
+		}
+		case OP_ARRAPPEND: { 
+			Val v = POP();
+			Val a = PEEK();
+			CHECK(IS_ARR(a), "can only append to array");
+			ObjArr *arr = AS_ARR(a);
+			objarr_append(S, arr, v);
+			break;
 		}
 
+		}
+
+
 	}
 	done:;
 	return status;
diff --git a/vm.h b/vm.h
index 4af6300..8479623 100644
--- a/vm.h
+++ b/vm.h
@@ -62,6 +62,9 @@ typedef enum {
 
 	OP_CALL,
 	OP_ENDSCOPE,
+
+	OP_ARRNEW,
+	OP_ARRAPPEND,
 } Op;
 
 int runvm(State *S);
-- 
cgit v1.2.3