cleanup
This commit is contained in:
@@ -5,5 +5,5 @@ generate::() -> string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main :: () {
|
main :: () {
|
||||||
#insert #run generate();
|
#insert generate();
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@ type_name :: ($T: Type) -> string #builtin;
|
|||||||
field_count :: ($T: Type) -> s64 #builtin;
|
field_count :: ($T: Type) -> s64 #builtin;
|
||||||
field_name :: ($T: Type, idx: s64) -> string #builtin;
|
field_name :: ($T: Type, idx: s64) -> string #builtin;
|
||||||
field_value :: (s: $T, idx: s64) -> Any #builtin;
|
field_value :: (s: $T, idx: s64) -> Any #builtin;
|
||||||
|
string :: []u8 #builtin;
|
||||||
|
|
||||||
int_to_string :: (n: s64) -> string {
|
int_to_string :: (n: s64) -> string {
|
||||||
if n == 0 { return "0"; }
|
if n == 0 { return "0"; }
|
||||||
|
|||||||
748
src/codegen.zig
748
src/codegen.zig
File diff suppressed because it is too large
Load Diff
@@ -1260,10 +1260,7 @@ pub const VM = struct {
|
|||||||
try self.push(.{ .string_val = s });
|
try self.push(.{ .string_val = s });
|
||||||
},
|
},
|
||||||
|
|
||||||
// Cast
|
.cast => {},
|
||||||
.cast => {
|
|
||||||
// TODO: implement type casting
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/core.zig
14
src/core.zig
@@ -93,18 +93,6 @@ pub const Compilation = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn renderErrors(self: *const Compilation) void {
|
pub fn renderErrors(self: *const Compilation) void {
|
||||||
for (self.diagnostics.items.items) |d| {
|
self.diagnostics.renderDebug();
|
||||||
const level_str = switch (d.level) {
|
|
||||||
.err => "error",
|
|
||||||
.warn => "warning",
|
|
||||||
.note => "note",
|
|
||||||
};
|
|
||||||
if (d.span) |span| {
|
|
||||||
const loc = errors.SourceLoc.compute(self.source, span.start);
|
|
||||||
std.debug.print("{s}:{d}:{d}: {s}: {s}\n", .{ self.file_path, loc.line, loc.col, level_str, d.message });
|
|
||||||
} else {
|
|
||||||
std.debug.print("{s}: {s}: {s}\n", .{ self.file_path, level_str, d.message });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ pub const SourceLoc = struct {
|
|||||||
pub fn compute(source: []const u8, byte_offset: u32) SourceLoc {
|
pub fn compute(source: []const u8, byte_offset: u32) SourceLoc {
|
||||||
var line: u32 = 1;
|
var line: u32 = 1;
|
||||||
var col: u32 = 1;
|
var col: u32 = 1;
|
||||||
for (source[0..byte_offset]) |c| {
|
const end = @min(byte_offset, @as(u32, @intCast(source.len)));
|
||||||
|
for (source[0..end]) |c| {
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
line += 1;
|
line += 1;
|
||||||
col = 1;
|
col = 1;
|
||||||
@@ -93,4 +94,20 @@ pub const DiagnosticList = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn renderDebug(self: *const DiagnosticList) void {
|
||||||
|
for (self.items.items) |d| {
|
||||||
|
const level_str = switch (d.level) {
|
||||||
|
.err => "error",
|
||||||
|
.warn => "warning",
|
||||||
|
.note => "note",
|
||||||
|
};
|
||||||
|
if (d.span) |span| {
|
||||||
|
const loc = SourceLoc.compute(self.source, span.start);
|
||||||
|
std.debug.print("{s}:{d}:{d}: {s}: {s}\n", .{ self.file_name, loc.line, loc.col, level_str, d.message });
|
||||||
|
} else {
|
||||||
|
std.debug.print("{s}: {s}: {s}\n", .{ self.file_name, level_str, d.message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,31 +50,25 @@ pub const Lexer = struct {
|
|||||||
return self.lexString(start);
|
return self.lexString(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Directives: #import, #insert, #run
|
// Directives: #import, #insert, #run, #builtin
|
||||||
if (c == '#') {
|
if (c == '#') {
|
||||||
if (self.source.len >= start + 7 and std.mem.eql(u8, self.source[start .. start + 7], "#import") and
|
const directives = .{
|
||||||
(start + 7 >= self.source.len or !isIdentContinue(self.source[start + 7])))
|
.{ "#import", Tag.hash_import },
|
||||||
{
|
.{ "#insert", Tag.hash_insert },
|
||||||
self.index = start + 7;
|
.{ "#run", Tag.hash_run },
|
||||||
return self.makeToken(.hash_import, start, self.index);
|
.{ "#builtin", Tag.hash_builtin },
|
||||||
}
|
};
|
||||||
if (self.source.len >= start + 7 and std.mem.eql(u8, self.source[start .. start + 7], "#insert") and
|
inline for (directives) |d| {
|
||||||
(start + 7 >= self.source.len or !isIdentContinue(self.source[start + 7])))
|
const keyword = d[0];
|
||||||
{
|
const tag = d[1];
|
||||||
self.index = start + 7;
|
const len: u32 = keyword.len;
|
||||||
return self.makeToken(.hash_insert, start, self.index);
|
if (self.source.len >= start + len and
|
||||||
}
|
std.mem.eql(u8, self.source[start .. start + len], keyword) and
|
||||||
if (self.source.len >= start + 4 and std.mem.eql(u8, self.source[start .. start + 4], "#run") and
|
(start + len >= self.source.len or !isIdentContinue(self.source[start + len])))
|
||||||
(start + 4 >= self.source.len or !isIdentContinue(self.source[start + 4])))
|
{
|
||||||
{
|
self.index = start + len;
|
||||||
self.index = start + 4;
|
return self.makeToken(tag, start, self.index);
|
||||||
return self.makeToken(.hash_run, start, self.index);
|
}
|
||||||
}
|
|
||||||
if (self.source.len >= start + 8 and std.mem.eql(u8, self.source[start .. start + 8], "#builtin") and
|
|
||||||
(start + 8 >= self.source.len or !isIdentContinue(self.source[start + 8])))
|
|
||||||
{
|
|
||||||
self.index = start + 8;
|
|
||||||
return self.makeToken(.hash_builtin, start, self.index);
|
|
||||||
}
|
}
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
return self.makeToken(.invalid, start, self.index);
|
return self.makeToken(.invalid, start, self.index);
|
||||||
|
|||||||
@@ -99,12 +99,36 @@ pub const Server = struct {
|
|||||||
stderr.writeStreamingAll(self.io, msg) catch {};
|
stderr.writeStreamingAll(self.io, msg) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RequestContext = struct {
|
||||||
|
id_json: []const u8,
|
||||||
|
uri: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn extractRequest(self: *Server, id: ?std.json.Value, params: std.json.Value) !?RequestContext {
|
||||||
|
const req_id = id orelse return null;
|
||||||
|
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
||||||
|
const td = jsonGet(params, "textDocument") orelse return null;
|
||||||
|
const uri = jsonStr(jsonGet(td, "uri") orelse return null) orelse return null;
|
||||||
|
return .{ .id_json = id_json, .uri = uri };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extractPosition(params: std.json.Value) ?struct { line: u32, character: u32 } {
|
||||||
|
const position = jsonGet(params, "position") orelse return null;
|
||||||
|
const line = std.math.cast(u32, jsonInt(jsonGet(position, "line") orelse return null) orelse return null) orelse return null;
|
||||||
|
const character = std.math.cast(u32, jsonInt(jsonGet(position, "character") orelse return null) orelse return null) orelse return null;
|
||||||
|
return .{ .line = line, .character = character };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sendResponse(self: *Server, id_json: []const u8, result_json: []const u8) !void {
|
||||||
|
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, result_json);
|
||||||
|
try self.transport.writeMessage(resp);
|
||||||
|
}
|
||||||
|
|
||||||
fn handleInitialize(self: *Server, id: ?std.json.Value) !void {
|
fn handleInitialize(self: *Server, id: ?std.json.Value) !void {
|
||||||
const req_id = id orelse return;
|
const req_id = id orelse return;
|
||||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
||||||
const result_json = try lsp.initializeResultJson(self.allocator);
|
const result_json = try lsp.initializeResultJson(self.allocator);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, result_json);
|
try self.sendResponse(id_json, result_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleDidOpen(self: *Server, params: std.json.Value) !void {
|
fn handleDidOpen(self: *Server, params: std.json.Value) !void {
|
||||||
@@ -142,25 +166,17 @@ pub const Server = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handleDefinition(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
fn handleDefinition(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||||
const req_id = id orelse return;
|
const ctx = try self.extractRequest(id, params) orelse return;
|
||||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
const pos = extractPosition(params) orelse return;
|
||||||
|
const id_json = ctx.id_json;
|
||||||
const td = jsonGet(params, "textDocument") orelse return;
|
const uri = ctx.uri;
|
||||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
|
||||||
const position = jsonGet(params, "position") orelse return;
|
|
||||||
const line = std.math.cast(u32, jsonInt(jsonGet(position, "line") orelse return) orelse return) orelse return;
|
|
||||||
const character = std.math.cast(u32, jsonInt(jsonGet(position, "character") orelse return) orelse return) orelse return;
|
|
||||||
|
|
||||||
const analysis = self.sema_cache.get(uri) orelse {
|
const analysis = self.sema_cache.get(uri) orelse {
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
return try self.sendResponse(id_json, "null");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const offset = positionToOffset(analysis.source, line, character) orelse {
|
const offset = positionToOffset(analysis.source, pos.line, pos.character) orelse {
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
return try self.sendResponse(id_json, "null");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if cursor is on a qualified name (e.g. "std.print" or UFCS "list.append")
|
// Check if cursor is on a qualified name (e.g. "std.print" or UFCS "list.append")
|
||||||
@@ -206,8 +222,7 @@ pub const Server = struct {
|
|||||||
.end = .{ .line = 0, .character = 0 },
|
.end = .{ .line = 0, .character = 0 },
|
||||||
};
|
};
|
||||||
const loc_json = try lsp.locationJson(self.allocator, target_uri, range);
|
const loc_json = try lsp.locationJson(self.allocator, target_uri, range);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, loc_json);
|
try self.sendResponse(id_json, loc_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,30 +238,20 @@ pub const Server = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
try self.sendResponse(id_json, "null");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleHover(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
fn handleHover(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||||
const req_id = id orelse return;
|
const ctx = try self.extractRequest(id, params) orelse return;
|
||||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
const pos = extractPosition(params) orelse return;
|
||||||
|
const id_json = ctx.id_json;
|
||||||
|
|
||||||
const td = jsonGet(params, "textDocument") orelse return;
|
const analysis = self.sema_cache.get(ctx.uri) orelse {
|
||||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
return try self.sendResponse(id_json, "null");
|
||||||
const position = jsonGet(params, "position") orelse return;
|
|
||||||
const line = std.math.cast(u32, jsonInt(jsonGet(position, "line") orelse return) orelse return) orelse return;
|
|
||||||
const character = std.math.cast(u32, jsonInt(jsonGet(position, "character") orelse return) orelse return) orelse return;
|
|
||||||
|
|
||||||
const analysis = self.sema_cache.get(uri) orelse {
|
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const offset = positionToOffset(analysis.source, line, character) orelse {
|
const offset = positionToOffset(analysis.source, pos.line, pos.character) orelse {
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
return try self.sendResponse(id_json, "null");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if cursor is on a qualified name (e.g. std.print) — source-based, no AST
|
// Check if cursor is on a qualified name (e.g. std.print) — source-based, no AST
|
||||||
@@ -255,17 +260,13 @@ pub const Server = struct {
|
|||||||
if (analysis.import_map.get(qn.ns)) |import_path| {
|
if (analysis.import_map.get(qn.ns)) |import_path| {
|
||||||
if (try self.formatNamespaceMemberHover(analysis, qn.ns, qn.member, import_path)) |hover_text| {
|
if (try self.formatNamespaceMemberHover(analysis, qn.ns, qn.member, import_path)) |hover_text| {
|
||||||
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, hover_json);
|
return try self.sendResponse(id_json, hover_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Struct field hover (e.g. point.x)
|
// Struct field hover (e.g. point.x)
|
||||||
if (try self.formatStructFieldHover(analysis, qn.ns, qn.member)) |hover_text| {
|
if (try self.formatStructFieldHover(analysis, qn.ns, qn.member)) |hover_text| {
|
||||||
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, hover_json);
|
return try self.sendResponse(id_json, hover_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,9 +276,7 @@ pub const Server = struct {
|
|||||||
if (node.data == .enum_literal) {
|
if (node.data == .enum_literal) {
|
||||||
if (try self.formatEnumVariantHover(analysis, node.data.enum_literal.name)) |hover_text| {
|
if (try self.formatEnumVariantHover(analysis, node.data.enum_literal.name)) |hover_text| {
|
||||||
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, hover_json);
|
return try self.sendResponse(id_json, hover_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -309,26 +308,18 @@ pub const Server = struct {
|
|||||||
const source_for_hover = if (resolved) |r| r.source else analysis.source;
|
const source_for_hover = if (resolved) |r| r.source else analysis.source;
|
||||||
const hover_text = try formatSymbolHover(self.allocator, sym, analysis.root, source_for_hover);
|
const hover_text = try formatSymbolHover(self.allocator, sym, analysis.root, source_for_hover);
|
||||||
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
const hover_json = try lsp.hoverJson(self.allocator, hover_text);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, hover_json);
|
return try self.sendResponse(id_json, hover_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
try self.sendResponse(id_json, "null");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleDocumentSymbol(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
fn handleDocumentSymbol(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||||
const req_id = id orelse return;
|
const ctx = try self.extractRequest(id, params) orelse return;
|
||||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
const id_json = ctx.id_json;
|
||||||
|
|
||||||
const td = jsonGet(params, "textDocument") orelse return;
|
const analysis = self.sema_cache.get(ctx.uri) orelse {
|
||||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
return try self.sendResponse(id_json, "[]");
|
||||||
|
|
||||||
const analysis = self.sema_cache.get(uri) orelse {
|
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "[]");
|
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var doc_symbols = std.ArrayList(lsp.DocumentSymbol).empty;
|
var doc_symbols = std.ArrayList(lsp.DocumentSymbol).empty;
|
||||||
@@ -359,23 +350,18 @@ pub const Server = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const symbols_json = try lsp.documentSymbolsJson(self.allocator, doc_symbols.items);
|
const symbols_json = try lsp.documentSymbolsJson(self.allocator, doc_symbols.items);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, symbols_json);
|
try self.sendResponse(id_json, symbols_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleCompletion(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
fn handleCompletion(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||||
const req_id = id orelse return;
|
const ctx = try self.extractRequest(id, params) orelse return;
|
||||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
const pos = extractPosition(params) orelse return;
|
||||||
|
const id_json = ctx.id_json;
|
||||||
const td = jsonGet(params, "textDocument") orelse return;
|
const uri = ctx.uri;
|
||||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
|
||||||
const position = jsonGet(params, "position") orelse return;
|
|
||||||
const line = std.math.cast(u32, jsonInt(jsonGet(position, "line") orelse return) orelse return) orelse return;
|
|
||||||
const character = std.math.cast(u32, jsonInt(jsonGet(position, "character") orelse return) orelse return) orelse return;
|
|
||||||
|
|
||||||
// Check if cursor is after a dot (possibly with partial identifier typed)
|
// Check if cursor is after a dot (possibly with partial identifier typed)
|
||||||
if (self.documents.get(uri)) |doc| {
|
if (self.documents.get(uri)) |doc| {
|
||||||
if (positionToOffset(doc.text, line, character)) |off| {
|
if (positionToOffset(doc.text, pos.line, pos.character)) |off| {
|
||||||
// Scan backwards past any identifier characters to find a dot
|
// Scan backwards past any identifier characters to find a dot
|
||||||
var scan = off;
|
var scan = off;
|
||||||
while (scan > 0 and isIdentChar(doc.text[scan - 1])) scan -= 1;
|
while (scan > 0 and isIdentChar(doc.text[scan - 1])) scan -= 1;
|
||||||
@@ -388,9 +374,7 @@ pub const Server = struct {
|
|||||||
|
|
||||||
// Regular completion: all in-scope symbols + keywords
|
// Regular completion: all in-scope symbols + keywords
|
||||||
const analysis = self.sema_cache.get(uri) orelse {
|
const analysis = self.sema_cache.get(uri) orelse {
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "[]");
|
return try self.sendResponse(id_json, "[]");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var items = std.ArrayList(lsp.CompletionItem).empty;
|
var items = std.ArrayList(lsp.CompletionItem).empty;
|
||||||
@@ -449,8 +433,7 @@ pub const Server = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const items_json = try lsp.completionItemsJson(self.allocator, items.items);
|
const items_json = try lsp.completionItemsJson(self.allocator, items.items);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, items_json);
|
try self.sendResponse(id_json, items_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleDotCompletion(self: *Server, id_json: []const u8, uri: []const u8, text: []const u8, cursor_offset: u32) !void {
|
fn handleDotCompletion(self: *Server, id_json: []const u8, uri: []const u8, text: []const u8, cursor_offset: u32) !void {
|
||||||
@@ -475,8 +458,7 @@ pub const Server = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const items_json = try lsp.completionListJson(self.allocator, items.items);
|
const items_json = try lsp.completionListJson(self.allocator, items.items);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, items_json);
|
try self.sendResponse(id_json, items_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collectMemberCompletions(self: *Server, items: *std.ArrayList(lsp.CompletionItem), analysis: DocumentAnalysis, name: []const u8) !void {
|
fn collectMemberCompletions(self: *Server, items: *std.ArrayList(lsp.CompletionItem), analysis: DocumentAnalysis, name: []const u8) !void {
|
||||||
@@ -594,31 +576,21 @@ pub const Server = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handleSignatureHelp(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
fn handleSignatureHelp(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||||
const req_id = id orelse return;
|
const req = try self.extractRequest(id, params) orelse return;
|
||||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
const pos = extractPosition(params) orelse return;
|
||||||
|
const id_json = req.id_json;
|
||||||
const td = jsonGet(params, "textDocument") orelse return;
|
const uri = req.uri;
|
||||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
|
||||||
const position = jsonGet(params, "position") orelse return;
|
|
||||||
const line = std.math.cast(u32, jsonInt(jsonGet(position, "line") orelse return) orelse return) orelse return;
|
|
||||||
const character = std.math.cast(u32, jsonInt(jsonGet(position, "character") orelse return) orelse return) orelse return;
|
|
||||||
|
|
||||||
const doc = self.documents.get(uri) orelse {
|
const doc = self.documents.get(uri) orelse {
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
return try self.sendResponse(id_json, "null");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const offset = positionToOffset(doc.text, line, character) orelse {
|
const offset = positionToOffset(doc.text, pos.line, pos.character) orelse {
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
return try self.sendResponse(id_json, "null");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ctx = findCallContext(doc.text, offset) orelse {
|
const call_ctx = findCallContext(doc.text, offset) orelse {
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
return try self.sendResponse(id_json, "null");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Built-in function signatures
|
// Built-in function signatures
|
||||||
@@ -636,25 +608,21 @@ pub const Server = struct {
|
|||||||
.{ .name = "write", .label = "write(str: string) -> void", .params = &.{"str: string"} },
|
.{ .name = "write", .label = "write(str: string) -> void", .params = &.{"str: string"} },
|
||||||
};
|
};
|
||||||
for (&builtin_sigs) |b| {
|
for (&builtin_sigs) |b| {
|
||||||
const matches = std.mem.eql(u8, ctx.name, b.name) or
|
const matches = std.mem.eql(u8, call_ctx.name, b.name) or
|
||||||
(std.mem.startsWith(u8, ctx.name, "std.") and std.mem.eql(u8, ctx.name[4..], b.name));
|
(std.mem.startsWith(u8, call_ctx.name, "std.") and std.mem.eql(u8, call_ctx.name[4..], b.name));
|
||||||
if (matches) {
|
if (matches) {
|
||||||
const sig_json = try lsp.signatureHelpJson(self.allocator, b.label, b.params, ctx.active_param);
|
const sig_json = try lsp.signatureHelpJson(self.allocator, b.label, b.params, call_ctx.active_param);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, sig_json);
|
return try self.sendResponse(id_json, sig_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up function in sema cache
|
// Look up function in sema cache
|
||||||
const analysis = self.sema_cache.get(uri) orelse {
|
const analysis = self.sema_cache.get(uri) orelse {
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
return try self.sendResponse(id_json, "null");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try to find the function — either at top level or inside a namespace
|
// Try to find the function — either at top level or inside a namespace
|
||||||
const fn_node = findFnDeclByName(analysis, ctx.name);
|
const fn_node = findFnDeclByName(analysis, call_ctx.name);
|
||||||
|
|
||||||
if (fn_node) |fd| {
|
if (fn_node) |fd| {
|
||||||
var label_buf = std.ArrayList(u8).empty;
|
var label_buf = std.ArrayList(u8).empty;
|
||||||
@@ -684,27 +652,19 @@ pub const Server = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sig_json = try lsp.signatureHelpJson(self.allocator, label_buf.items, param_labels.items, ctx.active_param);
|
const sig_json = try lsp.signatureHelpJson(self.allocator, label_buf.items, param_labels.items, call_ctx.active_param);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, sig_json);
|
return try self.sendResponse(id_json, sig_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "null");
|
try self.sendResponse(id_json, "null");
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleSemanticTokens(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
fn handleSemanticTokens(self: *Server, id: ?std.json.Value, params: std.json.Value) !void {
|
||||||
const req_id = id orelse return;
|
const ctx = try self.extractRequest(id, params) orelse return;
|
||||||
const id_json = try lsp.valueToJson(self.allocator, req_id);
|
const id_json = ctx.id_json;
|
||||||
|
|
||||||
const td = jsonGet(params, "textDocument") orelse return;
|
const analysis = self.sema_cache.get(ctx.uri) orelse {
|
||||||
const uri = jsonStr(jsonGet(td, "uri") orelse return) orelse return;
|
return try self.sendResponse(id_json, "{\"data\":[]}");
|
||||||
|
|
||||||
const analysis = self.sema_cache.get(uri) orelse {
|
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, "{\"data\":[]}");
|
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var data = std.ArrayList(u32).empty;
|
var data = std.ArrayList(u32).empty;
|
||||||
@@ -727,8 +687,7 @@ pub const Server = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result_json = try lsp.semanticTokensJson(self.allocator, data.items);
|
const result_json = try lsp.semanticTokensJson(self.allocator, data.items);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, result_json);
|
try self.sendResponse(id_json, result_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classifyToken(tok: sx.token.Token, analysis: DocumentAnalysis) ?u32 {
|
fn classifyToken(tok: sx.token.Token, analysis: DocumentAnalysis) ?u32 {
|
||||||
@@ -1308,8 +1267,7 @@ pub const Server = struct {
|
|||||||
else
|
else
|
||||||
uri;
|
uri;
|
||||||
const loc_json = try lsp.locationJson(self.allocator, target_uri, range);
|
const loc_json = try lsp.locationJson(self.allocator, target_uri, range);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, loc_json);
|
try self.sendResponse(id_json, loc_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1355,8 +1313,7 @@ pub const Server = struct {
|
|||||||
const range = spanToRange(imp_source, target.span);
|
const range = spanToRange(imp_source, target.span);
|
||||||
const target_uri = try std.fmt.allocPrint(self.allocator, "file://{s}", .{import_path});
|
const target_uri = try std.fmt.allocPrint(self.allocator, "file://{s}", .{import_path});
|
||||||
const loc_json = try lsp.locationJson(self.allocator, target_uri, range);
|
const loc_json = try lsp.locationJson(self.allocator, target_uri, range);
|
||||||
const resp = try lsp.jsonRpcResponse(self.allocator, id_json, loc_json);
|
try self.sendResponse(id_json, loc_json);
|
||||||
try self.transport.writeMessage(resp);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
src/main.zig
22
src/main.zig
@@ -115,11 +115,11 @@ fn readSource(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8)
|
|||||||
return try allocator.dupeZ(u8, source_bytes);
|
return try allocator.dupeZ(u8, source_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emitIR(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8) !void {
|
fn compilePipeline(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8) !sx.core.Compilation {
|
||||||
const source = try readSource(allocator, io, input_path);
|
const source = try readSource(allocator, io, input_path);
|
||||||
|
|
||||||
var comp = sx.core.Compilation.init(allocator, io, input_path, source);
|
var comp = sx.core.Compilation.init(allocator, io, input_path, source);
|
||||||
defer comp.deinit();
|
errdefer comp.deinit();
|
||||||
|
|
||||||
comp.parse() catch { comp.renderErrors(); return error.CompileError; };
|
comp.parse() catch { comp.renderErrors(); return error.CompileError; };
|
||||||
comp.resolveImports() catch { comp.renderErrors(); return error.CompileError; };
|
comp.resolveImports() catch { comp.renderErrors(); return error.CompileError; };
|
||||||
@@ -127,21 +127,21 @@ fn emitIR(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8) !voi
|
|||||||
|
|
||||||
var cg = &comp.cg.?;
|
var cg = &comp.cg.?;
|
||||||
cg.verify() catch { comp.renderErrors(); return error.CompileError; };
|
cg.verify() catch { comp.renderErrors(); return error.CompileError; };
|
||||||
cg.printIR();
|
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emitIR(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8) !void {
|
||||||
|
var comp = try compilePipeline(allocator, io, input_path);
|
||||||
|
defer comp.deinit();
|
||||||
|
comp.cg.?.printIR();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, output_path: []const u8) !void {
|
fn compile(allocator: std.mem.Allocator, io: std.Io, input_path: []const u8, output_path: []const u8) !void {
|
||||||
const source = try readSource(allocator, io, input_path);
|
var comp = try compilePipeline(allocator, io, input_path);
|
||||||
|
|
||||||
var comp = sx.core.Compilation.init(allocator, io, input_path, source);
|
|
||||||
defer comp.deinit();
|
defer comp.deinit();
|
||||||
|
|
||||||
comp.parse() catch { comp.renderErrors(); return error.CompileError; };
|
|
||||||
comp.resolveImports() catch { comp.renderErrors(); return error.CompileError; };
|
|
||||||
comp.generateCode() catch { comp.renderErrors(); return error.CompileError; };
|
|
||||||
|
|
||||||
var cg = &comp.cg.?;
|
var cg = &comp.cg.?;
|
||||||
cg.verify() catch { comp.renderErrors(); return error.CompileError; };
|
|
||||||
|
|
||||||
// Emit object file
|
// Emit object file
|
||||||
const obj_path = try std.fmt.allocPrintSentinel(allocator, "{s}.o", .{output_path}, 0);
|
const obj_path = try std.fmt.allocPrintSentinel(allocator, "{s}.o", .{output_path}, 0);
|
||||||
|
|||||||
@@ -169,6 +169,16 @@ pub const Parser = struct {
|
|||||||
|
|
||||||
// Otherwise it's a constant expression
|
// Otherwise it's a constant expression
|
||||||
const value = try self.parseExpr();
|
const value = try self.parseExpr();
|
||||||
|
|
||||||
|
// name :: type_expr #builtin; — builtin with type annotation
|
||||||
|
if (self.current.tag == .hash_builtin) {
|
||||||
|
const bi_start = self.current.loc.start;
|
||||||
|
self.advance();
|
||||||
|
try self.expect(.semicolon);
|
||||||
|
const bi = try self.createNode(bi_start, .{ .builtin_expr = {} });
|
||||||
|
return try self.createNode(start_pos, .{ .const_decl = .{ .name = name, .type_annotation = value, .value = bi } });
|
||||||
|
}
|
||||||
|
|
||||||
try self.expect(.semicolon);
|
try self.expect(.semicolon);
|
||||||
return try self.createNode(start_pos, .{ .const_decl = .{ .name = name, .type_annotation = null, .value = value } });
|
return try self.createNode(start_pos, .{ .const_decl = .{ .name = name, .type_annotation = null, .value = value } });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,10 +245,8 @@ pub const Analyzer = struct {
|
|||||||
const elem_name = elem_type.displayName(self.allocator) catch return .void_type;
|
const elem_name = elem_type.displayName(self.allocator) catch return .void_type;
|
||||||
return .{ .many_pointer_type = .{ .element_name = elem_name } };
|
return .{ .many_pointer_type = .{ .element_name = elem_name } };
|
||||||
}
|
}
|
||||||
// Parameterized type: Vector(N, T) or generic struct
|
// Sema does not resolve generics; codegen handles instantiation
|
||||||
if (tn.data == .parameterized_type_expr) {
|
if (tn.data == .parameterized_type_expr) {
|
||||||
// For now, skip generic instantiation — just return void_type
|
|
||||||
// (will be extended when generic support is added to sema)
|
|
||||||
return .void_type;
|
return .void_type;
|
||||||
}
|
}
|
||||||
// type_expr or identifier — check aliases, enums, structs
|
// type_expr or identifier — check aliases, enums, structs
|
||||||
|
|||||||
Reference in New Issue
Block a user