wip
This commit is contained in:
parent
04ca049e6c
commit
98ecaf57cd
326
src/compiler.bbb
326
src/compiler.bbb
@ -1417,6 +1417,10 @@ get_byte_size = fn (type: &Type) u64
|
|||||||
assert(byte_count == 1 or byte_count == 2 or byte_count == 4 or byte_count == 8 or byte_count == 16);
|
assert(byte_count == 1 or byte_count == 2 or byte_count == 4 or byte_count == 8 or byte_count == 16);
|
||||||
return byte_count;
|
return byte_count;
|
||||||
},
|
},
|
||||||
|
.pointer =>
|
||||||
|
{
|
||||||
|
return 8;
|
||||||
|
},
|
||||||
else =>
|
else =>
|
||||||
{
|
{
|
||||||
#trap();
|
#trap();
|
||||||
@ -1449,6 +1453,7 @@ get_byte_alignment = fn (type: &Type) u32
|
|||||||
assert(aligned_byte_count == 1 or aligned_byte_count == 2 or aligned_byte_count == 4 or aligned_byte_count == 8 or aligned_byte_count == 16);
|
assert(aligned_byte_count == 1 or aligned_byte_count == 2 or aligned_byte_count == 4 or aligned_byte_count == 8 or aligned_byte_count == 16);
|
||||||
return aligned_byte_count;
|
return aligned_byte_count;
|
||||||
},
|
},
|
||||||
|
.pointer => { return 8; },
|
||||||
else =>
|
else =>
|
||||||
{
|
{
|
||||||
#trap();
|
#trap();
|
||||||
@ -1514,6 +1519,8 @@ ValueId = enum
|
|||||||
variable,
|
variable,
|
||||||
local,
|
local,
|
||||||
unary_type,
|
unary_type,
|
||||||
|
macro_reference,
|
||||||
|
call,
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueConstantInteger = struct
|
ValueConstantInteger = struct
|
||||||
@ -1673,6 +1680,13 @@ ValueBinary = struct
|
|||||||
id: BinaryId,
|
id: BinaryId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueCall = struct
|
||||||
|
{
|
||||||
|
callable: &Value,
|
||||||
|
arguments: []&Value,
|
||||||
|
function_type: &Type,
|
||||||
|
}
|
||||||
|
|
||||||
ValueContent = union
|
ValueContent = union
|
||||||
{
|
{
|
||||||
constant_integer: ValueConstantInteger,
|
constant_integer: ValueConstantInteger,
|
||||||
@ -1681,6 +1695,7 @@ ValueContent = union
|
|||||||
binary: ValueBinary,
|
binary: ValueBinary,
|
||||||
variable: &Variable,
|
variable: &Variable,
|
||||||
unary_type: ValueUnaryType,
|
unary_type: ValueUnaryType,
|
||||||
|
call: ValueCall,
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueKind = enum
|
ValueKind = enum
|
||||||
@ -2321,8 +2336,19 @@ Statement = struct
|
|||||||
scope_to_block = fn (scope: &Scope) &Block
|
scope_to_block = fn (scope: &Scope) &Block
|
||||||
{
|
{
|
||||||
assert(scope.kind == .local);
|
assert(scope.kind == .local);
|
||||||
>result: &Block = #field_parent_pointer(scope, "scope");
|
return #field_parent_pointer(scope, "scope");
|
||||||
return result;
|
}
|
||||||
|
|
||||||
|
scope_to_function = fn (scope: &Scope) &ValueFunction
|
||||||
|
{
|
||||||
|
assert(scope.kind == .function);
|
||||||
|
return #field_parent_pointer(scope, "scope");
|
||||||
|
}
|
||||||
|
|
||||||
|
scope_to_module = fn (scope: &Scope) &Module
|
||||||
|
{
|
||||||
|
assert(scope.kind == .global);
|
||||||
|
return #field_parent_pointer(scope, "scope");
|
||||||
}
|
}
|
||||||
|
|
||||||
new_local = fn (module: &Module, scope: &Scope) &Local
|
new_local = fn (module: &Module, scope: &Scope) &Local
|
||||||
@ -3233,7 +3259,38 @@ tokenize = fn (module: &Module) Token
|
|||||||
},
|
},
|
||||||
'.' =>
|
'.' =>
|
||||||
{
|
{
|
||||||
#trap();
|
>id: TokenId = undefined;
|
||||||
|
>next_ch = module.content[start_index + 1];
|
||||||
|
switch (next_ch)
|
||||||
|
{
|
||||||
|
else => { id = .dot; },
|
||||||
|
'&' => { id = .pointer_dereference; },
|
||||||
|
'.' =>
|
||||||
|
{
|
||||||
|
switch (module.content[start_index + 2])
|
||||||
|
{
|
||||||
|
'.' => { id = .triple_dot; },
|
||||||
|
else => { id = .double_dot; },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
>add: u64 = undefined;
|
||||||
|
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
.dot => { add = 1; },
|
||||||
|
.double_dot, .pointer_dereference => { add = 2; },
|
||||||
|
.triple_dot => { add = 3; },
|
||||||
|
else => { unreachable; },
|
||||||
|
}
|
||||||
|
|
||||||
|
module.offset += add;
|
||||||
|
|
||||||
|
token = {
|
||||||
|
.id = id,
|
||||||
|
zero,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
'"' =>
|
'"' =>
|
||||||
{
|
{
|
||||||
@ -3437,11 +3494,41 @@ reference_identifier = fn (module: &Module, current_scope: &Scope, identifier: [
|
|||||||
{
|
{
|
||||||
.global =>
|
.global =>
|
||||||
{
|
{
|
||||||
#trap();
|
assert(module == scope_to_module(scope));
|
||||||
|
|
||||||
|
>global = module.first_global;
|
||||||
|
|
||||||
|
while (global != zero)
|
||||||
|
{
|
||||||
|
if (string_equal(identifier, global.variable.name))
|
||||||
|
{
|
||||||
|
variable = &global.variable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
global = global.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
>macro_declaration = module.first_macro_declaration;
|
||||||
|
|
||||||
|
while (macro_declaration != zero)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.function =>
|
.function =>
|
||||||
{
|
{
|
||||||
#trap();
|
assert(scope.parent != zero);
|
||||||
|
>function = scope_to_function(scope);
|
||||||
|
|
||||||
|
for (&argument: function.arguments)
|
||||||
|
{
|
||||||
|
if (string_equal(identifier, argument.variable.name))
|
||||||
|
{
|
||||||
|
variable = &argument.variable;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.local =>
|
.local =>
|
||||||
{
|
{
|
||||||
@ -3804,6 +3891,41 @@ get_token_precedence = fn (token: Token) Precedence
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_call_arguments = fn (module: &Module, scope: &Scope) []&Value
|
||||||
|
{
|
||||||
|
>arguments: []&Value = zero;
|
||||||
|
|
||||||
|
>argument_count: u64 = 0;
|
||||||
|
>argument_buffer: [64]&Value = undefined;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
skip_space(module);
|
||||||
|
|
||||||
|
if (consume_character_if_match(module, right_parenthesis))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
>argument = parse_value(module, scope, zero);
|
||||||
|
>argument_index = argument_count;
|
||||||
|
argument_buffer[argument_index] = argument;
|
||||||
|
|
||||||
|
skip_space(module);
|
||||||
|
|
||||||
|
consume_character_if_match(module, ',');
|
||||||
|
|
||||||
|
argument_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argument_count != 0)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
||||||
{
|
{
|
||||||
>left = builder.left;
|
>left = builder.left;
|
||||||
@ -3887,11 +4009,46 @@ parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
|||||||
},
|
},
|
||||||
.pointer_dereference =>
|
.pointer_dereference =>
|
||||||
{
|
{
|
||||||
#trap();
|
result = new_value(module);
|
||||||
|
result.& = {
|
||||||
|
.content = {
|
||||||
|
.unary = {
|
||||||
|
.value = left,
|
||||||
|
.id = .dereference,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.id = .unary,
|
||||||
|
.kind = .right,
|
||||||
|
zero,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
.left_parenthesis =>
|
.left_parenthesis =>
|
||||||
{
|
{
|
||||||
#trap();
|
result = new_value(module);
|
||||||
|
|
||||||
|
switch (left.id)
|
||||||
|
{
|
||||||
|
.macro_reference =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
else =>
|
||||||
|
{
|
||||||
|
>arguments = parse_call_arguments(module, scope);
|
||||||
|
result.& = {
|
||||||
|
.content = {
|
||||||
|
.call = {
|
||||||
|
.callable = left,
|
||||||
|
.arguments = arguments,
|
||||||
|
zero,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.id = .call,
|
||||||
|
.kind = .right,
|
||||||
|
zero,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.left_bracket =>
|
.left_bracket =>
|
||||||
{
|
{
|
||||||
@ -5488,7 +5645,17 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
|
|||||||
},
|
},
|
||||||
.dereference =>
|
.dereference =>
|
||||||
{
|
{
|
||||||
#trap();
|
analyze_type(module, unary_value, zero, { .must_be_constant = analysis.must_be_constant, zero });
|
||||||
|
if (value.kind == .left)
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
>pointer_type = unary_value.type;
|
||||||
|
assert(pointer_type.id == .pointer);
|
||||||
|
>dereference_type = pointer_type.content.pointer.element_type;
|
||||||
|
|
||||||
|
typecheck(module, expected_type, dereference_type);
|
||||||
|
value_type = dereference_type;
|
||||||
},
|
},
|
||||||
.int_from_enum =>
|
.int_from_enum =>
|
||||||
{
|
{
|
||||||
@ -5533,6 +5700,24 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
|
|||||||
|
|
||||||
typecheck(module, expected_type, value_type);
|
typecheck(module, expected_type, value_type);
|
||||||
},
|
},
|
||||||
|
// TODO: this is the default case
|
||||||
|
.ampersand
|
||||||
|
=>
|
||||||
|
{
|
||||||
|
>is_boolean = unary_is_boolean(unary_id);
|
||||||
|
if (is_boolean)
|
||||||
|
{
|
||||||
|
analyze_type(module, unary_value, zero, { .must_be_constant = analysis.must_be_constant, zero });
|
||||||
|
value_type = uint1(module);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
analyze_type(module, unary_value, expected_type, { .must_be_constant = analysis.must_be_constant, zero });
|
||||||
|
value_type = unary_value.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
typecheck(module, expected_type, value_type);
|
||||||
|
},
|
||||||
else =>
|
else =>
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
@ -5607,6 +5792,93 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
|
|||||||
|
|
||||||
typecheck(module, expected_type, value_type);
|
typecheck(module, expected_type, value_type);
|
||||||
},
|
},
|
||||||
|
.call =>
|
||||||
|
{
|
||||||
|
>call = &value.content.call;
|
||||||
|
>callable = call.callable;
|
||||||
|
analyze_type(module, callable, zero, { .must_be_constant = analysis.must_be_constant, zero });
|
||||||
|
|
||||||
|
>function_type: &Type = zero;
|
||||||
|
|
||||||
|
switch (callable.id)
|
||||||
|
{
|
||||||
|
.variable =>
|
||||||
|
{
|
||||||
|
>variable = callable.content.variable;
|
||||||
|
>variable_type = variable.type;
|
||||||
|
|
||||||
|
switch (variable_type.id)
|
||||||
|
{
|
||||||
|
.function =>
|
||||||
|
{
|
||||||
|
function_type = variable_type;
|
||||||
|
},
|
||||||
|
.pointer =>
|
||||||
|
{
|
||||||
|
>element_type = resolve_alias(module, variable_type.content.pointer.element_type);
|
||||||
|
|
||||||
|
switch (element_type.id)
|
||||||
|
{
|
||||||
|
.function =>
|
||||||
|
{
|
||||||
|
function_type = element_type;
|
||||||
|
},
|
||||||
|
else => { report_error(); },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else =>
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else =>
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(function_type != zero);
|
||||||
|
assert(function_type.id == .function);
|
||||||
|
call.function_type = function_type;
|
||||||
|
|
||||||
|
>semantic_argument_types = function_type.content.function.base.semantic_argument_types;
|
||||||
|
>call_arguments = call.arguments;
|
||||||
|
|
||||||
|
if (function_type.content.function.base.is_variable_argument)
|
||||||
|
{
|
||||||
|
if (call_arguments.length < semantic_argument_types.length)
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (call_arguments.length != semantic_argument_types.length)
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i: 0..semantic_argument_types.length)
|
||||||
|
{
|
||||||
|
>argument_type = semantic_argument_types[i];
|
||||||
|
>call_argument = call_arguments[i];
|
||||||
|
analyze_type(module, call_argument, argument_type, { .must_be_constant = analysis.must_be_constant, zero });
|
||||||
|
check_types(module, argument_type, call_argument.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i: semantic_argument_types.length..call_arguments.length)
|
||||||
|
{
|
||||||
|
>call_argument = call_arguments[i];
|
||||||
|
analyze_type(module, call_argument, zero, { .must_be_constant = analysis.must_be_constant, zero });
|
||||||
|
}
|
||||||
|
|
||||||
|
>semantic_return_type = function_type.content.function.base.semantic_return_type;
|
||||||
|
|
||||||
|
typecheck(module, expected_type, semantic_return_type);
|
||||||
|
value_type = semantic_return_type;
|
||||||
|
},
|
||||||
else =>
|
else =>
|
||||||
{
|
{
|
||||||
#trap();
|
#trap();
|
||||||
@ -5826,6 +6098,35 @@ emit_value = fn (module: &Module, value: &Value, type_kind: TypeKind, expect_con
|
|||||||
|
|
||||||
llvm_value = LLVMBuildTrunc(module.llvm.builder, llvm_unary_value, destination_type, "");
|
llvm_value = LLVMBuildTrunc(module.llvm.builder, llvm_unary_value, destination_type, "");
|
||||||
},
|
},
|
||||||
|
.ampersand =>
|
||||||
|
{
|
||||||
|
assert(resolved_value_type == resolved_unary_type);
|
||||||
|
llvm_value = llvm_unary_value;
|
||||||
|
},
|
||||||
|
.dereference =>
|
||||||
|
{
|
||||||
|
switch (value.kind)
|
||||||
|
{
|
||||||
|
.right =>
|
||||||
|
{
|
||||||
|
>pointer_type = unary_value.type;
|
||||||
|
assert(pointer_type.id == .pointer);
|
||||||
|
>child_type = resolve_alias(module, pointer_type.content.pointer.element_type);
|
||||||
|
assert(child_type == resolved_value_type);
|
||||||
|
>load = create_load(module, {
|
||||||
|
.type = child_type,
|
||||||
|
.pointer = unary_value.llvm,
|
||||||
|
.kind = type_kind,
|
||||||
|
zero,
|
||||||
|
});
|
||||||
|
llvm_value = load;
|
||||||
|
},
|
||||||
|
.left =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
else => { #trap(); },
|
else => { #trap(); },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -7184,6 +7485,15 @@ names: [_][]u8 = [
|
|||||||
"extend",
|
"extend",
|
||||||
"integer_max",
|
"integer_max",
|
||||||
"integer_hex",
|
"integer_hex",
|
||||||
|
"basic_pointer",
|
||||||
|
"basic_call",
|
||||||
|
"basic_branch",
|
||||||
|
"basic_array",
|
||||||
|
"basic_enum",
|
||||||
|
"basic_slice",
|
||||||
|
"basic_string",
|
||||||
|
"basic_varargs",
|
||||||
|
"basic_while",
|
||||||
];
|
];
|
||||||
|
|
||||||
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32
|
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32
|
||||||
|
@ -8621,8 +8621,10 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
|
|||||||
LLVMValueRef indices[] = {
|
LLVMValueRef indices[] = {
|
||||||
body_index_load,
|
body_index_load,
|
||||||
};
|
};
|
||||||
|
auto gep_type = aggregate_type->structure.fields[0].type->pointer.element_type;
|
||||||
|
resolve_type_in_place(module, gep_type);
|
||||||
auto gep = create_gep(module, {
|
auto gep = create_gep(module, {
|
||||||
.type = aggregate_type->structure.fields[0].type->pointer.element_type->llvm.memory,
|
.type = gep_type->llvm.memory,
|
||||||
.pointer = extract_pointer,
|
.pointer = extract_pointer,
|
||||||
.indices = array_to_slice(indices),
|
.indices = array_to_slice(indices),
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user