wip
This commit is contained in:
parent
0eee2a4ff3
commit
f48829312b
File diff suppressed because it is too large
Load Diff
427
src/compiler.bbb
427
src/compiler.bbb
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -332,4 +332,7 @@ const names = &[_][]const u8{
|
|||||||
"generic_pointer_macro",
|
"generic_pointer_macro",
|
||||||
"break_continue",
|
"break_continue",
|
||||||
"noreturn_macro",
|
"noreturn_macro",
|
||||||
|
"self_referential_struct",
|
||||||
|
"forward_declared_type",
|
||||||
|
"generic_pointer_array",
|
||||||
};
|
};
|
||||||
|
17
tests/forward_declared_type.bbb
Normal file
17
tests/forward_declared_type.bbb
Normal 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;
|
||||||
|
}
|
14
tests/generic_pointer_array.bbb
Normal file
14
tests/generic_pointer_array.bbb
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
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 = foo[&u8](&some_var, 1);
|
||||||
|
if (#int_from_pointer(result.pointer) != 0xaaaaaaaaaaaaaaaa) #trap();
|
||||||
|
if (result.length != 1) #trap();
|
||||||
|
return 0;
|
||||||
|
}
|
11
tests/self_referential_struct.bbb
Normal file
11
tests/self_referential_struct.bbb
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
S = struct
|
||||||
|
{
|
||||||
|
self: &S,
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>s: S = zero;
|
||||||
|
s.self = &s;
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user