...
This commit is contained in:
@@ -1,8 +1,11 @@
|
|||||||
#import "modules/std.sx";
|
#import "modules/std.sx";
|
||||||
#import "modules/sdl3.sx";
|
#import "modules/sdl3.sx";
|
||||||
#import "modules/opengl.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) {
|
vec4 :: (x: f32, y: f32, z: f32, w: f32) -> Vector(4, f32) {
|
||||||
.[x, y, z, w];
|
.[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.c3 = a.c0 * b.c3.x + a.c1 * b.c3.y + a.c2 * b.c3.z + a.c3 * b.c3.w;
|
||||||
out;
|
out;
|
||||||
}
|
}
|
||||||
|
multiply :: ufcs mat4_multiply;
|
||||||
|
|
||||||
mat4_perspective :: (fov: f32, aspect: f32, near: f32, far: f32) -> Matrix44 {
|
mat4_perspective :: (fov: f32, aspect: f32, near: f32, far: f32) -> Matrix44 {
|
||||||
half := fov / 2.0;
|
half := fov / 2.0;
|
||||||
@@ -117,7 +121,7 @@ main :: () {
|
|||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
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);
|
gl_ctx := SDL_GL_CreateContext(window);
|
||||||
SDL_GL_MakeCurrent(window, gl_ctx);
|
SDL_GL_MakeCurrent(window, gl_ctx);
|
||||||
SDL_GL_SetSwapInterval(1);
|
SDL_GL_SetSwapInterval(1);
|
||||||
@@ -276,11 +280,11 @@ GLSL;
|
|||||||
angle := ms * 0.001;
|
angle := ms * 0.001;
|
||||||
|
|
||||||
// Build matrices
|
// 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);
|
view := mat4_translate(0.0, 0.0, -3.0);
|
||||||
rot_y := mat4_rotate_y(angle);
|
rot_y := mat4_rotate_y(angle);
|
||||||
rot_x := mat4_rotate_x(angle * 0.7);
|
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);
|
vm := mat4_multiply(view, model);
|
||||||
mvp := mat4_multiply(proj, vm);
|
mvp := mat4_multiply(proj, vm);
|
||||||
|
|
||||||
|
|||||||
5
examples/modules/math/math.sx
Normal file
5
examples/modules/math/math.sx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
PI :f32: 3.14159265;
|
||||||
|
|
||||||
|
sqrt :: (x: $T) -> T #builtin;
|
||||||
|
sin :: (x: $T) -> T #builtin;
|
||||||
|
cos :: (x: $T) -> T #builtin;
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
Vector :: ($N: int, $T: Type) -> Type #builtin;
|
Vector :: ($N: int, $T: Type) -> Type #builtin;
|
||||||
out :: (str: string) -> void #builtin;
|
out :: (str: string) -> void #builtin;
|
||||||
sqrt :: (x: $T) -> T #builtin;
|
// sqrt :: (x: $T) -> T #builtin;
|
||||||
sin :: (x: $T) -> T #builtin;
|
// sin :: (x: $T) -> T #builtin;
|
||||||
cos :: (x: $T) -> T #builtin;
|
// cos :: (x: $T) -> T #builtin;
|
||||||
size_of :: ($T: Type) -> s64 #builtin;
|
size_of :: ($T: Type) -> s64 #builtin;
|
||||||
malloc :: (size: s64) -> *void #builtin;
|
malloc :: (size: s64) -> *void #builtin;
|
||||||
memcpy :: (dst: *void, src: *void, size: s64) -> *void #builtin;
|
memcpy :: (dst: *void, src: *void, size: s64) -> *void #builtin;
|
||||||
|
|||||||
@@ -2338,6 +2338,9 @@ pub const CodeGen = struct {
|
|||||||
const llvm_ty = self.typeToLLVM(target_ty);
|
const llvm_ty = self.typeToLLVM(target_ty);
|
||||||
switch (node.data) {
|
switch (node.data) {
|
||||||
.int_literal => |lit| {
|
.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);
|
return c.LLVMConstInt(llvm_ty, @bitCast(@as(i64, lit.value)), 0);
|
||||||
},
|
},
|
||||||
.float_literal => |lit| {
|
.float_literal => |lit| {
|
||||||
@@ -4773,6 +4776,15 @@ pub const CodeGen = struct {
|
|||||||
return entry.ptr;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ pub const Server = struct {
|
|||||||
const doc = self.documents.get(file_path) orelse {
|
const doc = self.documents.get(file_path) orelse {
|
||||||
return try self.sendResponse(id_json, "null");
|
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");
|
return try self.sendResponse(id_json, "null");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -420,7 +420,9 @@ pub const Server = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Regular completion: all in-scope symbols + keywords
|
// 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, "[]");
|
return try self.sendResponse(id_json, "[]");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -490,7 +492,7 @@ pub const Server = struct {
|
|||||||
var items = std.ArrayList(lsp.CompletionItem).empty;
|
var items = std.ArrayList(lsp.CompletionItem).empty;
|
||||||
|
|
||||||
if (extractDotPrefix(doc.source, cursor_offset)) |prefix| {
|
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
|
// Check if prefix is a namespace — offer imported doc's declarations
|
||||||
if (self.findImportByNs(doc, prefix)) |imp| {
|
if (self.findImportByNs(doc, prefix)) |imp| {
|
||||||
if (self.documents.get(imp.path)) |imp_doc| {
|
if (self.documents.get(imp.path)) |imp_doc| {
|
||||||
|
|||||||
65
src/sema.zig
65
src/sema.zig
@@ -539,7 +539,19 @@ pub const Analyzer = struct {
|
|||||||
|
|
||||||
fn analyzeParams(self: *Analyzer, params: []const ast.Param) !void {
|
fn analyzeParams(self: *Analyzer, params: []const ast.Param) !void {
|
||||||
for (params) |param| {
|
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);
|
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;
|
const resolved = self.type_aliases.get(name) orelse name;
|
||||||
if (self.symbol_index.get(resolved)) |indices| {
|
if (self.symbol_index.get(resolved)) |indices| {
|
||||||
for (indices.items) |idx| {
|
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;
|
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 {
|
fn inferValueType(value: *Node) ?Type {
|
||||||
return switch (value.data) {
|
return switch (value.data) {
|
||||||
.int_literal => Type.s(64),
|
.int_literal => Type.s(64),
|
||||||
|
|||||||
Reference in New Issue
Block a user