Compare commits

..

No commits in common. "self-referential-struct" and "main" have entirely different histories.

6 changed files with 379 additions and 1279 deletions

File diff suppressed because it is too large Load Diff

View File

@ -586,38 +586,11 @@ CompileOptions = struct
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;
Value = struct;
Statement = struct;
Local = struct;
Global = struct;
Block = struct;
TypeId = enum
{
void,
noreturn,
integer,
function,
pointer,
}
TypeInteger = struct
@ -626,30 +599,9 @@ TypeInteger = struct
signed: u1,
}
CallingConvention = enum
{
c,
}
TypeFunction = struct
{
semantic_return_type: &Type,
semantic_argument_types: []&Type,
calling_convention: CallingConvention,
is_variable_arguments: u1,
}
TypePointer = struct
{
element_type: &Type,
next_pointer_type: &Type,
}
TypeContent = union
{
integer: TypeInteger,
function: TypeFunction,
pointer: TypePointer,
}
Type = struct
@ -662,108 +614,14 @@ Type = struct
ValueId = enum
{
infer_or_ignore,
external_function,
function,
}
InlineBehavior = enum
{
default,
always_inline,
no_inline,
inline_hint,
}
FunctionAttributes = struct
{
inline_behavior: InlineBehavior,
naked: u1,
}
ValueFunction = struct
{
arguments: []&Local,
main_block: &Block,
scope: Scope,
attributes: FunctionAttributes,
}
ValueContent = union
{
function: ValueFunction,
}
Variable = struct
{
storage: &Value,
initial_value: &Value,
type: &Type,
scope: &Scope,
name: []u8,
line: u32,
column: u32,
}
Value = struct
{
content: ValueContent,
type: &Type,
id: ValueId,
}
Local = struct
{
variable: Variable,
argument_index: u32,
next: &Local,
}
local_is_argument = fn (local: &Local) u1
{
return local.argument_index == #integer_max(u32);
}
Block = struct
{
first_local: &Local,
last_local: &Local,
first_statement: &Statement,
last_statement: &Statement,
scope: Scope,
}
StatementId = enum
{
local,
}
StatementContent = union
{
local: &Local,
}
Statement = struct
{
content: StatementContent,
next: &Statement,
line: u32,
column: u32,
id: StatementId,
}
Linkage = enum
{
external,
internal,
}
Global = struct
{
variable: Variable,
linkage: Linkage,
next: &Global,
}
i128_offset: u64 = 64 * 2;
void_offset: u64 = i128_offset + 2;
@ -772,144 +630,11 @@ Module = struct
arena: &Arena,
base_type_allocation: &Type,
void_value: &Value,
// Parser data start
// Parser data
content: []u8,
offset: u64,
line_offset: u64,
line_character_offset: u64,
// Parser data end
scope: Scope,
first_global: &Global,
last_global: &Global,
first_pointer_type: &Type,
current_function: &Global,
}
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;
}
new_local = fn (module: &Module) &Local
{
>result = arena_allocate[Local](module.arena, 1);
return result;
}
new_global = fn (module: &Module) &Global
{
>result = arena_allocate[Global](module.arena, 1);
if (module.last_global)
{
assert(!module.last_global.next);
module.last_global.next = result;
module.last_global = result;
}
else
{
module.first_global = result;
module.last_global = result;
}
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));
}
get_pointer_type = fn (module: &Module, element_type: &Type) &Type
{
>it = module.first_pointer_type;
if (it)
{
while (1)
{
if (it.content.pointer.element_type == element_type)
{
return it;
}
if (!it.content.pointer.next_pointer_type)
{
break;
}
}
}
>result_type = new_type(module);
result_type.& = {
.content = {
.pointer = {
.element_type = element_type,
.next_pointer_type = zero,
},
},
.id = .pointer,
.name = arena_join_string(module.arena, [ "&", element_type.name ][..]),
};
if (it)
{
assert(!it.content.pointer.next_pointer_type);
it.content.pointer.next_pointer_type = result_type;
}
else if (!module.first_pointer_type)
{
module.first_pointer_type = result_type;
}
return result_type;
}
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
@ -930,13 +655,6 @@ module_noreturn_type = fn (module: &Module) &Type
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
{
return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r';
@ -979,7 +697,7 @@ is_hex = 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
@ -1099,355 +817,8 @@ parse_identifier = fn (module: &Module) []u8
return result;
}
parse_type = fn (module: &Module) &Type
{
}
ValueBuilder = struct
{
foo: u32,
}
parse_value = fn (module: &Module, scope: &Scope, v: ValueBuilder) &Value
{
#trap();
}
parse_block = fn (module: &Module, scope: &Scope) &Block
{
#trap();
}
GlobalKeyword = enum
{
export,
extern,
}
GlobalKind = enum
{
bits,
enum,
fn,
macro,
struct,
typealias,
union,
}
FunctionKeyword = enum
{
cc,
}
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);
storage.& = {
.content = undefined,
.type = get_pointer_type(module, function_type),
.id = .external_function, // If not a function declaration, later updated
};
>global = new_global(module);
global.& = {
.variable = {
.storage = storage,
.initial_value = zero,
.type = function_type,
.name = global_name,
.line = global_line,
.column = global_column,
.scope = &module.scope,
},
.linkage = #select(is_export or is_extern, .external, .internal),
.next = zero,
};
module.current_function = global;
if (!is_declaration)
{
storage.content = {
.function = {
.arguments = zero,
.main_block = zero,
.scope = {
.parent = &module.scope,
.line = global_line,
.column = global_column,
.kind = .function,
},
.attributes = function_attributes,
},
};
storage.id = .function;
if (semantic_argument_count != 0)
{
#trap();
}
storage.content.function.main_block = parse_block(module, &module.scope);
}
// END OF SCOPE
module.current_function = zero;
#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
@ -1523,31 +894,20 @@ compile = fn (arena: &Arena, options: CompileOptions) void
.name = "noreturn",
};
>void_value = arena_allocate[Value](arena, 1);
void_value.& = {
.type = void_type,
.id = .infer_or_ignore,
};
>module: Module = {
.arena = arena,
.base_type_allocation = base_type_allocation,
.void_value = undefined,
.void_value = void_value,
.content = options.content,
.offset = 0,
.line_offset = 0,
.line_character_offset = 0,
.scope = {
.parent = zero,
.line = 0,
.column = 0,
.kind = .global,
},
.first_global = zero,
.last_global = zero,
.first_pointer_type = zero,
.current_function = zero,
};
>void_value = new_value(&module);
void_value.& = {
.type = void_type,
.id = .infer_or_ignore,
};
parse(&module);

View File

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

View File

@ -1,17 +0,0 @@
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

@ -1,14 +0,0 @@
foo = macro[T](addr: &u64, count: u64) []T
{
>pointer: &T = #pointer_cast(addr);
return pointer[..count];
}
[export] main = fn [cc(c)] () s32
{
>some_var: u64 = 0xaaaaaaaaaaaaaaaa;
>result: []&u8 = foo[&u8](&some_var, 1);
if (#int_from_pointer(result.pointer) != 0xaaaaaaaaaaaaaaaa) #trap();
if (result.length != 1) #trap();
return 0;
}

View File

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