From 8fe044083a9c20932b2c5f685f7e539db60ebe2e Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Fri, 6 Jun 2025 21:32:57 -0600 Subject: [PATCH] wip --- src/compiler.bbb | 403 ++++++++++++++++++++++++++++++++++++++++++++++- src/emitter.cpp | 2 + 2 files changed, 402 insertions(+), 3 deletions(-) diff --git a/src/compiler.bbb b/src/compiler.bbb index 531c6c5..a1747e3 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -1487,6 +1487,9 @@ ValueId = enum function, constant_integer, global, + unary, + binary, + string_literal, } ValueConstantInteger = struct @@ -1510,10 +1513,108 @@ ValueFunction = struct 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 { constant_integer: ValueConstantInteger, function: ValueFunction, + unary: ValueUnary, + binary: ValueBinary, } ValueKind = enum @@ -1531,6 +1632,22 @@ Value = struct llvm: &LLVMValue, } +value_is_constant = fn (value: &Value) u1 +{ + switch (value.id) + { + .constant_integer => + { + return 1; + }, + else => + { + #trap(); + } + } + #trap(); +} + i128_offset: u64 = 64 * 2; void_offset: u64 = i128_offset + 2; @@ -2139,6 +2256,11 @@ integer_type = fn (module: &Module, integer: TypeInteger) &Type return result; } +uint1 = fn (module: &Module) &Type +{ + return integer_type(module, { .bit_count = 1, .signed = 0 }); +} + uint64 = fn (module: &Module) &Type { return integer_type(module, { .bit_count = 64, .signed = 0 }); @@ -2819,7 +2941,7 @@ tokenize = fn (module: &Module) Token >start_character = module.content[start_index]; - >token: Token = undefined; + >token: Token = zero; 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 => { @@ -2984,6 +3144,8 @@ ValueBuilder = struct allow_assignment_operators: u1, } +parse_precedence = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value; + parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value { >token = builder.token; @@ -3007,6 +3169,72 @@ parse_left = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value 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 => { report_error(); @@ -3102,7 +3330,109 @@ get_token_precedence = fn (token: Token) Precedence 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 @@ -4452,6 +4782,49 @@ TypeAnalysis = struct indexing_type: &Type, 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 { @@ -4527,6 +4900,18 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi 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 => { #trap(); @@ -5738,6 +6123,18 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) []u8 names: [_][]u8 = [ "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 diff --git a/src/emitter.cpp b/src/emitter.cpp index 6c4a60b..92c2cb6 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -5983,6 +5983,7 @@ fn LLVMValueRef emit_field_access(Module* module, Value* value, LLVMValueRef lef auto load = create_load(module, { .type = field_access.type, .pointer = gep, + .kind = type_kind, }); return load; } break; @@ -7704,6 +7705,7 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect auto condition = value->select.condition; auto true_value = value->select.true_value; auto false_value = value->select.false_value; + emit_value(module, condition, TypeKind::abi, must_be_constant); LLVMValueRef llvm_condition = condition->llvm; auto condition_type = condition->type;