summaryrefslogtreecommitdiff
path: root/run_old.c
blob: e4fa5400db8f62202e275a548ae83579aa77051b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "run.h"
#include "ast.h"
#include "ht.h"

#include <stdio.h>
#include <string.h>

// return pointer to nth subnode of AST_LIST node *l.
// doesn't check that l is a list, or that it has at least n elems. 
#define NTH(l,n) (&(l)->as.list.vals[(n)])

// n is max index
#define CK_LEN(s, l, n) do { if(l.len-1 != n) { \
	printf("%s fn requires exactly %d args (%ld provided)",\
	s, n, l.len-1); return 0; } } while(0);
static int func_plus(Env *s, AstVec l) {
	CK_LEN("+",l,2);
	return eval(s, l.vals[1]) + eval(s, l.vals[2]);
}
static int func_id(Env *s, AstVec l) {
	CK_LEN("id",l,1);
	return eval(s, l.vals[1]);
}
static int func_minus(Env *s, AstVec l) {
	CK_LEN("-",l,2);
	return eval(s, l.vals[1]) - eval(s, l.vals[2]);
}
static int func_mult(Env *s, AstVec l) {
	CK_LEN("*",l,2);
	return eval(s, l.vals[1]) * eval(s, l.vals[2]);
}
static int func_div(Env *s, AstVec l) {
	CK_LEN("/",l,2);
	return eval(s, l.vals[1]) / eval(s, l.vals[2]);
}
static int func_print(Env *s, AstVec l) {
	CK_LEN("print",l,1);
	int v = eval(s, l.vals[1]);
	printf("%d\n",v);
	return v;
}
static int func_set(Env *s, AstVec l) {
	CK_LEN("set", l, 2);
	if (l.vals[1].ty != AST_SYMBOL) {
		printf("can only assign to symbols");
		return 0;
	}
	int v = eval(s, l.vals[2]);
	printf("  %p set %s %d\n", (void*)s, l.vals[1].as.str, v);
	ht_put(s, l.vals[1].as.str, v);
	return v;
}
static int func_do(Env *s, AstVec l) {
	for (int i = 1; i < l.len; i++) {
		eval(s, l.vals[i]);
	}
	return 0;
}

typedef int (*builtin_func)(Env*, AstVec);
typedef struct {
	char *name;
	builtin_func func;
} BuiltinDesc;

BuiltinDesc builtins[] = {
	{ "+", func_plus },
	{ "-", func_minus },
	{ "*", func_mult },
	{ "/", func_div },
	{ "id", func_id },
	{ "print", func_print },
	{ "set", func_set },
	{ "do", func_do },

	{ NULL, NULL },
};

static int call_builtin(Env *s, char *name, AstVec arglist) {
	for (BuiltinDesc *bd = builtins; bd->name != NULL; bd++) {
		if (0 == strcmp(bd->name, name)) {
			return bd->func(s, arglist);
		}
	}
	printf("couldn't find builtin fn %s\n",name);
	return 0;
}

int eval(Env *s, AstNode a) {
	switch (a.ty) {
	case AST_SYMBOL:;
		int v;
		if (ht_get(s, a.as.str, &v)) {
			return v;
		} else {
			printf("unset variable %s\n",a.as.str);
			return 0;
		}
		break;
	case AST_NUM:
		return a.as.num;
		break;
	case AST_LIST:;
		AstVec l = a.as.list;
		if (l.len < 1) {
			printf("can't execute empty list\n");
			return 0;
		}
		AstNode *first = &l.vals[0];
		if (first->ty != AST_SYMBOL) {
			printf("first element of list must be symbol\n");
			return 0;
		}
		return call_builtin(s, first->as.str, l);
		break;
	default:
		printf("???\n");
		return 0;
	}
}