Skip to content

Commit a1afcc7

Browse files
committed
feat: Establish the foundational compiler and runtime architecture for ProXPL, including AST, parsing, bytecode generation, and VM.
1 parent d19549e commit a1afcc7

12 files changed

Lines changed: 718 additions & 95 deletions

File tree

include/ast.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ typedef enum {
7373
STMT_BREAK,
7474
STMT_CONTINUE,
7575
STMT_SWITCH,
76-
STMT_TRY_CATCH
76+
STMT_TRY_CATCH,
77+
STMT_PRINT
7778
} StmtType;
7879

7980
// Dynamic array for expressions
@@ -294,6 +295,10 @@ typedef struct {
294295
StmtList *default_case; // Can be NULL
295296
} SwitchStmt;
296297

298+
typedef struct {
299+
Expr *expression;
300+
} PrintStmt;
301+
297302
typedef struct {
298303
StmtList *try_block;
299304
char *catch_var;
@@ -321,6 +326,7 @@ struct Stmt {
321326
ContinueStmt continue_stmt;
322327
SwitchStmt switch_stmt;
323328
TryCatchStmt try_catch;
329+
PrintStmt print;
324330
} as;
325331
};
326332

@@ -371,6 +377,7 @@ Stmt *createSwitchStmt(Expr *value, SwitchCaseList *cases, StmtList *def,
371377
Stmt *createTryCatchStmt(StmtList *try_blk, const char *catch_var,
372378
StmtList *catch_blk, StmtList *finally_blk, int line,
373379
int column);
380+
Stmt *createPrintStmt(Expr *expression, int line, int column);
374381

375382
// List management functions
376383
ExprList *createExprList();

include/chunk.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,42 @@
1313
// OpCodes
1414
typedef enum {
1515
OP_CONSTANT,
16+
OP_NIL,
1617
OP_TRUE,
1718
OP_FALSE,
18-
OP_NULL,
1919
OP_POP,
20+
OP_GET_LOCAL,
21+
OP_SET_LOCAL,
22+
OP_GET_GLOBAL,
23+
OP_DEFINE_GLOBAL,
24+
OP_SET_GLOBAL,
25+
OP_GET_UPVALUE,
26+
OP_SET_UPVALUE,
27+
OP_GET_PROPERTY,
28+
OP_SET_PROPERTY,
29+
OP_GET_SUPER,
30+
OP_EQUAL,
31+
OP_GREATER,
32+
OP_LESS,
2033
OP_ADD,
2134
OP_SUBTRACT,
2235
OP_MULTIPLY,
2336
OP_DIVIDE,
2437
OP_NOT,
2538
OP_NEGATE,
2639
OP_PRINT,
40+
OP_JUMP,
41+
OP_JUMP_IF_FALSE,
42+
OP_LOOP,
43+
OP_CALL,
44+
OP_INVOKE,
45+
OP_SUPER_INVOKE,
46+
OP_CLOSURE,
47+
OP_CLOSE_UPVALUE,
2748
OP_RETURN,
49+
OP_CLASS,
50+
OP_INHERIT,
51+
OP_METHOD
2852
} OpCode;
2953

3054
// Chunk: Sequence of bytecode

include/compiler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,7 @@ typedef struct {
3737

3838
bool compile(const char *source, Chunk *chunk);
3939

40+
#include "ast.h"
41+
void generateBytecode(StmtList* statements, Chunk* chunk);
42+
4043
#endif

include/table.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef PROX_TABLE_H
2+
#define PROX_TABLE_H
3+
4+
#include "common.h"
5+
#include "value.h"
6+
7+
typedef struct {
8+
ObjString *key;
9+
Value value;
10+
} Entry;
11+
12+
typedef struct {
13+
int count;
14+
int capacity;
15+
Entry *entries;
16+
} Table;
17+
18+
void initTable(Table *table);
19+
void freeTable(Table *table);
20+
bool tableGet(Table *table, ObjString *key, Value *value);
21+
bool tableSet(Table *table, ObjString *key, Value value);
22+
bool tableDelete(Table *table, ObjString *key);
23+
void tableAddAll(Table *from, Table *to);
24+
ObjString *tableFindString(Table *table, const char *chars, int length,
25+
uint32_t hash);
26+
27+
#endif

include/vm.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
#ifndef PROX_VM_H
88
#define PROX_VM_H
99

10-
#include "chunk.h"
11-
#include "value.h"
10+
#include "table.h"
1211

1312
#define STACK_MAX 256
1413

@@ -17,8 +16,13 @@ typedef struct {
1716
u8 *ip; // Instruction Pointer
1817
Value stack[STACK_MAX];
1918
Value *stackTop;
19+
Table globals;
20+
Table strings;
21+
struct Obj *objects;
2022
} VM;
2123

24+
extern VM vm;
25+
2226
typedef enum {
2327
INTERPRET_OK,
2428
INTERPRET_COMPILE_ERROR,

src/compiler/bytecode_gen.c

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
#include "../../include/ast.h"
6+
#include "../../include/chunk.h"
7+
#include "../../include/common.h"
8+
#include "../../include/value.h"
9+
#include "../../include/object.h"
10+
11+
typedef struct {
12+
Chunk* chunk;
13+
// Local scope management (simplified for now, will need full symbol table later)
14+
// For now, we assume global scope if not handled.
15+
} BytecodeGen;
16+
17+
static void emitByte(BytecodeGen* gen, uint8_t byte, int line) {
18+
writeChunk(gen->chunk, byte, line);
19+
}
20+
21+
static void emitBytes(BytecodeGen* gen, uint8_t byte1, uint8_t byte2, int line) {
22+
emitByte(gen, byte1, line);
23+
emitByte(gen, byte2, line);
24+
}
25+
26+
static void emitConstant(BytecodeGen* gen, Value value, int line) {
27+
int constant = addConstant(gen->chunk, value);
28+
if (constant > 255) {
29+
// Handle long constants if needed
30+
fprintf(stderr, "Too many constants in one chunk\n");
31+
return;
32+
}
33+
emitBytes(gen, OP_CONSTANT, (uint8_t)constant, line);
34+
}
35+
36+
static int emitJump(BytecodeGen *gen, uint8_t instruction, int line) {
37+
emitByte(gen, instruction, line);
38+
emitByte(gen, 0xff, line);
39+
emitByte(gen, 0xff, line);
40+
return gen->chunk->count - 2;
41+
}
42+
43+
static void patchJump(BytecodeGen *gen, int offset) {
44+
// -2 to adjust for the bytecode for the jump offset itself.
45+
int jump = gen->chunk->count - offset - 2;
46+
47+
if (jump > UINT16_MAX) {
48+
fprintf(stderr, "Too much code to jump over.\n");
49+
}
50+
51+
gen->chunk->code[offset] = (jump >> 8) & 0xff;
52+
gen->chunk->code[offset + 1] = jump & 0xff;
53+
}
54+
55+
static void emitLoop(BytecodeGen *gen, int loopStart, int line) {
56+
emitByte(gen, OP_LOOP, line);
57+
58+
int offset = gen->chunk->count - loopStart + 2;
59+
if (offset > UINT16_MAX) fprintf(stderr, "Loop body too large.\n");
60+
61+
emitByte(gen, (offset >> 8) & 0xff, line);
62+
emitByte(gen, offset & 0xff, line);
63+
}
64+
65+
// Forward declarations for recursive traversal
66+
static void genExpr(BytecodeGen* gen, Expr* expr);
67+
static void genStmt(BytecodeGen* gen, Stmt* stmt);
68+
69+
static void genExpr(BytecodeGen* gen, Expr* expr) {
70+
if (expr == NULL) return;
71+
72+
switch (expr->type) {
73+
case EXPR_LITERAL:
74+
if (IS_NUMBER(expr->as.literal.value)) {
75+
emitConstant(gen, expr->as.literal.value, expr->line);
76+
} else if (IS_BOOL(expr->as.literal.value)) {
77+
emitByte(gen, AS_BOOL(expr->as.literal.value) ? OP_TRUE : OP_FALSE, expr->line);
78+
} else if (IS_NULL(expr->as.literal.value)) {
79+
emitByte(gen, OP_NIL, expr->line);
80+
}
81+
break;
82+
83+
case EXPR_BINARY:
84+
genExpr(gen, expr->as.binary.left);
85+
genExpr(gen, expr->as.binary.right);
86+
87+
if (strcmp(expr->as.binary.operator, "+") == 0) emitByte(gen, OP_ADD, expr->line);
88+
else if (strcmp(expr->as.binary.operator, "-") == 0) emitByte(gen, OP_SUBTRACT, expr->line);
89+
else if (strcmp(expr->as.binary.operator, "*") == 0) emitByte(gen, OP_MULTIPLY, expr->line);
90+
else if (strcmp(expr->as.binary.operator, "/") == 0) emitByte(gen, OP_DIVIDE, expr->line);
91+
else if (strcmp(expr->as.binary.operator, "==") == 0) emitByte(gen, OP_EQUAL, expr->line);
92+
else if (strcmp(expr->as.binary.operator, "!=") == 0) {
93+
emitBytes(gen, OP_EQUAL, OP_NOT, expr->line);
94+
}
95+
else if (strcmp(expr->as.binary.operator, ">") == 0) emitByte(gen, OP_GREATER, expr->line);
96+
else if (strcmp(expr->as.binary.operator, "<") == 0) emitByte(gen, OP_LESS, expr->line);
97+
else if (strcmp(expr->as.binary.operator, ">=") == 0) {
98+
emitBytes(gen, OP_LESS, OP_NOT, expr->line);
99+
}
100+
else if (strcmp(expr->as.binary.operator, "<=") == 0) {
101+
emitBytes(gen, OP_GREATER, OP_NOT, expr->line);
102+
}
103+
break;
104+
105+
case EXPR_UNARY:
106+
genExpr(gen, expr->as.unary.right);
107+
if (strcmp(expr->as.unary.operator, "!") == 0) emitByte(gen, OP_NOT, expr->line);
108+
else if (strcmp(expr->as.unary.operator, "-") == 0) emitByte(gen, OP_NEGATE, expr->line);
109+
break;
110+
111+
case EXPR_GROUPING:
112+
genExpr(gen, expr->as.grouping.expression);
113+
break;
114+
115+
case EXPR_VARIABLE: {
116+
// Placeholder: Assume global for now
117+
// In a real implementation, we'd lookup in scope and emit OP_GET_LOCAL if found
118+
// For now, we'll need to store the variable name as a constant
119+
Value nameVal = OBJ_VAL(copyString(expr->as.variable.name, strlen(expr->as.variable.name)));
120+
int nameConst = addConstant(gen->chunk, nameVal);
121+
emitBytes(gen, OP_GET_GLOBAL, (uint8_t)nameConst, expr->line);
122+
break;
123+
}
124+
125+
case EXPR_ASSIGN: {
126+
genExpr(gen, expr->as.assign.value);
127+
Value nameVal = OBJ_VAL(copyString(expr->as.assign.name, strlen(expr->as.assign.name)));
128+
int nameConst = addConstant(gen->chunk, nameVal);
129+
emitBytes(gen, OP_SET_GLOBAL, (uint8_t)nameConst, expr->line);
130+
break;
131+
}
132+
133+
case EXPR_LOGICAL: {
134+
if (strcmp(expr->as.logical.operator, "&&") == 0) {
135+
genExpr(gen, expr->as.logical.left);
136+
int endJump = emitJump(gen, OP_JUMP_IF_FALSE, expr->line);
137+
emitByte(gen, OP_POP, expr->line);
138+
genExpr(gen, expr->as.logical.right);
139+
patchJump(gen, endJump);
140+
} else { // ||
141+
genExpr(gen, expr->as.logical.left);
142+
int elseJump = emitJump(gen, OP_JUMP_IF_FALSE, expr->line);
143+
int endJump = emitJump(gen, OP_JUMP, expr->line);
144+
patchJump(gen, elseJump);
145+
emitByte(gen, OP_POP, expr->line);
146+
genExpr(gen, expr->as.logical.right);
147+
patchJump(gen, endJump);
148+
}
149+
break;
150+
}
151+
152+
default:
153+
fprintf(stderr, "Unimplemented expression type in BytecodeGen: %d\n", expr->type);
154+
break;
155+
}
156+
}
157+
158+
static void genStmt(BytecodeGen* gen, Stmt* stmt) {
159+
if (stmt == NULL) return;
160+
161+
switch (stmt->type) {
162+
case STMT_EXPRESSION:
163+
genExpr(gen, stmt->as.expression.expression);
164+
emitByte(gen, OP_POP, stmt->line);
165+
break;
166+
167+
case STMT_PRINT:
168+
genExpr(gen, stmt->as.print.expression);
169+
emitByte(gen, OP_PRINT, stmt->line);
170+
break;
171+
172+
case STMT_RETURN:
173+
if (stmt->as.return_stmt.value != NULL) {
174+
genExpr(gen, stmt->as.return_stmt.value);
175+
} else {
176+
emitByte(gen, OP_NIL, stmt->line);
177+
}
178+
emitByte(gen, OP_RETURN, stmt->line);
179+
break;
180+
181+
case STMT_BLOCK:
182+
for (int i = 0; i < stmt->as.block.statements->count; i++) {
183+
genStmt(gen, stmt->as.block.statements->items[i]);
184+
}
185+
break;
186+
187+
case STMT_IF: {
188+
genExpr(gen, stmt->as.if_stmt.condition);
189+
int thenJump = emitJump(gen, OP_JUMP_IF_FALSE, stmt->line);
190+
emitByte(gen, OP_POP, stmt->line);
191+
genStmt(gen, stmt->as.if_stmt.then_branch);
192+
193+
int elseJump = emitJump(gen, OP_JUMP, stmt->line);
194+
patchJump(gen, thenJump);
195+
emitByte(gen, OP_POP, stmt->line);
196+
197+
if (stmt->as.if_stmt.else_branch != NULL) {
198+
genStmt(gen, stmt->as.if_stmt.else_branch);
199+
}
200+
patchJump(gen, elseJump);
201+
break;
202+
}
203+
204+
case STMT_WHILE: {
205+
int loopStart = gen->chunk->count;
206+
genExpr(gen, stmt->as.while_stmt.condition);
207+
208+
int exitJump = emitJump(gen, OP_JUMP_IF_FALSE, stmt->line);
209+
emitByte(gen, OP_POP, stmt->line);
210+
genStmt(gen, stmt->as.while_stmt.body);
211+
emitLoop(gen, loopStart, stmt->line);
212+
213+
patchJump(gen, exitJump);
214+
emitByte(gen, OP_POP, stmt->line);
215+
break;
216+
}
217+
218+
case STMT_VAR_DECL: {
219+
if (stmt->as.var_decl.initializer != NULL) {
220+
genExpr(gen, stmt->as.var_decl.initializer);
221+
} else {
222+
emitByte(gen, OP_NIL, stmt->line);
223+
}
224+
Value nameVal = OBJ_VAL(copyString(stmt->as.var_decl.name, strlen(stmt->as.var_decl.name)));
225+
int nameConst = addConstant(gen->chunk, nameVal);
226+
emitBytes(gen, OP_DEFINE_GLOBAL, (uint8_t)nameConst, stmt->line);
227+
break;
228+
}
229+
230+
default:
231+
fprintf(stderr, "Unimplemented statement type in BytecodeGen: %d\n", stmt->type);
232+
break;
233+
}
234+
}
235+
236+
void generateBytecode(StmtList* statements, Chunk* chunk) {
237+
BytecodeGen gen;
238+
gen.chunk = chunk;
239+
240+
for (int i = 0; i < statements->count; i++) {
241+
genStmt(&gen, statements->items[i]);
242+
}
243+
}

0 commit comments

Comments
 (0)