Clean up Boolean using an "if" instruction

By introducing the virtual "if" instruction we can clean up Boolean so
that we no longer have to refine the True and False instances. If we
also clean up Nil in a similar way it becomes easier to rewrite the
compiler in Inko, as it no longer needs to support the refining of
random objects.
parent c30ca995
Pipeline #105654300 passed with stages
in 18 minutes and 6 seconds
......@@ -1771,6 +1771,10 @@ module Inkoc
typedb.byte_array_type.new_instance
end
def on_raw_if(node, _)
node.arguments.fetch(1).type.new_instance
end
def define_block_signature(node, scope, expected_block = nil)
define_type_parameters(node, scope)
define_argument_types(node, scope, expected_block)
......
......@@ -1491,6 +1491,33 @@ module Inkoc
raw_unary_instruction(:RandomBytes, node, body)
end
def on_raw_if(node, body)
loc = node.location
rec_node = node.arguments.fetch(0)
result = body.register(rec_node.type)
receiver = process_node(rec_node, body)
body.instruct(:GotoNextBlockIfTrue, receiver, loc)
# The block used for the "false" argument.
if_false = process_node(node.arguments.fetch(2), body)
body.instruct(:Unary, :SetRegister, result, if_false, loc)
body.instruct(:SkipNextBlock, loc)
# The block used for the "true" argument.
body.add_connected_basic_block
if_true = process_node(node.arguments.fetch(1), body)
body.instruct(:Unary, :SetRegister, result, if_true, loc)
body.add_connected_basic_block
result
end
def on_return(node, body)
location = node.location
register =
......
......@@ -9,35 +9,35 @@ import std::hash::(Hasher, Hash)
impl Boolean {
# Returns the `Boolean` that is the opposite of `self`.
def not -> Boolean {
False
_INKOC.if(self, False, True)
}
}
impl Conditional for Boolean {
def if_true!(R)(block: do -> R) -> ?R {
block.call
def if!(R)(true: do -> R, false: do -> R) -> R {
_INKOC.if(self, true, false).call
}
def if_false!(R)(block: do -> R) -> ?R {
Nil
def if_true!(R)(block: do -> R) -> ?R {
_INKOC.if(self, block.call, Nil)
}
def if!(R)(true: do -> R, false: do -> R) -> R {
true.call
def if_false!(R)(block: do -> R) -> ?R {
_INKOC.if(self, Nil, block.call)
}
def and(other: do -> Boolean) -> Boolean {
other.call
_INKOC.if(self, other.call, False)
}
def or(other: do -> Boolean) -> Boolean {
True
_INKOC.if(self, True, other.call)
}
}
impl ToString for Boolean {
def to_string -> String {
_INKOC.get_attribute(self, '@_object_name') as String
_INKOC.if(self, 'True', 'False')
}
}
......@@ -47,31 +47,3 @@ impl Hash for Boolean {
Nil
}
}
impl Conditional for False {
def if_true!(R)(block: do -> R) -> ?R {
Nil
}
def if_false!(R)(block: do -> R) -> ?R {
block.call
}
def if!(R)(true: do -> R, false: do -> R) -> R {
false.call
}
def and(other: do -> Boolean) -> Boolean {
False
}
def or(other: do -> Boolean) -> Boolean {
other.call
}
}
impl False {
def not -> Boolean {
True
}
}
......@@ -2,82 +2,6 @@ import std::map::DefaultHasher
import std::test
import std::test::assert
test.group('std::boolean::Boolean.not') do (g) {
g.test('Returning the opposite of Boolean') {
assert.false(Boolean.not)
}
}
test.group('std::boolean::Boolean.if_true') do (g) {
g.test('The supplied Block is always executed') {
let number = Boolean.if_true {
10
}
assert.equal(number, 10)
}
}
test.group('std::boolean::Boolean.if_false') do (g) {
g.test('The supplied Block is never executed') {
let number = Boolean.if_false {
10
}
assert.equal(number, Nil)
}
}
test.group('std::boolean::Boolean.if') do (g) {
g.test('The Block passed to the "true" argument is always executed') {
let number = Boolean.if(true: { 10 }, false: { 20 })
assert.equal(number, 10)
}
}
test.group('std::boolean::Boolean.and') do (g) {
g.test('The supplied Block is always executed') {
assert.equal(Boolean.and({ True }), True)
}
}
test.group('std::boolean::Boolean.or') do (g) {
g.test('The return value is always True') {
assert.equal(Boolean.or({ False }), True)
}
}
test.group('std::boolean::Boolean.==') do (g) {
g.test('Comparing Boolean with other booleans') {
assert.equal(Boolean, Boolean)
assert.not_equal(Boolean, True)
assert.not_equal(Boolean, False)
}
}
test.group('std::boolean::Boolean.to_string') do (g) {
g.test('Converting Boolean to a String') {
assert.equal(Boolean.to_string, 'Boolean')
}
}
test.group('std::boolean::Boolean.hash') do (g) {
g.test('Hashing a Boolean') {
let hasher1 = DefaultHasher.new(1, 2)
let hasher2 = DefaultHasher.new(1, 2)
Boolean.hash(hasher1)
Boolean.hash(hasher2)
# The exact hash value may change between OS processes or releases, so all
# we can do is assert that the value is the same every time we send `hash`
# to `Boolean`.
assert.equal(hasher1.to_hash, hasher2.to_hash)
}
}
test.group('std::boolean::True.not') do (g) {
g.test('Returning the opposite of True') {
assert.false(True.not)
......
......@@ -478,10 +478,6 @@ test.group('std::mirror::BlockMirror.format') do (g) {
}
test.group('std::mirror::BooleanMirror.format') do (g) {
g.test('Formatting Boolean') {
assert.equal(format(BooleanMirror.new(Boolean)), 'Boolean')
}
g.test('Formatting True') {
assert.equal(format(BooleanMirror.new(True)), 'True')
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment