Module: MilkTea::Lowering::Assertions
- Included in:
- MilkTea::Lowerer
- Defined in:
- lib/milk_tea/core/lowering/assertions.rb
Constant Summary collapse
- ASSERT_CALL_NAMES =
%w[assert expect expect_eq expect_ne].freeze
Instance Method Summary collapse
- #assert_like_call_kind(expression) ⇒ Object
- #binary_expression(operator, left, right, line:, column:) ⇒ Object
- #default_assert_message(kind, line) ⇒ Object
-
#lower_assert_like_statement(statement, env:) ⇒ Object
Lowers an
assert/expect/expect_eq/expect_neexpression statement into anIR::IfStmtwhose then-branch aborts viafatal. - #lower_fatal_expression_statement(message, line:, column:, env:) ⇒ Object
- #string_literal(value, line:, column:) ⇒ Object
- #unary_expression(operator, operand, line:, column:) ⇒ Object
Instance Method Details
#assert_like_call_kind(expression) ⇒ Object
55 56 57 58 59 60 61 |
# File 'lib/milk_tea/core/lowering/assertions.rb', line 55 def assert_like_call_kind(expression) return nil unless expression.is_a?(AST::Call) return nil unless expression.callee.is_a?(AST::Identifier) return nil unless ASSERT_CALL_NAMES.include?(expression.callee.name) expression.callee.name end |
#binary_expression(operator, left, right, line:, column:) ⇒ Object
91 92 93 |
# File 'lib/milk_tea/core/lowering/assertions.rb', line 91 def binary_expression(operator, left, right, line:, column:) AST::BinaryOp.new(operator:, left:, right:, line:, column:) end |
#default_assert_message(kind, line) ⇒ Object
63 64 65 66 67 68 69 70 71 |
# File 'lib/milk_tea/core/lowering/assertions.rb', line 63 def (kind, line) path = @ctx.current_analysis_path.to_s case kind when "assert" then "assertion failed at #{path}:#{line}" when "expect" then "expectation failed at #{path}:#{line}" when "expect_eq" then "expect_eq failed: values are not equal at #{path}:#{line}" when "expect_ne" then "expect_ne failed: values are equal at #{path}:#{line}" end end |
#lower_assert_like_statement(statement, env:) ⇒ Object
Lowers an assert/expect/expect_eq/expect_ne expression statement
into an IR::IfStmt whose then-branch aborts via fatal. The message is
only evaluated on the failing path so unused messages cost nothing.
Returns nil when the statement is not one of the assertion calls so the
caller can fall through to ordinary expression-statement lowering.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/milk_tea/core/lowering/assertions.rb', line 13 def lower_assert_like_statement(statement, env:) kind = assert_like_call_kind(statement.expression) return nil unless kind arguments = statement.expression.arguments line = statement.expression.line column = statement.expression.column = (kind, statement.line) condition_ast = nil = nil case kind when "assert", "expect" condition_ast = unary_expression("not", arguments.fetch(0).value, line:, column:) = arguments.length > 1 ? arguments.fetch(1).value : string_literal(, line:, column:) when "expect_eq" condition_ast = binary_expression("!=", arguments.fetch(0).value, arguments.fetch(1).value, line:, column:) = arguments.length > 2 ? arguments.fetch(2).value : string_literal(, line:, column:) when "expect_ne" condition_ast = binary_expression("==", arguments.fetch(0).value, arguments.fetch(1).value, line:, column:) = arguments.length > 2 ? arguments.fetch(2).value : string_literal(, line:, column:) end # Hoist inline-proc/foreign-temporary setup out of the condition so the # failure check itself stays a plain `if (!cond)` in C. setup, prepared_condition, cleanups = prepare_expression_with_cleanups( condition_ast, env:, expected_type: @ctx.types.fetch("bool"), ) [ *setup, IR::IfStmt.new( condition: lower_expression(prepared_condition, env:, expected_type: @ctx.types.fetch("bool")), then_body: [lower_fatal_expression_statement(, line:, column:, env:)], else_body: [], ), *cleanups.flat_map(&:itself), ] end |
#lower_fatal_expression_statement(message, line:, column:, env:) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/milk_tea/core/lowering/assertions.rb', line 73 def lower_fatal_expression_statement(, line:, column:, env:) fatal_call = AST::Call.new( callee: AST::Identifier.new(name: "fatal", line:, column:), arguments: [AST::Argument.new(name: nil, value: , line:, column:)], line:, column:, ) IR::ExpressionStmt.new( expression: lower_expression(fatal_call, env:, expected_type: @ctx.types.fetch("void")), line:, path: @ctx.current_analysis_path, ) end |
#string_literal(value, line:, column:) ⇒ Object
95 96 97 |
# File 'lib/milk_tea/core/lowering/assertions.rb', line 95 def string_literal(value, line:, column:) AST::StringLiteral.new(lexeme: value.inspect, value:, cstring: false, line:, column:) end |