commit 177e774dc5134b62d28f960334abca595023af6d
parent 78ab1d361c89debc36336835569daac1b6bbd642
Author: citbl <citbl@citbl.org>
Date: Mon, 13 Oct 2025 20:43:09 +1000
handle different variables
Diffstat:
9 files changed, 100 insertions(+), 75 deletions(-)
diff --git a/.zed/debug.json b/.zed/debug.json
@@ -7,11 +7,11 @@
"label": "Debug native binary",
"build": {
"command": "make",
- "args": ["check"],
+ "args": ["debug"],
"cwd": "$ZED_WORKTREE_ROOT"
},
"program": "$ZED_WORKTREE_ROOT/oxc",
- "args": ["$ZED_WORKTREE_ROOT/ex2.ox"],
+ "args": ["$ZED_WORKTREE_ROOT/ex9.ox"],
"request": "launch",
"adapter": "CodeLLDB"
}
diff --git a/ex9.ox b/ex9.ox
@@ -1,13 +1,13 @@
int jack = 111;
-// void test() {
-// float alice = 222;
-// }
+void test() {
+ float alice = 222;
+}
void main() {
int peter = 333;
}
-uint jill = 444;
+int jill = 444;
-float jane = 123.45;
+float jane = 125.34;
diff --git a/makefile b/makefile
@@ -21,6 +21,9 @@ SRC = */*/*.c */*.c
BIN = oxc
STD = -std=c23
+debug:
+ cc ${STD} -g -Wall -Wextra -o ${BIN} ${SRC} ${LIB}
+
default:
cc ${STD} -g -Wall -Wextra -Wno-unused-parameter -Wno-unused-function -fsanitize=address -fsanitize=undefined -o ${BIN} ${SRC} ${LIB} # -Wpedantic -Wshadow -Wconversion
diff --git a/src/gen/gen.c b/src/gen/gen.c
@@ -10,7 +10,7 @@
static gcc_jit_type *type_int;
static gcc_jit_type *type_uint;
-static gcc_jit_type *type_float;
+static gcc_jit_type *type_double;
static gcc_jit_type *type_void;
static gcc_jit_type *type_cstr;
@@ -51,7 +51,7 @@ gen_init(Scope *scope, const char *src, Node *node, bool quiet)
type_int = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_INT64_T);
type_uint = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_UINT64_T);
- type_float = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_DOUBLE);
+ type_double = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_DOUBLE);
type_void = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_VOID);
type_cstr = gcc_jit_context_get_type(ctx, GCC_JIT_TYPE_CONST_CHAR_PTR);
@@ -140,6 +140,12 @@ emit_literal_int(Gen *gen, Node *node)
return gcc_jit_context_new_rvalue_from_int(gen->ctx, type_int, (int)node->data.number.value);
}
+static gcc_jit_rvalue *
+emit_literal_float(Gen *gen, Node *node)
+{
+ return gcc_jit_context_new_rvalue_from_double(gen->ctx, type_double, node->data.number.value);
+}
+
static void
build_program(Gen *gen, Node *node)
{
@@ -196,7 +202,7 @@ lower_builtin_print(Gen *gen, Node *node)
gcc_jit_type *ty = gcc_jit_rvalue_get_type(arg);
if (ty == type_int) {
arg = gcc_jit_context_new_cast(gen->ctx, loc_from_node(gen, node), arg, type_cstr);
- } else if (ty == type_float) {
+ } else if (ty == type_double) {
// variadics already promote float→double; double is
} else if (ty == type_cstr) {
// leave as const char*
@@ -246,9 +252,12 @@ static gcc_jit_rvalue *
handle_expr(Gen *gen, Node *node)
{
switch (node->type) {
- case NODE_NUMBER_LITERAL:
+ case NODE_INT_LITERAL:
return emit_literal_int(gen, node);
break;
+ case NODE_FLOAT_LITERAL:
+ return emit_literal_float(gen, node);
+ break;
case NODE_STRING_LITERAL:
return emit_literal_string(gen, node);
break;
@@ -277,6 +286,12 @@ ox_type_to_c_type(Gen *gen, Node *node)
return type_int;
} else if (strcmp(type_name, "string") == 0) {
return type_cstr;
+ } else if (strcmp(type_name, "float") == 0) {
+ return type_double;
+ } else if (strcmp(type_name, "uint") == 0) {
+ return type_uint;
+ } else if (strcmp(type_name, "void") == 0) {
+ return type_void;
} else {
softpanic("unhandled type in gen %s", type_name);
}
@@ -295,27 +310,34 @@ build_statement(Gen *gen, Node *node)
gcc_jit_location *loc = loc_from_node(gen, node);
const char *var_name = span_str(gen->src, node->data.var_decl.name, (char[IDENTSZ]) { 0 });
gcc_jit_type *declared_type = ox_type_to_c_type(gen, node->data.var_decl.type);
- gcc_jit_lvalue *var_decl = gcc_jit_function_new_local(gen->curr_func, loc, declared_type, strdup(var_name));
- if (node->data.var_decl.init != NULL) {
- gcc_jit_rvalue *rvalue = handle_expr(gen, node->data.var_decl.init);
+ gcc_jit_lvalue *var_decl = NULL;
+ gcc_jit_rvalue *rvalue = handle_expr(gen, node->data.var_decl.init);
+
+ if (gen->curr_func == NULL && gen->curr_block == NULL) {
+ var_decl = gcc_jit_context_new_global(gen->ctx, loc, GCC_JIT_GLOBAL_INTERNAL, declared_type, strdup(var_name));
+ gcc_jit_global_set_initializer_rvalue(var_decl, rvalue);
+ } else {
+ var_decl = gcc_jit_function_new_local(gen->curr_func, loc, declared_type, strdup(var_name));
gcc_jit_block_add_assignment(gen->curr_block, loc, var_decl, rvalue);
+ }
- printf("adding 1 symbol: %s\n", span_str(gen->src, node->data.var_decl.name, (char[IDENTSZ]) { 0 }));
+ if (node->data.var_decl.init == NULL) { panic("could not instanciate gcc jit new local"); }
- Symbol *sym = (Symbol *)calloc(1, sizeof(Symbol));
- sym->name = node->data.var_decl.name;
- sym->decl = node;
- sym->ctype = declared_type;
- sym->d.lvalue = var_decl;
+ printf("adding 1 symbol: %s\n", span_str(gen->src, node->data.var_decl.name, (char[IDENTSZ]) { 0 }));
- if (gen->scope->len == gen->scope->cap) {
- gen->scope->cap *= 2;
- gen->scope->symbols = (Symbol **)realloc(gen->scope->symbols, sizeof(Symbol *) * gen->scope->cap);
- }
+ Symbol *sym = (Symbol *)calloc(1, sizeof(Symbol));
+ sym->name = node->data.var_decl.name;
+ sym->decl = node;
+ sym->ctype = declared_type;
+ sym->d.lvalue = var_decl;
- gen->scope->symbols[gen->scope->len++] = sym;
+ if (gen->scope->len == gen->scope->cap) {
+ gen->scope->cap *= 2;
+ gen->scope->symbols = (Symbol **)realloc(gen->scope->symbols, sizeof(Symbol *) * gen->scope->cap);
}
+
+ gen->scope->symbols[gen->scope->len++] = sym;
} break;
case NODE_EXPR_STATEMENT: {
gcc_jit_rvalue *rv = handle_expr(gen, node->data.expr_statement.expr);
@@ -381,10 +403,16 @@ gen_next(Gen *gen, Node *node)
case NODE_STRING_LITERAL:
emit_literal_string(gen, node);
break;
- case NODE_NUMBER_LITERAL:
+ case NODE_INT_LITERAL:
emit_literal_int(gen, node);
break;
+ case NODE_FLOAT_LITERAL:
+ emit_literal_float(gen, node);
+ break;
+ case NODE_VAR_DECL:
+ build_statement(gen, node);
+ break;
default:
- printf("unhandled, %s\n", node_type_str(node->type));
+ printf("gen: unhandled, %s\n", node_type_str(node->type));
}
}
diff --git a/src/lexer.c b/src/lexer.c
@@ -1,4 +1,5 @@
#include "lexer.h"
+#include "types.h"
#include "utils.h"
#include <string.h>
@@ -111,15 +112,17 @@ static Token make_ident(Lexer* lex, size_t pos, size_t line, size_t col)
}
static Token make_number(Lexer* lex, size_t pos, size_t line, size_t col)
{
+ bool is_float = false;
while (isdigit(peek(lex)))
nudge(lex);
if (peek(lex) == '.' && isdigit(peek2(lex))) {
+ is_float = true;
nudge(lex);
while (isdigit(peek(lex)))
nudge(lex);
}
return (Token) {
- .type = TOKEN_NUMBER_LITERAL,
+ .type = is_float ? TOKEN_FLOAT_LITERAL : TOKEN_INT_LITERAL,
.start = pos,
.end = lex->pos,
.line = line,
@@ -286,7 +289,8 @@ static void print_token(const Token* t, const char* contents)
[TOKEN_EQUAL] = "equal",
[TOKEN_SEMICOLON] = "semicol",
[TOKEN_COMMA] = "comma",
- [TOKEN_NUMBER_LITERAL] = "number",
+ [TOKEN_INT_LITERAL] = "integer literal",
+ [TOKEN_FLOAT_LITERAL] = "float literal",
[TOKEN_STRING_LITERAL] = "string literal",
[TOKEN_SLASH] = "slash",
[TOKEN_STAR] = "star",
@@ -364,7 +368,8 @@ const char* token_type_str(TokenType t)
[TOKEN_EQUAL] = "TOKEN_EQUAL",
[TOKEN_SEMICOLON] = "TOKEN_SEMICOLON",
[TOKEN_COMMA] = "TOKEN_COMMA",
- [TOKEN_NUMBER_LITERAL] = "TOKEN_NUMBER_LITERAL",
+ [TOKEN_INT_LITERAL] = "TOKEN_INT_LITERAL",
+ [TOKEN_FLOAT_LITERAL] = "TOKEN_FLOAT_LITERAL",
[TOKEN_STRING_LITERAL] = "TOKEN_STRING_LITERAL",
[TOKEN_SLASH] = "TOKEN_SLASH",
[TOKEN_STAR] = "TOKEN_STAR",
diff --git a/src/parser/ast.c b/src/parser/ast.c
@@ -37,7 +37,7 @@ Node*
make_number_node(Parser* par)
{
Token tok = consume(par);
- assert(tok.type == TOKEN_NUMBER_LITERAL);
+ assert(tok.type == TOKEN_INT_LITERAL || tok.type == TOKEN_FLOAT_LITERAL);
size_t len = tok.end - tok.start;
char buf[len + 1]; // strtod needs a \0 terminated string
for (size_t i = 0; i < len; i++)
@@ -46,7 +46,7 @@ make_number_node(Parser* par)
double value = strtod(buf, NULL);
Node* node = (Node*)calloc(1, sizeof(Node));
if (node == NULL) panic("make_number_node: could not alloc");
- node->type = NODE_NUMBER_LITERAL;
+ node->type = tok.type == TOKEN_INT_LITERAL ? NODE_INT_LITERAL : NODE_FLOAT_LITERAL;
node->scope = NULL;
node->data.number.value = value;
return node;
diff --git a/src/parser/expr.c b/src/parser/expr.c
@@ -57,7 +57,7 @@ Node*
parse_number(Parser* par)
{
Token tok = consume(par);
- assert(tok.type == TOKEN_NUMBER_LITERAL);
+ assert(tok.type == TOKEN_INT_LITERAL || tok.type == TOKEN_FLOAT_LITERAL);
size_t len = tok.end - tok.start;
char buf[len + 1]; // strtod needs a \0 terminated string
@@ -68,7 +68,7 @@ parse_number(Parser* par)
Node* num_node = (Node*)calloc(1, sizeof(Node));
if (num_node == NULL) panic("parse_number: alloc failed");
- num_node->type = NODE_NUMBER_LITERAL;
+ num_node->type = tok.type == TOKEN_INT_LITERAL ? NODE_INT_LITERAL : NODE_FLOAT_LITERAL;
num_node->scope = NULL;
num_node->data.number.value = value;
return num_node;
@@ -183,7 +183,7 @@ parse_primary(Parser* par)
{
Token tok = peek(par);
if (tok.type == TOKEN_STRING_LITERAL) { return make_string_node(par); }
- if (tok.type == TOKEN_NUMBER_LITERAL) { return make_number_node(par); }
+ if (tok.type == TOKEN_INT_LITERAL || tok.type == TOKEN_FLOAT_LITERAL) { return make_number_node(par); }
if (tok.type == TOKEN_IDENT) { return parse_ident(par); }
if (tok.type == TOKEN_LPAREN) {
consume(par); // consume '('
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
@@ -6,8 +6,8 @@
#include <stdbool.h>
/* basic range to str */
-const char*
-range_str(const char* src, size_t start, size_t end, char* stack_alloc_chptr)
+const char *
+range_str(const char *src, size_t start, size_t end, char *stack_alloc_chptr)
{
const size_t len = end - start;
if (!src || !stack_alloc_chptr) return NULL;
@@ -18,8 +18,8 @@ range_str(const char* src, size_t start, size_t end, char* stack_alloc_chptr)
return stack_alloc_chptr;
}
-const char*
-span_str(const char* src, Span s, char* stack_alloc_chptr)
+const char *
+span_str(const char *src, Span s, char *stack_alloc_chptr)
{
return range_str(src, s.start, s.end, stack_alloc_chptr);
}
@@ -60,18 +60,15 @@ span_str(const char* src, Span s, char* stack_alloc_chptr)
// }
static void
-print_node(const char* source, Node* node, int level)
+print_node(const char *source, Node *node, int level)
{
assert(node != NULL);
assert(level < 192);
- const char* name;
+ const char *name;
switch (node->type) {
case NODE_FUNCTION_DECL:
- name = range_str(source,
- node->data.function_decl.name.start,
- node->data.function_decl.name.end,
- (char[IDENTSZ]) { 0 });
+ name = range_str(source, node->data.function_decl.name.start, node->data.function_decl.name.end, (char[IDENTSZ]) { 0 });
printf("%*s FUNC DECL: name='%s'\n", level, "", name);
if (node->data.function_decl.return_type) {
printf("%*s ↳ return type:\n", level * 2, "");
@@ -80,7 +77,7 @@ print_node(const char* source, Node* node, int level)
if (node->data.function_decl.params) {
printf("%*s ↳ params:\n", level * 2, "");
for (size_t i = 0; i < node->data.function_decl.p_len; i++) {
- Node* param = node->data.function_decl.params[i];
+ Node *param = node->data.function_decl.params[i];
print_node(source, param, level + 1);
}
} else {
@@ -92,18 +89,12 @@ print_node(const char* source, Node* node, int level)
}
break;
case NODE_PARAM:
- name = range_str(source,
- node->data.param.name.start,
- node->data.param.name.end,
- (char[IDENTSZ]) { 0 });
+ name = range_str(source, node->data.param.name.start, node->data.param.name.end, (char[IDENTSZ]) { 0 });
printf("%*s ↳ param: name='%s'\n", level * 2, "", name);
if (node->data.param.type) { print_node(source, node->data.param.type, level + 1); }
break;
case NODE_VAR_DECL:
- name = range_str(source,
- node->data.var_decl.name.start,
- node->data.var_decl.name.end,
- (char[IDENTSZ]) { 0 });
+ name = range_str(source, node->data.var_decl.name.start, node->data.var_decl.name.end, (char[IDENTSZ]) { 0 });
printf("%*s VAR DECL: name='%s'\n", level, "", name);
if (node->data.var_decl.type) {
printf("%*s ↳ type:\n", level * 2, "");
@@ -139,7 +130,7 @@ print_node(const char* source, Node* node, int level)
if (node->data.call_expr.args) {
printf("%*s ↳ args:\n", level * 2, "");
for (size_t i = 0; i < node->data.call_expr.len; i++) {
- Node* arg = node->data.call_expr.args[i];
+ Node *arg = node->data.call_expr.args[i];
print_node(source, arg, level + 1);
}
}
@@ -152,26 +143,23 @@ print_node(const char* source, Node* node, int level)
printf("%*s CONTINUE statement\n", level, "");
if (node->data.cont.expr) { print_node(source, node->data.cont.expr, level + 1); }
break;
- case NODE_NUMBER_LITERAL:
- printf("%*s ↳ LITERAL NUMBER value=%f\n", level * 2, "", node->data.number.value);
+ case NODE_INT_LITERAL:
+ printf("%*s ↳ LITERAL INT NUMBER value=%f\n", level * 2, "", node->data.number.value);
+ break;
+ case NODE_FLOAT_LITERAL:
+ printf("%*s ↳ LITERAL FLOAT NUMBER value=%f\n", level * 2, "", node->data.number.value);
break;
case NODE_STRING_LITERAL: {
- const char* lit = span_str(source, node->data.string.value, (char[IDENTSZ]) { 0 });
+ const char *lit = span_str(source, node->data.string.value, (char[IDENTSZ]) { 0 });
printf("%*s ↳ LITERAL STRING value=\"%s\"\n", level * 2, "", lit);
break;
}
case NODE_TYPE:
- name = range_str(source,
- node->data.ident.name.start,
- node->data.ident.name.end,
- (char[IDENTSZ]) { 0 });
+ name = range_str(source, node->data.ident.name.start, node->data.ident.name.end, (char[IDENTSZ]) { 0 });
printf("%*s ↳ TYPE name='%s'\n", level * 2, "", name);
break;
case NODE_IDENT:
- name = range_str(source,
- node->data.ident.name.start,
- node->data.ident.name.end,
- (char[IDENTSZ]) { 0 });
+ name = range_str(source, node->data.ident.name.start, node->data.ident.name.end, (char[IDENTSZ]) { 0 });
printf("%*s ↳ IDENT name='%s'\n", level * 2, "", name);
break;
// case NODE_VOID:
@@ -222,9 +210,7 @@ print_node(const char* source, Node* node, int level)
break;
case NODE_EXPR_STATEMENT:
printf("%*s EXPR STMT:\n", level, "");
- if (node->data.expr_statement.expr) {
- print_node(source, node->data.expr_statement.expr, level + 1);
- }
+ if (node->data.expr_statement.expr) { print_node(source, node->data.expr_statement.expr, level + 1); }
break;
case NODE_SUBSCRIPT_EXPR:
printf("%*s SUBSCRIPT expr:\n", level, "");
@@ -294,7 +280,7 @@ print_node(const char* source, Node* node, int level)
}
void
-ast_print(Ast* ast)
+ast_print(Ast *ast)
{
print_node(ast->src, ast->node, 0);
}
@@ -305,10 +291,10 @@ print_node_type_str(NodeType t)
printf("print_node_type_str: %s\n", node_type_str(t));
}
-const char*
+const char *
node_type_str(NodeType t)
{
- static const char* type_strings[] = { [NODE_PROGRAM] = "NODE_PROGRAM",
+ static const char *type_strings[] = { [NODE_PROGRAM] = "NODE_PROGRAM",
[NODE_FUNCTION_DECL] = "NODE_FUNCTION_DECL",
[NODE_PARAM] = "NODE_PARAM",
[NODE_VAR_DECL] = "NODE_VAR_DECL",
@@ -316,7 +302,8 @@ node_type_str(NodeType t)
[NODE_CALL_EXPR] = "NODE_CALL_EXPR",
[NODE_RETURN] = "NODE_RETURN",
[NODE_CONTINUE] = "NODE_CONTINUE",
- [NODE_NUMBER_LITERAL] = "NODE_NUMBER_LITERAL",
+ [NODE_INT_LITERAL] = "NODE_INT_LITERAL",
+ [NODE_FLOAT_LITERAL] = "NODE_FLOAT_LITERAL",
[NODE_STRING_LITERAL] = "NODE_STRING_LITERAL",
[NODE_TYPE] = "NODE_TYPE",
[NODE_IDENT] = "NODE_IDENT",
diff --git a/src/types.h b/src/types.h
@@ -16,7 +16,8 @@ typedef enum {
TOKEN_SEMICOLON,
TOKEN_PERCENT,
TOKEN_COMMA,
- TOKEN_NUMBER_LITERAL,
+ TOKEN_INT_LITERAL,
+ TOKEN_FLOAT_LITERAL,
TOKEN_STRING_LITERAL,
TOKEN_SLASH,
TOKEN_STAR,
@@ -75,7 +76,8 @@ typedef enum {
NODE_RETURN,
NODE_BREAK,
NODE_CONTINUE,
- NODE_NUMBER_LITERAL,
+ NODE_INT_LITERAL,
+ NODE_FLOAT_LITERAL,
NODE_STRING_LITERAL,
NODE_IDENT,
NODE_TYPE,