shithub: lpa

Download patch

ref: da6308e5df8ed9cdf8d8f6cad73eef10f31ac4b0
parent: ee1ed56428b090dd694f50b49f4957c4d2e11bc2
author: Peter Mikkelsen <peter@pmikkelsen.com>
date: Mon Jul 22 16:24:11 EDT 2024

Do some work on functions

--- a/array.c
+++ b/array.c
@@ -151,6 +151,26 @@
 	return buf;
 }
 
+char *
+printfunc(Function *f) /* Doesn't really belong here.. */
+{
+	char buf[2048]; /* TODO: fixed size :) */
+	char *p = buf;
+
+	p += sprint(p, "∇");
+	if(f->ast->funcresult)
+		p += sprint(p, "%s←", f->ast->funcresult->name);
+	if(f->ast->funcleftarg)
+		p += sprint(p, "%s ", f->ast->funcleftarg->name);
+	p += sprint(p, "%s", f->ast->funcname->name);
+	if(f->ast->funcrightarg)
+		p += sprint(p, " %s", f->ast->funcrightarg->name);
+	for(uvlong i = 0; i < f->ast->funclocals->childcount; i++)
+		p += sprint(p, ";%s", f->ast->funclocals->children[i]->name);
+	sprint(p, "\n∇");
+	return buf;
+}
+
 Array *
 simplifyarray(Array *a)
 {
--- a/dat.h
+++ b/dat.h
@@ -13,6 +13,9 @@
 	DataAst,
 	DataByteCode,
 	DataValueStack,
+	DataCallStack,
+	DataFunction,
+	DataLocalList,
 
 	DataMax,
 };
@@ -172,6 +175,8 @@
 	AstLater, /* parse at runtime */
 };
 
+typedef struct ByteCode ByteCode;
+
 typedef struct Ast Ast;
 struct Ast
 {
@@ -206,7 +211,6 @@
 	NameclassFunc, /* Function value */
 };
 
-typedef struct ByteCode ByteCode;
 struct ByteCode
 {
 	uvlong count;
@@ -221,10 +225,13 @@
 	IStrand,
 	IMonadic,
 	IDyadic,
+	ICall,
 	IClear,
 	IParse,
 	IDone,
-	IJump,
+	IReturn,
+	IAssign,
+	ILocal,
 };
 
 typedef struct ValueStack ValueStack;
@@ -232,4 +239,45 @@
 {
 	uvlong count;
 	void **values;
+};
+
+typedef struct Local Local;
+struct Local
+{
+	uvlong id;
+	void *value;
+};
+
+typedef struct LocalList LocalList;
+struct LocalList
+{
+	uvlong count;
+	Local *list;
+};
+
+typedef struct CallFrame CallFrame;
+struct CallFrame
+{
+	/* Values stored when the frame is pushed */
+	ByteCode *code;
+	uvlong offset;
+
+	/* Old values of symbols before they were localised */
+	LocalList *locals;
+};
+
+typedef struct CallStack CallStack;
+struct CallStack
+{
+	uvlong count;
+	CallFrame *frames;
+};
+
+typedef struct Function Function;
+struct Function
+{
+	Ast *ast;
+	uvlong symbol;
+	ByteCode *code;
+	int prim;
 };
\ No newline at end of file
--- a/eval.c
+++ b/eval.c
@@ -39,6 +39,21 @@
 }
 
 static void
+emitlocal(ByteCode *c, Symtab *s, Ast *a, int assign)
+{
+	if(a == nil)
+		return;
+
+	uvlong id = sym(s, a->name);
+	emitbyte(c, ILocal);
+	emituvlong(c, id);
+	if(assign){
+		emitbyte(c, IAssign);
+		emituvlong(c, id);
+	}
+}
+
+static void
 codegensub(Session *s, Module *m, ByteCode *c, Ast *a)
 {
 	char *err;
@@ -53,6 +68,39 @@
 		}
 		emitbyte(c, IDone);
 		break;
+	case AstFunc:
+		/* Emit bytecode for the function body */
+		{
+			Function *fn = alloc(DataFunction);
+			fn->ast = a;
+			fn->symbol = sym(m->symtab, a->funcname->name);
+			fn->code = alloc(DataByteCode);
+			emitbyte(fn->code, IPushConst);
+			emitptr(fn->code, fn);
+			emitlocal(fn->code, m->symtab, fn->ast->funcname, 1);
+			emitlocal(fn->code, m->symtab, fn->ast->funcresult, 0);
+			emitlocal(fn->code, m->symtab, fn->ast->funcleftarg, 1);
+			emitlocal(fn->code, m->symtab, fn->ast->funcrightarg, 1);
+			for(i = 0; i < fn->ast->funclocals->childcount; i++)
+				emitlocal(fn->code, m->symtab, fn->ast->funclocals->children[i], 0);
+			for(i = 0; i < a->childcount; i++){
+				if(i != 0)
+					emitbyte(fn->code, IClear);
+				codegensub(s, m, fn->code, a->children[i]);
+			}
+			emitbyte(fn->code, IReturn);
+
+			emitbyte(c, IPushConst);
+			emitptr(c, fn);
+
+			/* push the value twice so defining a function yields a function value.. */
+			emitbyte(c, IPushConst);
+			emitptr(c, fn);
+
+			emitbyte(c, IAssign);
+			emituvlong(c, fn->symbol);
+		}
+		break;
 	case AstName:
 		emitbyte(c, ILookup);
 		emituvlong(c, sym(m->symtab, a->name));
