This commit is contained in:
David Gonzalez Martin 2025-04-29 06:29:32 -06:00
parent 0eee2a4ff3
commit 07c2ea7da0
5 changed files with 742 additions and 293 deletions

File diff suppressed because it is too large Load Diff

View File

@ -586,11 +586,32 @@ CompileOptions = struct
silent: u1, silent: u1,
} }
ScopeKind = enum
{
global,
function,
local,
for_each,
macro_declaration,
macro_instantiation_function,
}
Scope = struct
{
parent: &Scope,
line: u32,
column: u32,
kind: ScopeKind,
}
Type = struct;
TypeId = enum TypeId = enum
{ {
void, void,
noreturn, noreturn,
integer, integer,
function,
} }
TypeInteger = struct TypeInteger = struct
@ -599,9 +620,23 @@ TypeInteger = struct
signed: u1, signed: u1,
} }
CallingConvention = enum
{
c,
}
TypeFunction = struct
{
semantic_return_type: &Type,
semantic_argument_types: []&Type,
calling_convention: CallingConvention,
is_variable_arguments: u1,
}
TypeContent = union TypeContent = union
{ {
integer: TypeInteger, integer: TypeInteger,
function: TypeFunction,
} }
Type = struct Type = struct
@ -630,11 +665,36 @@ Module = struct
arena: &Arena, arena: &Arena,
base_type_allocation: &Type, base_type_allocation: &Type,
void_value: &Value, void_value: &Value,
// Parser data // Parser data start
content: []u8, content: []u8,
offset: u64, offset: u64,
line_offset: u64, line_offset: u64,
line_character_offset: u64, line_character_offset: u64,
// Parser data end
scope: Scope,
}
ModuleCheckpoint = struct
{
offset: u64,
line_offset: u64,
line_character_offset: u64,
}
get_checkpoint = fn (module: &Module) ModuleCheckpoint
{
return {
.offset = module.offset,
.line_offset = module.line_offset,
.line_character_offset = module.line_character_offset,
};
}
set_checkpoint = fn (module: &Module, checkpoint: ModuleCheckpoint) void
{
module.offset = checkpoint.offset;
module.line_offset = checkpoint.line_offset;
module.line_character_offset = checkpoint.line_character_offset;
} }
module_integer_type = fn (module: &Module, integer: TypeInteger) &Type module_integer_type = fn (module: &Module, integer: TypeInteger) &Type
@ -655,6 +715,13 @@ module_noreturn_type = fn (module: &Module) &Type
return module_void_type(module) + 1; return module_void_type(module) + 1;
} }
left_bracket: u8 = '[';
right_bracket: u8 = ']';
left_parenthesis: u8 = '(';
right_parenthesis: u8 = ')';
left_brace: u8 = '{';
right_brace: u8 = '}';
is_space = fn (ch: u8) u1 is_space = fn (ch: u8) u1
{ {
return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r'; return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r';
@ -697,7 +764,7 @@ is_hex = fn (ch: u8) u1
is_identifier_start = fn (ch: u8) u1 is_identifier_start = fn (ch: u8) u1
{ {
return (ch >= 'a' and ch >= 'z') or (ch >= 'A' and ch <= 'Z') or ch == '_'; return (ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or ch == '_';
} }
is_identifier = fn (ch: u8) u1 is_identifier = fn (ch: u8) u1
@ -817,8 +884,351 @@ parse_identifier = fn (module: &Module) []u8
return result; return result;
} }
parse_type = fn (module: &Module) &Type
{
}
ValueBuilder = struct
{
foo: u32,
}
parse_value = fn (module: &Module, scope: &Scope, v: ValueBuilder) &Value
{
}
GlobalKeyword = enum
{
export,
extern,
}
GlobalKind = enum
{
bits,
enum,
fn,
macro,
struct,
typealias,
union,
}
FunctionKeyword = enum
{
cc,
}
InlineBehavior = enum
{
default,
always_inline,
no_inline,
inline_hint,
}
FunctionAttributes = struct
{
inline_behavior: InlineBehavior,
naked: u1,
}
new_type_array = fn (module: &Module, count: u64) []&Type
{
>result = arena_allocate[&Type](module.arena, count);
return result[..count];
}
new_type = fn (module: &Module) &Type
{
>result = arena_allocate[Type](module.arena, 1);
return result;
}
new_value_array = fn (module: &Module, count: u64) []&Value
{
>result = arena_allocate[&Value](module.arena, count);
return result[..count];
}
new_value = fn (module: &Module) &Value
{
>result = arena_allocate[Value](module.arena, 1);
return result;
}
allocate_value_array = fn (module: &Module, stack_array: []&Value) []&Value
{
>result = new_value_array(module, stack_array.length);
memcpy(#pointer_cast(result.pointer), #pointer_cast(stack_array.pointer), stack_array.length * #byte_size(&Value));
}
allocate_type_array = fn (module: &Module, stack_array: []&Type) []&Type
{
>result = new_type_array(module, stack_array.length);
memcpy(#pointer_cast(result.pointer), #pointer_cast(stack_array.pointer), stack_array.length * #byte_size(&Type));
}
parse = fn (module: &Module) void parse = fn (module: &Module) void
{ {
while (1)
{
skip_space(module);
if (module.offset == module.content.length)
{
break;
}
>is_export: u1 = 0;
>is_extern: u1 = 0;
>global_line = get_line(module);
>global_column = get_column(module);
if (consume_character_if_match(module, left_bracket))
{
while (module.offset < module.content.length)
{
>global_keyword_string = parse_identifier(module);
>global_keyword_s2e = #string_to_enum(GlobalKeyword, global_keyword_string);
if (!global_keyword_s2e.is_valid)
{
report_error();
}
>global_keyword = global_keyword_s2e.enum_value;
switch (global_keyword)
{
.export => { is_export = 1; }
.extern => { is_extern = 1; }
}
if (consume_character_if_match(module, right_bracket))
{
break;
}
report_error();
}
skip_space(module);
}
>global_name = parse_identifier(module);
// TODO: check if the name is repeated in global namespace
skip_space(module);
>global_type: &Type = zero;
if (consume_character_if_match(module, ':'))
{
skip_space(module);
global_type = parse_type(module);
skip_space(module);
}
expect_character(module, '=');
skip_space(module);
>has_global_keyword: u1 = 0;
if (is_identifier_start(module.content[module.offset]))
{
>checkpoint = get_checkpoint(module);
>global_string = parse_identifier(module);
skip_space(module);
>global_kind_s2e = #string_to_enum(GlobalKind, global_string);
if (global_kind_s2e.is_valid)
{
>global_kind = global_kind_s2e.enum_value;
switch (global_kind)
{
.bits => {
#trap();
},
.enum => {
#trap();
},
.fn => {
>calling_convention: CallingConvention = .c;
>function_attributes: FunctionAttributes = zero;
>is_variable_arguments: u1 = 0;
if (consume_character_if_match(module, left_bracket))
{
while (module.offset < module.content.length)
{
>function_identifier = parse_identifier(module);
>function_keyword_s2e = #string_to_enum(FunctionKeyword, function_identifier);
if (function_keyword_s2e.is_valid)
{
>function_keyword = function_keyword_s2e.enum_value;
skip_space(module);
switch (function_keyword)
{
.cc => {
expect_character(module, left_parenthesis);
skip_space(module);
>calling_convention_string = parse_identifier(module);
>calling_convention_s2e = #string_to_enum(CallingConvention, calling_convention_string);
if (calling_convention_s2e.is_valid)
{
calling_convention = calling_convention_s2e.enum_value;
skip_space(module);
expect_character(module, right_parenthesis);
}
else
{
report_error();
}
},
}
skip_space(module);
if (consume_character_if_match(module, right_bracket))
{
break;
}
else
{
report_error();
}
}
else
{
report_error();
}
}
}
skip_space(module);
expect_character(module, left_parenthesis);
>semantic_argument_type_buffer: [64]&Type = undefined;
>semantic_argument_name_buffer: [64][]u8 = undefined;
>semantic_argument_count: u64 = 0;
while (module.offset < module.content.length)
{
skip_space(module);
if (consume_character_if_match(module, '.'))
{
expect_character(module, '.');
expect_character(module, '.');
skip_space(module);
expect_character(module, right_parenthesis);
is_variable_arguments = 1;
break;
}
if (consume_character_if_match(module, right_parenthesis))
{
break;
}
>argument_name = parse_identifier(module);
semantic_argument_name_buffer[semantic_argument_count] = argument_name;
skip_space(module);
expect_character(module, ':');
skip_space(module);
>argument_type = parse_type(module);
semantic_argument_type_buffer[semantic_argument_count] = argument_type;
skip_space(module);
if (consume_character_if_match(module, ','))
{
skip_space(module);
}
semantic_argument_count += 1;
}
skip_space(module);
>return_type = parse_type(module);
>argument_types: []&Type = zero;
if (semantic_argument_count != 0)
{
argument_types = allocate_type_array(module, semantic_argument_type_buffer[..semantic_argument_count]);
}
skip_space(module);
>is_declaration = consume_character_if_match(module, ';');
>function_type = new_type(module);
function_type.& = {
.content = {
.function = {
.semantic_return_type = return_type,
.semantic_argument_types = argument_types,
.calling_convention = calling_convention,
.is_variable_arguments = is_variable_arguments,
},
},
.id = .function,
.name = "",
};
>storage = new_value(module);
#trap();
},
.macro => {
#trap();
},
.struct => {
#trap();
},
.typealias => {
#trap();
},
.union => {
#trap();
},
}
}
else
{
set_checkpoint(module, checkpoint);
}
}
if (!has_global_keyword)
{
>v = parse_value(module, &module.scope, zero);
skip_space(module);
expect_character(module, ';');
#trap();
}
}
} }
emit = fn (module: &Module) void emit = fn (module: &Module) void
@ -894,22 +1304,23 @@ compile = fn (arena: &Arena, options: CompileOptions) void
.name = "noreturn", .name = "noreturn",
}; };
>void_value = arena_allocate[Value](arena, 1);
void_value.& = {
.type = void_type,
.id = .infer_or_ignore,
};
>module: Module = { >module: Module = {
.arena = arena, .arena = arena,
.base_type_allocation = base_type_allocation, .base_type_allocation = base_type_allocation,
.void_value = void_value, .void_value = undefined,
.content = options.content, .content = options.content,
.offset = 0, .offset = 0,
.line_offset = 0, .line_offset = 0,
.line_character_offset = 0, .line_character_offset = 0,
}; };
>void_value = new_value(&module);
void_value.& = {
.type = void_type,
.id = .infer_or_ignore,
};
parse(&module); parse(&module);
emit(&module); emit(&module);
} }

View File

@ -332,4 +332,6 @@ const names = &[_][]const u8{
"generic_pointer_macro", "generic_pointer_macro",
"break_continue", "break_continue",
"noreturn_macro", "noreturn_macro",
"self_referential_struct",
"forward_declared_type",
}; };

View File

@ -0,0 +1,17 @@
T = struct;
Foo = struct
{
t: &T,
}
T = struct
{
f: Foo,
}
[export] main = fn [cc(c)] () s32
{
>t: T = zero;
t.f.t = &t;
return 0;
}

View File

@ -0,0 +1,11 @@
S = struct
{
self: &S,
}
[export] main = fn [cc(c)] () s32
{
>s: S = zero;
s.self = &s;
return 0;
}