ox

The Ox programming language, compiler and tools (WIP)
Log | Files | Refs | README | LICENSE

commit 177e774dc5134b62d28f960334abca595023af6d
parent 78ab1d361c89debc36336835569daac1b6bbd642
Author: citbl <citbl@citbl.org>
Date:   Mon, 13 Oct 2025 20:43:09 +1000

handle different variables

Diffstat:
M.zed/debug.json | 4++--
Mex9.ox | 10+++++-----
Mmakefile | 3+++
Msrc/gen/gen.c | 68++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/lexer.c | 11++++++++---
Msrc/parser/ast.c | 4++--
Msrc/parser/expr.c | 6+++---
Msrc/parser/parser_utils.c | 63+++++++++++++++++++++++++--------------------------------------
Msrc/types.h | 6++++--
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,