@@ -71,13 +119,19 @@
 	case AstMonadic:
 		codegensub(s, m, c, a->right);
 		codegensub(s, m, c, a->func);
-		emitbyte(c, IMonadic);
+		if(a->func->tag == AstPrim)
+			emitbyte(c, IMonadic);
+		else
+			emitbyte(c, ICall);
 		break;
 	case AstDyadic:
 		codegensub(s, m, c, a->right);
 		codegensub(s, m, c, a->left);
 		codegensub(s, m, c, a->func);
-		emitbyte(c, IDyadic);
+		if(a->func->tag == AstPrim)
+			emitbyte(c, IDyadic);
+		else
+			emitbyte(c, ICall);
 		break;
 	case AstPrim:
 		emitbyte(c, IPushPrim);
@@ -107,7 +161,7 @@
 static void
 pushval(ValueStack *s, void *v)
 {
-	s->count += 1;
+	s->count++;
 	s->values = allocextra(s, s->count * sizeof(v));
 	s->values[s->count-1] = v;
 }
@@ -121,15 +175,57 @@
 	return s->values[s->count];
 }
 
+static void
+pushcall(CallStack *s, ByteCode *c, uvlong o)
+{
+	s->count++;
+	s->frames = allocextra(s, s->count * sizeof(CallFrame));
+	s->frames[s->count-1].code = c;
+	s->frames[s->count-1].offset = o;
+	s->frames[s->count-1].locals = alloc(DataLocalList);
+}
+
+static void
+popcall(CallStack *s, Symtab *t, ByteCode **c, uvlong *o)
+{
+	if(s->count == 0)
+		sysfatal("popcall on empty call stack");
+	s->count--; /* no realloc */
+	*c = s->frames[s->count].code;
+	*o = s->frames[s->count].offset;
+
+	LocalList *locals = s->frames[s->count].locals;
+	for(uvlong i = 0; i < locals->count; i++)
+		symset(t, locals->list[i].id, locals->list[i].value);
+}
+
+static void
+pushlocal(CallStack *c, Symtab *s, uvlong id)
+{
+	CallFrame f = c->frames[s->count-1];
+
+	f.locals->count++;
+	f.locals->list = allocextra(f.locals, sizeof(Local) * f.locals->count);
+	f.locals->list[f.locals->count-1].id = id;
+	f.locals->list[f.locals->count-1].value = symval(s, id);
+
+	symset(s, id, nil);
+}
+
 static void *
 evalbc(Session *s, Module *m, ByteCode *c)
 {
 	ValueStack *values;
+	CallStack *calls;
+
+	ByteCode *newcode;
 	uvlong o, v;
-	int prim = 0;
+	Function *func;
 	void *r;
 
 	values = alloc(DataValueStack);
+	calls = alloc(DataCallStack);
+
 	debugbc(c);
 
 	o = 0;
@@ -144,7 +240,11 @@
 			break;
 		case IPushPrim:
 			o += getuvlong(c->instrs+o, &v);
-			prim = v;
+			{
+				Function *f = alloc(DataFunction);
+				f->prim = v;
+				pushval(values, f);
+			}
 			break;
 		case ILookup:
 			o += getuvlong(c->instrs+o, &v);
@@ -165,11 +265,20 @@
 			appendlog(s, "NOTE: monadic call acts like ⊢\n");
 			break;
 		case IDyadic:
-			USED(prim);
-			appendlog(s, "NOTE: dyadic call acts like ⊣\n");
+			appendlog(s, "NOTE: dyadic call acts like ⊢\n");
 			popval(values);
 			break;
-		case IClear:
+		case ICall:
+			func = popval(values);
+			newcode = func->code;
+call:
+			pushcall(calls, c, o);
+			c = newcode;
+			o = 0;
+			print("CALLED:\n");
+			debugbc(c);
+			break;
+		case IClear: /* TODO: get rid of this instruction. It shouldn't be there, and it is wrong */
 			while(values->count > 0)
 				popval(values);
 			break;
@@ -186,15 +295,10 @@
 					appendlog(s, "\n");
 					return nil;
 				}else{
-					uvlong next = o;
-					uvlong start = c->count;
-					codegensub(s, m, c, a);
-					emitbyte(c, IJump);
-					emituvlong(c, next);
-					o = start; /* jump to new code */
-					/* TODO: this adds code every time the instruction is run */
-					print("updated bytecode:\n");
-					debugbc(c);
+					newcode = alloc(DataByteCode);
+					codegensub(s, m, newcode, a);
+					emitbyte(newcode, IReturn);
+					goto call;
 				}
 			}
 			break;
