ox

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

commit 89c19100b77b3ab89675aeb9cfab834f1d464c0b
parent ba4d6709b055e7e7ffc6581809388ce97a77a58b
Author: citbl <citbl@citbl.org>
Date:   Mon, 20 Oct 2025 22:08:29 +1000

handle assignments, check existence and matching type

Diffstat:
M.zed/debug.json | 2+-
Aex12.ox | 5+++++
Msrc/gen/gen.c | 49+++++++++++++++++++++++++++++++++++++++----------
Msrc/main.c | 2+-
Msrc/parser.h | 3+++
Msrc/parser/parser.c | 6++++--
Msrc/parser/parser_utils.c | 14++++++++++++++
Msrc/parser/stmt.c | 3+++
Msrc/types.h | 2+-
Msrc/utils.c | 17+++++++++++++++++
Msrc/utils.h | 5++++-
11 files changed, 92 insertions(+), 16 deletions(-)

diff --git a/.zed/debug.json b/.zed/debug.json @@ -11,7 +11,7 @@ "cwd": "$ZED_WORKTREE_ROOT" }, "program": "$ZED_WORKTREE_ROOT/oxc", - "args": ["$ZED_WORKTREE_ROOT/ex9.ox"], + "args": ["$ZED_WORKTREE_ROOT/ex12.ox"], "request": "launch", "adapter": "CodeLLDB" } diff --git a/ex12.ox b/ex12.ox @@ -0,0 +1,5 @@ +void main() { + string jake = "before change"; + jake = "expected result"; + print(jake); +} diff --git a/src/gen/gen.c b/src/gen/gen.c @@ -260,7 +260,8 @@ handle_expr(Gen* gen, Node* node) } // case NODE_IDENT: { // return NULL; // fixme - // } break; + // break; + // } default: printf("handle_expr unhandled, %s\n", node_type_str(node->type)); } @@ -289,6 +290,17 @@ ox_type_to_c_type(Gen* gen, Node* node) } static void +add_symbol(Gen* gen, Symbol* 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; +} + +static void build_statement(Gen* gen, Node* node) { switch (node->type) { @@ -314,25 +326,42 @@ build_statement(Gen* gen, Node* node) if (node->data.var_decl.init == NULL) { panic("could not instanciate gcc jit new local"); } - printf("adding 1 symbol: %s\n", span_str(gen->src, node->data.var_decl.name, (char[IDENTSZ]) { 0 })); + printf("adding 1 symbol: %s\n", var_name); 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; - - if (gen->scope->len == gen->scope->cap) { - gen->scope->cap *= 2; - gen->scope->symbols = (Symbol**)realloc(gen->scope->symbols, sizeof(Symbol*) * gen->scope->cap); + add_symbol(gen, sym); + break; + } + case NODE_VAR_ASSIGN: { + gcc_jit_location* loc = loc_from_node(gen, node); + gcc_jit_rvalue* rvalue = handle_expr(gen, node->data.var_assign.rhs); + // find the var_decl (d.lvalue) from the symbols table's symbol. + for (size_t i = 0; i < gen->scope->len; i++) { + Symbol* sym = gen->scope->symbols[i]; + if (span_ident_same(sym->name, node->data.var_assign.lhs->data.ident.name, gen->src)) { + // we found the symbol we are assigning to + gcc_jit_lvalue* lvalue = sym->d.lvalue; + + // check the type of lvalue matches the rvalue + gcc_jit_type* ltype = sym->ctype; + gcc_jit_type* rtype = gcc_jit_rvalue_get_type(rvalue); + if (rtype != ltype) { + panic_at(node, "right hand side of assigment doesn't match the type of the left hand side"); + } + if (lvalue) gcc_jit_block_add_assignment(gen->curr_block, loc, lvalue, rvalue); + } } - - gen->scope->symbols[gen->scope->len++] = sym; - } break; + break; + } case NODE_EXPR_STATEMENT: { gcc_jit_rvalue* rv = handle_expr(gen, node->data.expr_statement.expr); if (rv) gcc_jit_block_add_eval(gen->curr_block, loc_from_node(gen, node), rv); - } break; + break; + } default: printf("build_statement unhandled, %s\n", node_type_str(node->type)); break; diff --git a/src/main.c b/src/main.c @@ -56,7 +56,7 @@ main(int argc, char* argv[]) Ast ast; parser_parse(&ast, &par); - // ast_print(&ast); + ast_print(&ast); printf("--- sem --- \n"); diff --git a/src/parser.h b/src/parser.h @@ -61,3 +61,6 @@ Node* make_call_node(Node*, NodeVec); const char* span_str(const char* src, Span s, char* stack_alloc_chptr); const char* range_str(const char* src, size_t start, size_t end, char* stack_alloc_chptr); +bool span_ident_same(Span a, Span b, const char* src); + +void error_fmt(char* buffer, const char* message, Node* node); diff --git a/src/parser/parser.c b/src/parser/parser.c @@ -52,7 +52,7 @@ expect(Parser* par, TokenType type) Token tok = peek(par); if (tok.type != type) { const char* name = range_str(par->src, tok.start, tok.end, (char[IDENTSZ]) { 0 }); - panic("Expected %d got '%s' (%d) at %s:%zu:%zu", token_type_str(type), name, tok.type, par->filename, tok.line, tok.col); + panic("Expected %s, but got '%s' (%d) at %s:%zu:%zu", token_type_str(type), name, tok.type, par->filename, tok.line, tok.col); assert(tok.type == type); } return consume(par); @@ -182,7 +182,9 @@ parse_statement(Parser* par) return parse_block(par); } - if (tok.type == TOKEN_IDENT && tok2.type == TOKEN_IDENT) return parse_decl_or_func_decl(par); + if (tok.type == TOKEN_IDENT && tok2.type == TOKEN_IDENT) { return parse_decl_or_func_decl(par); } + + if (tok.type == TOKEN_IDENT && tok2.type == TOKEN_EQUAL) { return parse_assignment(par); } switch (tok.type) { case TOKEN_RETURN: diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c @@ -24,6 +24,14 @@ span_str(const char* src, Span s, char* stack_alloc_chptr) return range_str(src, s.start, s.end, stack_alloc_chptr); } +bool +span_ident_same(Span a, Span b, const char* src) +{ + const char* a_name = span_str(src, a, (char[IDENTSZ]) { 0 }); + const char* b_name = span_str(src, b, (char[IDENTSZ]) { 0 }); + return strcmp(a_name, b_name) == 0; +} + // int span_to_str(const char* src, size_t start, size_t end, char* out_buf) { // if (!src || !out_buf) return -1; /* Null pointer passed */ // if (start >= end) return -2; /* Empty or inverted span */ @@ -59,6 +67,12 @@ span_str(const char* src, Span s, char* stack_alloc_chptr) // return s; // } +void +error_fmt(char* buffer, const char* msg, Node* node) +{ + sprintf(buffer, "%s (%s L.%zu:%zu).", msg, node->filename, node->line, node->col); +} + static void print_node(const char* source, Node* node, int level) { diff --git a/src/parser/stmt.c b/src/parser/stmt.c @@ -118,6 +118,9 @@ parse_assignment(Parser* par) dereference *p = 5; */ + assign->filename = par->filename; + assign->line = ident.line; + assign->col = ident.col; assign->data.var_assign.lhs->type = NODE_IDENT; // TODO handle other cases assign->data.var_assign.lhs->scope = NULL; assign->data.var_assign.lhs->data.ident.name = name; diff --git a/src/types.h b/src/types.h @@ -150,7 +150,7 @@ typedef struct Node { struct Node* next; struct Scope* scope; const char* filename; - int line, col; + size_t line, col; /* NOTE we will eventually add spans for condition info, etc. to print out in errors */ diff --git a/src/utils.c b/src/utils.c @@ -7,6 +7,23 @@ #include <string.h> void +panic_at(Node* node, const char* fmt, ...) +{ + va_list args; + int saved_errno; + saved_errno = errno; + va_start(args, fmt); + fprintf(stderr, "%s, [%zu:%zu] ", node->filename, node->line, node->col); + fprintf(stderr, "Error: "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + if (fmt[0] && fmt[strlen(fmt) - 1] == ':') fprintf(stderr, " %s", strerror(saved_errno)); + fputc('\n', stderr); + exit(1); +} + +void panic(const char* fmt, ...) { va_list args; diff --git a/src/utils.h b/src/utils.h @@ -1,6 +1,9 @@ #pragma once #include <stdlib.h> +#include "types.h" -void panic(const char* fmt, ...); void softpanic(const char* fmt, ...); + +void panic(const char* fmt, ...); +void panic_at(Node* node, const char* fmt, ...);