This commit is contained in:
agra
2026-02-22 17:24:04 +02:00
parent 775dcb44cc
commit d3e574eae5
38 changed files with 16135 additions and 33 deletions

View File

@@ -49,9 +49,14 @@ pub const Parser = struct {
fn parseTopLevel(self: *Parser) anyerror!*Node {
const start = self.current.loc.start;
// Top-level flat import: #import "path";
// Top-level flat import: #import "path"; or #import c { ... };
if (self.current.tag == .hash_import) {
self.advance();
// Check for #import c { ... } (C import block)
if (self.current.tag == .identifier and std.mem.eql(u8, self.tokenSlice(self.current), "c") and self.peekNext() == .l_brace) {
self.advance(); // consume 'c'
return self.parseCImportBlock(start, null);
}
if (self.current.tag != .string_literal) {
return self.fail("expected string path after '#import'");
}
@@ -105,9 +110,14 @@ pub const Parser = struct {
// After `::`
// Could be: #run expr, enum { ... }, (params) -> type { body }, or expr;
// Namespaced import: name :: #import "path";
// Namespaced import: name :: #import "path"; or name :: #import c { ... };
if (self.current.tag == .hash_import) {
self.advance();
// Check for name :: #import c { ... }
if (self.current.tag == .identifier and std.mem.eql(u8, self.tokenSlice(self.current), "c") and self.peekNext() == .l_brace) {
self.advance(); // consume 'c'
return self.parseCImportBlock(start_pos, name);
}
if (self.current.tag != .string_literal) {
return self.fail("expected string path after '#import'");
}
@@ -232,6 +242,58 @@ pub const Parser = struct {
return try self.createNode(start_pos, .{ .const_decl = .{ .name = name, .type_annotation = null, .value = value } });
}
fn parseCImportBlock(self: *Parser, start: u32, name: ?[]const u8) anyerror!*Node {
try self.expect(.l_brace);
var includes = std.ArrayList([]const u8).empty;
var sources = std.ArrayList([]const u8).empty;
var defines = std.ArrayList([]const u8).empty;
var flags = std.ArrayList([]const u8).empty;
while (self.current.tag != .r_brace and self.current.tag != .eof) {
if (self.current.tag == .hash_include) {
self.advance();
if (self.current.tag != .string_literal) return self.fail("expected string after '#include'");
const raw = self.tokenSlice(self.current);
try includes.append(self.allocator, raw[1 .. raw.len - 1]);
self.advance();
try self.expect(.semicolon);
} else if (self.current.tag == .hash_source) {
self.advance();
if (self.current.tag != .string_literal) return self.fail("expected string after '#source'");
const raw = self.tokenSlice(self.current);
try sources.append(self.allocator, raw[1 .. raw.len - 1]);
self.advance();
try self.expect(.semicolon);
} else if (self.current.tag == .hash_define) {
self.advance();
if (self.current.tag != .string_literal) return self.fail("expected string after '#define'");
const raw = self.tokenSlice(self.current);
try defines.append(self.allocator, raw[1 .. raw.len - 1]);
self.advance();
try self.expect(.semicolon);
} else if (self.current.tag == .hash_flags) {
self.advance();
if (self.current.tag != .string_literal) return self.fail("expected string after '#flags'");
const raw = self.tokenSlice(self.current);
try flags.append(self.allocator, raw[1 .. raw.len - 1]);
self.advance();
try self.expect(.semicolon);
} else {
return self.fail("unexpected token inside '#import c { ... }'");
}
}
try self.expect(.r_brace);
try self.expect(.semicolon);
return try self.createNode(start, .{ .c_import_decl = .{
.includes = try includes.toOwnedSlice(self.allocator),
.sources = try sources.toOwnedSlice(self.allocator),
.defines = try defines.toOwnedSlice(self.allocator),
.flags = try flags.toOwnedSlice(self.allocator),
.name = name,
} });
}
fn parseTypedBinding(self: *Parser, name: []const u8, start_pos: u32) anyerror!*Node {
// After `name :`
// Parse type