diff --git a/examples/28-sdl-graphics.sx b/examples/28-sdl-graphics.sx index 58ab3e7..e803a2a 100644 --- a/examples/28-sdl-graphics.sx +++ b/examples/28-sdl-graphics.sx @@ -1,8 +1,11 @@ #import "modules/std.sx"; #import "modules/sdl3.sx"; #import "modules/opengl.sx"; +#import "modules/math"; -PI :f32: 3.14159265; + +WIDTH :f32: 800; +HEIGHT :f32: 600; vec4 :: (x: f32, y: f32, z: f32, w: f32) -> Vector(4, f32) { .[x, y, z, w]; @@ -23,6 +26,7 @@ mat4_multiply :: (a: *Matrix44, b: *Matrix44) -> Matrix44 { out.c3 = a.c0 * b.c3.x + a.c1 * b.c3.y + a.c2 * b.c3.z + a.c3 * b.c3.w; out; } +multiply :: ufcs mat4_multiply; mat4_perspective :: (fov: f32, aspect: f32, near: f32, far: f32) -> Matrix44 { half := fov / 2.0; @@ -117,7 +121,7 @@ main :: () { SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - window := SDL_CreateWindow("sx GL cube", 800, 600, SDL_WINDOW_OPENGL); + window := SDL_CreateWindow("sx GL cube", xx WIDTH, xx HEIGHT, SDL_WINDOW_OPENGL); gl_ctx := SDL_GL_CreateContext(window); SDL_GL_MakeCurrent(window, gl_ctx); SDL_GL_SetSwapInterval(1); @@ -276,11 +280,11 @@ GLSL; angle := ms * 0.001; // Build matrices - proj := mat4_perspective(PI / 4.0, 800.0 / 600.0, 0.1, 100.0); + proj := mat4_perspective(PI / 4.0, WIDTH / HEIGHT, 0.1, 100.0); view := mat4_translate(0.0, 0.0, -3.0); rot_y := mat4_rotate_y(angle); rot_x := mat4_rotate_x(angle * 0.7); - model := mat4_multiply(rot_y, rot_x); + model := (rot_y, rot_x).multiply(); vm := mat4_multiply(view, model); mvp := mat4_multiply(proj, vm); diff --git a/examples/modules/math/math.sx b/examples/modules/math/math.sx new file mode 100644 index 0000000..c341b0f --- /dev/null +++ b/examples/modules/math/math.sx @@ -0,0 +1,5 @@ +PI :f32: 3.14159265; + +sqrt :: (x: $T) -> T #builtin; +sin :: (x: $T) -> T #builtin; +cos :: (x: $T) -> T #builtin; diff --git a/examples/modules/std.sx b/examples/modules/std.sx index 775e79d..7e6f9b8 100644 --- a/examples/modules/std.sx +++ b/examples/modules/std.sx @@ -1,8 +1,8 @@ Vector :: ($N: int, $T: Type) -> Type #builtin; out :: (str: string) -> void #builtin; -sqrt :: (x: $T) -> T #builtin; -sin :: (x: $T) -> T #builtin; -cos :: (x: $T) -> T #builtin; +// sqrt :: (x: $T) -> T #builtin; +// sin :: (x: $T) -> T #builtin; +// cos :: (x: $T) -> T #builtin; size_of :: ($T: Type) -> s64 #builtin; malloc :: (size: s64) -> *void #builtin; memcpy :: (dst: *void, src: *void, size: s64) -> *void #builtin; diff --git a/src/codegen.zig b/src/codegen.zig index 86a86bc..5222033 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -2338,6 +2338,9 @@ pub const CodeGen = struct { const llvm_ty = self.typeToLLVM(target_ty); switch (node.data) { .int_literal => |lit| { + if (target_ty.isFloat()) { + return c.LLVMConstReal(llvm_ty, @floatFromInt(@as(i64, lit.value))); + } return c.LLVMConstInt(llvm_ty, @bitCast(@as(i64, lit.value)), 0); }, .float_literal => |lit| { @@ -4773,6 +4776,15 @@ pub const CodeGen = struct { return entry.ptr; } } + // Non-identifier expressions (e.g. field access, tuple element): + // generate value, store into temp alloca, return alloca pointer + if (node.data != .identifier) { + const val = try self.genExpr(node); + const llvm_ty = c.LLVMTypeOf(val); + const tmp = self.buildEntryBlockAlloca(llvm_ty, "implicit_addr"); + _ = c.LLVMBuildStore(self.builder, val, tmp); + return tmp; + } } } diff --git a/src/lsp/server.zig b/src/lsp/server.zig index 6644e0f..27dae08 100644 --- a/src/lsp/server.zig +++ b/src/lsp/server.zig @@ -164,7 +164,7 @@ pub const Server = struct { const doc = self.documents.get(file_path) orelse { return try self.sendResponse(id_json, "null"); }; - const sema = doc.sema orelse { + const sema = doc.sema orelse doc.last_good_sema orelse { return try self.sendResponse(id_json, "null"); }; @@ -420,7 +420,9 @@ pub const Server = struct { } // Regular completion: all in-scope symbols + keywords - const sema = doc.sema orelse { + // Fall back to last successful analysis when current parse/analysis fails + // (common while user is mid-typing) + const sema = doc.sema orelse doc.last_good_sema orelse { return try self.sendResponse(id_json, "[]"); }; @@ -490,7 +492,7 @@ pub const Server = struct { var items = std.ArrayList(lsp.CompletionItem).empty; if (extractDotPrefix(doc.source, cursor_offset)) |prefix| { - if (doc.sema) |sema| { + if (doc.sema orelse doc.last_good_sema) |sema| { // Check if prefix is a namespace — offer imported doc's declarations if (self.findImportByNs(doc, prefix)) |imp| { if (self.documents.get(imp.path)) |imp_doc| { diff --git a/src/sema.zig b/src/sema.zig index b27f713..6ab2902 100644 --- a/src/sema.zig +++ b/src/sema.zig @@ -539,7 +539,19 @@ pub const Analyzer = struct { fn analyzeParams(self: *Analyzer, params: []const ast.Param) !void { for (params) |param| { - const param_type = Type.fromTypeExpr(param.type_expr); + self.resolveTypeRef(param.type_expr); + const param_type = Type.fromTypeExpr(param.type_expr) orelse blk: { + if (param.type_expr.data == .type_expr) { + const name = param.type_expr.data.type_expr.name; + const resolved = self.type_aliases.get(name) orelse name; + if (self.symbol_index.get(resolved)) |indices| { + for (indices.items) |idx| { + if (self.symbols.items[idx].ty) |ty| break :blk ty; + } + } + } + break :blk null; + }; try self.addSymbol(param.name, .param, param_type, param.name_span); } } @@ -884,14 +896,63 @@ pub const Analyzer = struct { const resolved = self.type_aliases.get(name) orelse name; if (self.symbol_index.get(resolved)) |indices| { for (indices.items) |idx| { - if (self.symbols.items[idx].ty) |ty| return ty; + if (self.symbols.items[idx].ty) |ty| { + // Register a reference so go-to-definition works on type names + self.tryAddReference(resolved, tn.span); + return ty; + } } } } + // For compound types (pointers, slices, arrays), resolve inner type refs + self.resolveTypeRef(tn); } return null; } + /// Try to create a reference for a name without emitting diagnostics. + /// Used for type names where missing symbols are expected (primitives, builtins). + fn tryAddReference(self: *Analyzer, name: []const u8, span: Span) void { + if (self.symbol_index.get(name)) |indices| { + var j = indices.items.len; + while (j > 0) { + j -= 1; + const idx = indices.items[j]; + const sym = self.symbols.items[idx]; + if (sym.scope_depth <= self.scope_depth) { + self.references.append(self.allocator, .{ + .span = span, + .symbol_index = idx, + }) catch {}; + return; + } + } + } + } + + /// Create references for type expression nodes so go-to-definition works on type names. + /// Only resolves compound types (pointer/slice/array element types). + fn resolveTypeRef(self: *Analyzer, node: *Node) void { + switch (node.data) { + .type_expr => |te| { + self.tryAddReference(te.name, node.span); + }, + .pointer_type_expr => |pte| { + self.resolveTypeRef(pte.pointee_type); + }, + .many_pointer_type_expr => |mpte| { + self.resolveTypeRef(mpte.element_type); + }, + .slice_type_expr => |ste| { + self.resolveTypeRef(ste.element_type); + }, + .array_type_expr => |ate| { + self.resolveTypeRef(ate.element_type); + }, + else => {}, + } + } + fn inferValueType(value: *Node) ?Type { return switch (value.data) { .int_literal => Type.s(64),