wip
This commit is contained in:
parent
09c92d666c
commit
8fe044083a
403
src/compiler.bbb
403
src/compiler.bbb
@ -1487,6 +1487,9 @@ ValueId = enum
|
|||||||
function,
|
function,
|
||||||
constant_integer,
|
constant_integer,
|
||||||
global,
|
global,
|
||||||
|
unary,
|
||||||
|
binary,
|
||||||
|
string_literal,
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueConstantInteger = struct
|
ValueConstantInteger = struct
|
||||||
@ -1510,10 +1513,108 @@ ValueFunction = struct
|
|||||||
attributes: FunctionAttributes,
|
attributes: FunctionAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnaryId = enum
|
||||||
|
{
|
||||||
|
minus,
|
||||||
|
plus,
|
||||||
|
ampersand,
|
||||||
|
exclamation,
|
||||||
|
tilde,
|
||||||
|
enum_name,
|
||||||
|
extend,
|
||||||
|
truncate,
|
||||||
|
pointer_cast,
|
||||||
|
int_from_enum,
|
||||||
|
int_from_pointer,
|
||||||
|
va_end,
|
||||||
|
bitwise_not,
|
||||||
|
dereference,
|
||||||
|
pointer_from_int,
|
||||||
|
enum_from_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueUnary = struct
|
||||||
|
{
|
||||||
|
value: &Value,
|
||||||
|
id: UnaryId,
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryId = enum
|
||||||
|
{
|
||||||
|
add,
|
||||||
|
sub,
|
||||||
|
mul,
|
||||||
|
div,
|
||||||
|
rem,
|
||||||
|
bitwise_and,
|
||||||
|
bitwise_or,
|
||||||
|
bitwise_xor,
|
||||||
|
shift_left,
|
||||||
|
shift_right,
|
||||||
|
compare_equal,
|
||||||
|
compare_not_equal,
|
||||||
|
compare_greater,
|
||||||
|
compare_less,
|
||||||
|
compare_greater_equal,
|
||||||
|
compare_less_equal,
|
||||||
|
logical_and,
|
||||||
|
logical_or,
|
||||||
|
logical_and_shortcircuit,
|
||||||
|
logical_or_shortcircuit,
|
||||||
|
max,
|
||||||
|
min,
|
||||||
|
}
|
||||||
|
|
||||||
|
binary_is_boolean = fn (id: BinaryId) u1
|
||||||
|
{
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
.add,
|
||||||
|
.sub,
|
||||||
|
.mul,
|
||||||
|
.div,
|
||||||
|
.rem,
|
||||||
|
.bitwise_and,
|
||||||
|
.bitwise_or,
|
||||||
|
.bitwise_xor,
|
||||||
|
.shift_left,
|
||||||
|
.shift_right,
|
||||||
|
.max,
|
||||||
|
.min,
|
||||||
|
=>
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
.compare_equal,
|
||||||
|
.compare_not_equal,
|
||||||
|
.compare_less,
|
||||||
|
.compare_less_equal,
|
||||||
|
.compare_greater,
|
||||||
|
.compare_greater_equal,
|
||||||
|
.logical_and,
|
||||||
|
.logical_or,
|
||||||
|
.logical_and_shortcircuit,
|
||||||
|
.logical_or_shortcircuit,
|
||||||
|
=>
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueBinary = struct
|
||||||
|
{
|
||||||
|
left: &Value,
|
||||||
|
right: &Value,
|
||||||
|
id: BinaryId,
|
||||||
|
}
|
||||||
|
|
||||||
ValueContent = union
|
ValueContent = union
|
||||||
{
|
{
|
||||||
constant_integer: ValueConstantInteger,
|
constant_integer: ValueConstantInteger,
|
||||||
function: ValueFunction,
|
function: ValueFunction,
|
||||||
|
unary: ValueUnary,
|
||||||
|
binary: ValueBinary,
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueKind = enum
|
ValueKind = enum
|
||||||
@ -1531,6 +1632,22 @@ Value = struct
|
|||||||
llvm: &LLVMValue,
|
llvm: &LLVMValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value_is_constant = fn (value: &Value) u1
|
||||||
|
{
|
||||||
|
switch (value.id)
|
||||||
|
{
|
||||||
|
.constant_integer =>
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
},
|
||||||
|
else =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
|
||||||
i128_offset: u64 = 64 * 2;
|
i128_offset: u64 = 64 * 2;
|
||||||
void_offset: u64 = i128_offset + 2;
|
void_offset: u64 = i128_offset + 2;
|
||||||
|
|
||||||
@ -2139,6 +2256,11 @@ integer_type = fn (module: &Module, integer: TypeInteger) &Type
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint1 = fn (module: &Module) &Type
|
||||||
|
{
|
||||||
|
return integer_type(module, { .bit_count = 1, .signed = 0 });
|
||||||
|
}
|
||||||
|
|
||||||
uint64 = fn (module: &Module) &Type
|
uint64 = fn (module: &Module) &Type
|
||||||
{
|
{
|
||||||
return integer_type(module, { .bit_count = 64, .signed = 0 });
|
return integer_type(module, { .bit_count = 64, .signed = 0 });
|
||||||
@ -2819,7 +2941,7 @@ tokenize = fn (module: &Module) Token
|
|||||||
|
|
||||||
>start_character = module.content[start_index];
|
>start_character = module.content[start_index];
|
||||||
|
|
||||||
>token: Token = undefined;
|
>token: Token = zero;
|
||||||
|
|
||||||
switch (start_character)
|
switch (start_character)
|
||||||
{
|
{
|
||||||
@ -2940,7 +3062,45 @@ tokenize = fn (module: &Module) Token
|
|||||||
'!',
|
'!',
|
||||||
=>
|
=>
|
||||||
{
|
{
|
||||||
#trap();
|
>next_ch = module.content[start_index + 1];
|
||||||
|
>id: TokenId = undefined;
|
||||||
|
|
||||||
|
if (next_ch == '=')
|
||||||
|
{
|
||||||
|
switch (start_character)
|
||||||
|
{
|
||||||
|
'+' => { id = .assign_plus; },
|
||||||
|
'-' => { id = .assign_dash; },
|
||||||
|
'*' => { id = .assign_asterisk; },
|
||||||
|
'/' => { id = .assign_forward_slash; },
|
||||||
|
'%' => { id = .assign_percentage; },
|
||||||
|
'&' => { id = .assign_ampersand; },
|
||||||
|
'|' => { id = .assign_bar; },
|
||||||
|
'^' => { id = .assign_caret; },
|
||||||
|
'!' => { id = .compare_not_equal; },
|
||||||
|
else => { unreachable; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (start_character)
|
||||||
|
{
|
||||||
|
'+' => { id = .plus; },
|
||||||
|
'-' => { id = .dash; },
|
||||||
|
'*' => { id = .asterisk; },
|
||||||
|
'/' => { id = .forward_slash; },
|
||||||
|
'%' => { id = .percentage; },
|
||||||
|
'&' => { id = .ampersand; },
|
||||||
|
'|' => { id = .bar; },
|
||||||
|
'^' => { id = .caret; },
|
||||||
|
'!' => { id = .exclamation; },
|
||||||
|
else => { unreachable; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token.id = id;
|
||||||
|
|
||||||
|
module.offset += #extend(next_ch == '=') + 1;
|
||||||
},
|
},
|
||||||
else =>
|
else =>
|
||||||
{
|
{
|
||||||
@ -2984,6 +3144,8 @@ ValueBuilder = struct
|
|||||||
allow_assignment_operators: u1,
|
allow_assignment_operators: u1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_precedence = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value;
|
||||||
|
|
||||||
parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
||||||
{
|
{
|
||||||
>token = builder.token;
|
>token = builder.token;
|
||||||
@ -3007,6 +3169,72 @@ parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
|||||||
zero,
|
zero,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
.dash, .ampersand, .exclamation, .tilde =>
|
||||||
|
{
|
||||||
|
assert(!builder.left);
|
||||||
|
>id: UnaryId = undefined;
|
||||||
|
|
||||||
|
switch (token.id)
|
||||||
|
{
|
||||||
|
.dash => { id = .minus; },
|
||||||
|
.ampersand => { id = .ampersand; },
|
||||||
|
.exclamation => { id = .exclamation; },
|
||||||
|
.tilde => { id = .bitwise_not; },
|
||||||
|
else => { unreachable; },
|
||||||
|
}
|
||||||
|
|
||||||
|
>unary_builder = builder;
|
||||||
|
unary_builder.precedence = .prefix;
|
||||||
|
unary_builder.token = zero;
|
||||||
|
unary_builder.kind = #select(token.id == .ampersand, .left, builder.kind);
|
||||||
|
|
||||||
|
>unary_value = parse_precedence(module, scope, unary_builder);
|
||||||
|
|
||||||
|
result = new_value(module);
|
||||||
|
result.& = {
|
||||||
|
.content = {
|
||||||
|
.unary = {
|
||||||
|
.value = unary_value,
|
||||||
|
.id = id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.id = .unary,
|
||||||
|
.kind = .right,
|
||||||
|
zero,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.identifier =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.value_intrinsic =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.left_bracket =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.dot =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.left_parenthesis =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.string_literal =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.left_brace =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.value_keyword =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
else =>
|
else =>
|
||||||
{
|
{
|
||||||
report_error();
|
report_error();
|
||||||
@ -3102,7 +3330,109 @@ get_token_precedence = fn (token: Token) Precedence
|
|||||||
|
|
||||||
parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
||||||
{
|
{
|
||||||
#trap();
|
>left = builder.left;
|
||||||
|
assert(left != zero);
|
||||||
|
|
||||||
|
>token = builder.token;
|
||||||
|
|
||||||
|
>result: &Value = zero;
|
||||||
|
|
||||||
|
switch (token.id)
|
||||||
|
{
|
||||||
|
.plus,
|
||||||
|
.dash,
|
||||||
|
.asterisk,
|
||||||
|
.forward_slash,
|
||||||
|
.percentage,
|
||||||
|
.ampersand,
|
||||||
|
.bar,
|
||||||
|
.caret,
|
||||||
|
.shift_left,
|
||||||
|
.shift_right,
|
||||||
|
.compare_equal,
|
||||||
|
.compare_not_equal,
|
||||||
|
.compare_less,
|
||||||
|
.compare_less_equal,
|
||||||
|
.compare_greater,
|
||||||
|
.compare_greater_equal,
|
||||||
|
.operator_keyword,
|
||||||
|
=>
|
||||||
|
{
|
||||||
|
>precedence = get_token_precedence(token);
|
||||||
|
assert(precedence != .assignment);
|
||||||
|
|
||||||
|
>id: BinaryId = undefined;
|
||||||
|
|
||||||
|
switch (token.id)
|
||||||
|
{
|
||||||
|
.operator_keyword =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.plus => { id = .add; },
|
||||||
|
.dash => { id = .sub; },
|
||||||
|
.asterisk => { id = .mul; },
|
||||||
|
.forward_slash => { id = .div; },
|
||||||
|
.percentage => { id = .rem; },
|
||||||
|
.ampersand => { id = .bitwise_and; },
|
||||||
|
.bar => { id = .bitwise_or; },
|
||||||
|
.caret => { id = .bitwise_xor; },
|
||||||
|
.shift_left => { id = .shift_left; },
|
||||||
|
.shift_right => { id = .shift_right; },
|
||||||
|
.compare_equal => { id = .compare_equal; },
|
||||||
|
.compare_not_equal => { id = .compare_not_equal; },
|
||||||
|
.compare_less => { id = .compare_less; },
|
||||||
|
.compare_less_equal => { id = .compare_less_equal; },
|
||||||
|
.compare_greater => { id = .compare_greater; },
|
||||||
|
.compare_greater_equal => { id = .compare_greater_equal; },
|
||||||
|
else => { unreachable; },
|
||||||
|
}
|
||||||
|
|
||||||
|
>right_precedence: Precedence = #enum_from_int(#int_from_enum(precedence) + 1);
|
||||||
|
>right_builder = builder;
|
||||||
|
right_builder.precedence = right_precedence;
|
||||||
|
right_builder.token = zero;
|
||||||
|
right_builder.left = zero;
|
||||||
|
>right = parse_precedence(module, scope, right_builder);
|
||||||
|
|
||||||
|
result = new_value(module);
|
||||||
|
result.& = {
|
||||||
|
.content = {
|
||||||
|
.binary = {
|
||||||
|
.left = left,
|
||||||
|
.right = right,
|
||||||
|
.id = id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.id = .binary,
|
||||||
|
.kind = .right,
|
||||||
|
zero,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.pointer_dereference =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.left_parenthesis =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.left_bracket =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
.dot =>
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
},
|
||||||
|
else =>
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(result != zero);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_right_with_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
parse_right_with_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value
|
||||||
@ -4452,6 +4782,49 @@ TypeAnalysis = struct
|
|||||||
indexing_type: &Type,
|
indexing_type: &Type,
|
||||||
must_be_constant: u1,
|
must_be_constant: u1,
|
||||||
}
|
}
|
||||||
|
analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysis: TypeAnalysis) void;
|
||||||
|
|
||||||
|
analyze_binary_type = fn (module: &Module, left: &Value, right: &Value, is_boolean: u1, expected_type: &Type, must_be_constant: u1) void
|
||||||
|
{
|
||||||
|
>left_constant = value_is_constant(left);
|
||||||
|
>right_constant = value_is_constant(right);
|
||||||
|
|
||||||
|
if (!expected_type)
|
||||||
|
{
|
||||||
|
if (left_constant != zero and right_constant)
|
||||||
|
{
|
||||||
|
if (left.type == zero and right.type == zero)
|
||||||
|
{
|
||||||
|
>string_literal = left.id == .string_literal and right.id == .string_literal;
|
||||||
|
|
||||||
|
if (string_literal)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_boolean or expected_type == zero)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
else if (!is_boolean and expected_type != zero)
|
||||||
|
{
|
||||||
|
#trap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(left.type != zero);
|
||||||
|
assert(right.type != zero);
|
||||||
|
}
|
||||||
|
|
||||||
analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysis: TypeAnalysis) void
|
analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysis: TypeAnalysis) void
|
||||||
{
|
{
|
||||||
@ -4527,6 +4900,18 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi
|
|||||||
|
|
||||||
typecheck(module, expected_type, value_type);
|
typecheck(module, expected_type, value_type);
|
||||||
},
|
},
|
||||||
|
.binary =>
|
||||||
|
{
|
||||||
|
>left = value.content.binary.left;
|
||||||
|
>right = value.content.binary.right;
|
||||||
|
>id = value.content.binary.id;
|
||||||
|
|
||||||
|
>is_boolean = binary_is_boolean(id);
|
||||||
|
analyze_binary_type(module, left, right, is_boolean, expected_type, analysis.must_be_constant);
|
||||||
|
check_types(module, left.type, right.type);
|
||||||
|
|
||||||
|
value_type = #select(is_boolean, uint1(module), left.type);
|
||||||
|
},
|
||||||
else =>
|
else =>
|
||||||
{
|
{
|
||||||
#trap();
|
#trap();
|
||||||
@ -5738,6 +6123,18 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) []u8
|
|||||||
|
|
||||||
names: [_][]u8 = [
|
names: [_][]u8 = [
|
||||||
"minimal",
|
"minimal",
|
||||||
|
"comments",
|
||||||
|
"constant_add",
|
||||||
|
"constant_and",
|
||||||
|
"constant_div",
|
||||||
|
"constant_mul",
|
||||||
|
"constant_rem",
|
||||||
|
"constant_or",
|
||||||
|
"constant_sub",
|
||||||
|
"constant_xor",
|
||||||
|
"constant_shift_left",
|
||||||
|
"constant_shift_right",
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
[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
|
||||||
|
@ -5983,6 +5983,7 @@ fn LLVMValueRef emit_field_access(Module* module, Value* value, LLVMValueRef lef
|
|||||||
auto load = create_load(module, {
|
auto load = create_load(module, {
|
||||||
.type = field_access.type,
|
.type = field_access.type,
|
||||||
.pointer = gep,
|
.pointer = gep,
|
||||||
|
.kind = type_kind,
|
||||||
});
|
});
|
||||||
return load;
|
return load;
|
||||||
} break;
|
} break;
|
||||||
@ -7704,6 +7705,7 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
|
|||||||
auto condition = value->select.condition;
|
auto condition = value->select.condition;
|
||||||
auto true_value = value->select.true_value;
|
auto true_value = value->select.true_value;
|
||||||
auto false_value = value->select.false_value;
|
auto false_value = value->select.false_value;
|
||||||
|
|
||||||
emit_value(module, condition, TypeKind::abi, must_be_constant);
|
emit_value(module, condition, TypeKind::abi, must_be_constant);
|
||||||
LLVMValueRef llvm_condition = condition->llvm;
|
LLVMValueRef llvm_condition = condition->llvm;
|
||||||
auto condition_type = condition->type;
|
auto condition_type = condition->type;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user