summaryrefslogtreecommitdiff
path: root/dis.c
blob: 530ad49de36e4d1a6f30542513f79646918384d6 (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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include "dis.h"

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

static void print_const(Chunk *ch, uint8_t ix) {
	Val k = ch->consts.d[ix];
	printf("%-4s : ", typename_str(k));
	println_val(k);
}


char *op_name(Op op) {
	switch (op) {
	case OP_RET:		return "ret"; break;
	case OP_LOADK:		return "loadk"; break;
	case OP_ADD:		return "add"; break;
	case OP_SUB:		return "sub"; break;
	case OP_MUL:		return "mul"; break;
	case OP_DIV:		return "div"; break;
	case OP_MOD:		return "mod"; break;
	case OP_EQU:		return "equ"; break;
	case OP_CMP:		return "cmp"; break;
	case OP_HALT:		return "halt"; break;
	case OP_DROP:		return "drop"; break;
	case OP_GETGLOBAL:	return "getglobal"; break;
	case OP_SETGLOBAL:	return "setglobal"; break;
	case OP_GETLOCAL:	return "getlocal"; break;
	case OP_SETLOCAL:	return "setlocal"; break;
	case OP_TRUE:		return "true"; break;
	case OP_FALSE:		return "false"; break;
	case OP_NIL:		return "nil"; break;
	case OP_0BRANCH:	return "0branch"; break;
	case OP_SKIP:		return "skip"; break;
	case OP_REDO:		return "redo"; break;
	case OP_CALL:		return "call"; break;
	case OP_TAILCALL:	return "tailcall"; break;
	case OP_ENDSCOPE:	return "endscope"; break;
	case OP_ARRNEW:		return "arrnew"; break;
	case OP_ARRAPPEND:	return "arrappend"; break;
	case OP_ARRLEN:		return "arrlen"; break;
	case OP_SETIDX:		return "setidx"; break;
	default: return "???"; break;
	}
}

static void disasm_chunk_h(Chunk *ch, int depth);
void disasm_chunk(Chunk *ch) {
	disasm_chunk_h(ch, 0);
}

static size_t disasm_instr_h(Chunk *ch, size_t ip, int depth);
size_t disasm_instr(Chunk *ch, size_t ip) {
	return disasm_instr_h(ch, ip, 0);
}


static size_t disasm_instr_h(Chunk *ch, size_t ip, int depth) {
	size_t orig_ip = ip;
	uint8_t instr = ch->bc.d[ip];
	printf("%*s%04zd\t%3d ",depth,"",ip,instr);
	ip ++;
	switch (instr) {
	case OP_LOADK: {
		uint8_t ix = ch->bc.d[ip++];
		printf("loadk #%d\t; ",ix);
		print_const(ch, ix);
		break;
	}
	case OP_GETGLOBAL: {
		uint8_t ix = ch->bc.d[ip++];
		printf("getglobal #%d\t; ",ix);
		print_const(ch, ix);
		break;
	}
	case OP_GETLOCAL: {
		uint8_t ix = ch->bc.d[ip++];
		printf("getlocal #%d\n",ix);
		break;
	}
	case OP_SETLOCAL: {
		uint8_t ix = ch->bc.d[ip++];
		printf("setlocal #%d\n",ix);
		break;
	}
	case OP_SETGLOBAL: {
		uint8_t ix = ch->bc.d[ip++];
		printf("setglobal #%d\t; ",ix);
		print_const(ch, ix);
		break;
	}
	case OP_CALL: {
		uint8_t nargs = ch->bc.d[ip++];
		printf("call #%hhu\n",nargs);
		break;
	}
	case OP_TAILCALL: {
		uint8_t nargs = ch->bc.d[ip++];
		printf("\033[31mtailcall\033[0m #%hhu\n",nargs);
		break;
	}
	case OP_ENDSCOPE: {
		uint8_t nlocals = ch->bc.d[ip++];
		printf("endscope #%hhu\n",nlocals);
		break;
	}
	#define RSHORT() (uint16_t)( ch->bc.d[ip-2] | ch->bc.d[ip-1] << 8 )
	case OP_SKIP: {
		ip += 2;
		uint16_t offset = RSHORT();
		printf("skip +%5hu\t; -> %04zd\n", offset, ip + offset);
		break;
	}
	case OP_0BRANCH: {
		ip += 2;
		uint16_t offset = RSHORT();
		printf("0branch +%5hu\t; -> %04zd\n", offset, ip + offset);
		break;
	}
	case OP_REDO: {
		ip += 2;
		uint16_t offset = RSHORT();
		printf("redo -%5hu\t; -> %04zd\n", offset, ip - offset);
		break;
	}
	#undef RSHORT

	#define SIMPLE_INSTR(opcode, str) \
		case opcode: puts(str); break;
	SIMPLE_INSTR(OP_RET, "ret")
	SIMPLE_INSTR(OP_DROP, "drop")
	SIMPLE_INSTR(OP_ADD, "add")
	SIMPLE_INSTR(OP_SUB, "sub")
	SIMPLE_INSTR(OP_MUL, "mul")
	SIMPLE_INSTR(OP_DIV, "div")
	SIMPLE_INSTR(OP_MOD, "mod")
	SIMPLE_INSTR(OP_NIL, "nil")
	SIMPLE_INSTR(OP_TRUE, "true")
	SIMPLE_INSTR(OP_FALSE, "false")
	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")
	SIMPLE_INSTR(OP_ARRLEN, "arrlen")
	#undef SIMPLE_INSTR

	default:
		printf("unknown opcode %d\n", instr);

	}

	return ip - orig_ip;

}

static void disasm_chunk_h(Chunk *ch, int depth) {
	#define P(msg) printf("%*s%s\n",depth,"",msg);
	P("constants:");
	for (uint8_t cix = 0; cix < ch->consts.len; cix++) {
		printf("%*s%hd\t",depth,"",cix);
		print_const(ch, cix);
	}

	P("bytecode:");
	#undef P
	for (size_t ip = 0; ip < ch->bc.len; ) {
		ip += disasm_instr_h(ch, ip, depth);
	}
	printf("\n");

	for (uint8_t cix = 0; cix < ch->consts.len; cix++) {
		Val c = ch->consts.d[cix];
		if (IS_FUNC(c)) {
			printf("%*sconst %d is function:\n",depth,"", cix);
			disasm_chunk_h(&AS_FUNC(c)->ch,depth+4);
		}
	}


}