@@ -201,10 +305,19 @@
 		case IDone:
 			goto done;
 			break;
-		case IJump:
-			getuvlong(c->instrs+o, &v);
-			o = v;
+		case IReturn:
+			popcall(calls, m->symtab, &c, &o);
+			print("RETURNED TO (%ulld)\n", o);
+			debugbc(c);
 			break;
+		case IAssign:
+			o += getuvlong(c->instrs+o, &v);
+			symset(m->symtab, v, popval(values));
+			break;
+		case ILocal:
+			o += getuvlong(c->instrs+o, &v);
+			pushlocal(calls, m->symtab, v);
+			break;
 		default:
 			appendlog(s, "unknown instruction in evalbc\n");
 			return nil;
@@ -213,6 +326,8 @@
 
 done:
 	r = nil;
+	print("Final value stack size: %ulld\n", values->count);
+	print("Final call stack size: %ulld\n", calls->count);
 	if(values->count != 0)
 		r = popval(values);
 	return r;
--- a/fns.h
+++ b/fns.h
@@ -6,6 +6,7 @@
 void setshape(Array *, int, usize);
 Array *simplifyarray(Array *);
 char *printarray(Array *);
+char *printfunc(Function *);
 
 /* eval.c */
 void *eval(Session *s, Ast *);
--- a/fs.c
+++ b/fs.c
@@ -280,6 +280,11 @@
 		char *buf = requeststr(r);
 		void *v = parseval(session, buf, &err);
 		free(buf);
+		if(v && getalloctag(v) == DataFunction){
+			Function *f = v;
+			if(strcmp(symb->name, f->ast->funcname->name) != 0)
+				err = "Function name must match symbol name";
+		}
 		if(!err)
 			symset(symb->table, symb->id, v);
 	}
--- a/memory.c
+++ b/memory.c
@@ -36,6 +36,9 @@
 	[DataAst] = {.size = sizeof(Ast) },
 	[DataByteCode] = {.size = sizeof(ByteCode) },
 	[DataValueStack] = {.size = sizeof(ValueStack) },
+	[DataCallStack] = {.size = sizeof(CallStack) },
+	[DataFunction] = {.size = sizeof(Function) },
+	[DataLocalList] = {.size = sizeof(LocalList) },
 };
 
 void *
--- a/parse.c
+++ b/parse.c
@@ -136,6 +136,9 @@
 		case DataArray:
 			class = NameclassArray;
 			break;
+		case DataFunction:
+			class = NameclassFunc;
+			break;
 		/* more cases here in the future */
 		}
 	}else{
@@ -193,6 +196,7 @@
 			parseseps(t, 1);
 	}
 	match(t, TokDel);
+
 	return func;
 }
 
@@ -368,7 +372,6 @@
 static Ast *
 parsefunc(TokenList *t)
 {
-	/* TODO: parse primitives as well */
 	Ast *func;
 	if(peek(t) == TokName && peekclass(t) == NameclassFunc)
 		func = parsename(t);
--- a/util.c
+++ b/util.c
@@ -159,11 +159,14 @@
 			print("STRAND %ulld\n", v);
 			break;
 		case IMonadic:
-			print("MONADIC\n");
+			print("MONADIC PRIM\n");
 			break;
 		case IDyadic:
-			print("DYADIC\n");
+			print("DYADIC PRIM\n");
 			break;
+		case ICall:
+			print("CALL\n");
+			break;
 		case IClear:
 			print("CLEAR\n");
 			break;
@@ -174,13 +177,21 @@
 		case IDone:
 			print("DONE\n");
 			break;
-		case IJump:
+		case IReturn:
+			print("RETURN\n");
+			break;
+		case IAssign:
 			o += getuvlong(c->instrs+o, &v);
-			print("JUMP %ulld\n", v);
+			print("ASSIGN %ulld\n", v);
 			break;
+		case ILocal:
+			o += getuvlong(c->instrs+o, &v);
+			print("LOCAL %ulld\n", v);
+			break;
 		default:
 			print("???");
 			return;
 		}
 	}
+	print("\n");
 }
\ No newline at end of file
--- a/value.c
+++ b/value.c
@@ -18,6 +18,8 @@
 		switch(tag){
 		case DataArray:
 			return smprint("%s\n", printarray(v));
+		case DataFunction:
+			return smprint("%s\n", printfunc(v));
 		default:
 			return smprint("some value of type %d\n", tag);
 		}