Current section

Files

Jump to
orb lib orb numeric dsl.ex
Raw

lib/orb/numeric/dsl.ex

defmodule Orb.Numeric.DSL do
@moduledoc """
Operators that work with all number types.
"""
import Kernel, except: [+: 2, -: 2, *: 2, ===: 2, !==: 2, not: 1, or: 2]
alias require Orb.Ops
def left + right do
case Ops.extract_common_type(left, right) do
Integer ->
Kernel.+(left, right)
Float ->
Kernel.+(left, right)
type when Ops.is_primitive_integer_type(type) ->
Orb.Numeric.Add.optimized(type, left, right)
type when Ops.is_primitive_float_type(type) ->
Orb.Instruction.new(type, :add, [left, right])
end
end
def left - right do
case Ops.extract_common_type(left, right) do
Integer ->
Kernel.-(left, right)
Float ->
Kernel.-(left, right)
type when Ops.is_primitive_integer_type(type) ->
Orb.Numeric.Subtract.optimized(type, left, right)
type when Ops.is_primitive_float_type(type) ->
Orb.Instruction.new(type, :sub, [left, right])
end
end
def left * right do
case Ops.extract_common_type(left, right) do
type when type in [Integer, Float] ->
Kernel.*(left, right)
type when Ops.is_primitive_integer_type(type) ->
Orb.Numeric.Multiply.optimized(type, left, right)
type when Ops.is_primitive_float_type(type) ->
Orb.Instruction.new(type, :mul, [left, right])
end
end
def left / right do
case Ops.extract_common_type(left, right) do
Elixir.Integer ->
Kernel.div(left, right)
Elixir.Float ->
Kernel./(left, right)
type when Ops.is_primitive_integer_type(type) ->
Orb.Instruction.new(type, :div_s, [left, right])
type when Ops.is_primitive_float_type(type) ->
Orb.Instruction.new(type, :div, [left, right])
_ ->
raise Orb.TypeCheckError,
expected_type: Ops.typeof(left),
received_type: Ops.typeof(right),
instruction_identifier: "div"
end
end
def _left == _right do
raise "== is not supported in Orb. Use === instead."
end
def _left != _right do
raise "!= is not supported in Orb. Use !== instead."
end
def left === right do
case Ops.extract_common_type(left, right) do
type when Ops.is_primitive_type(type) ->
Orb.Instruction.Relative.new(type, :eq, left, right)
end
end
def left !== right do
# Orb.Numeric.NotEqual.optimized(Orb.I32, left, right)
case Ops.extract_common_type(left, right) do
type when Ops.is_primitive_type(type) ->
Orb.Instruction.Relative.new(type, :ne, left, right)
end
end
def left < right do
case Ops.extract_common_type(left, right) do
type when Ops.is_primitive_integer_type(type) ->
Orb.Instruction.Relative.new(type, :lt_s, left, right)
type when Ops.is_primitive_float_type(type) ->
Orb.Instruction.Relative.new(type, :lt, left, right)
end
end
def left > right do
case Ops.extract_common_type(left, right) do
type when Ops.is_primitive_integer_type(type) ->
Orb.Instruction.Relative.new(type, :gt_s, left, right)
type when Ops.is_primitive_float_type(type) ->
Orb.Instruction.Relative.new(type, :gt, left, right)
end
end
def left <= right do
case Ops.extract_common_type(left, right) do
type when Ops.is_primitive_integer_type(type) ->
Orb.Instruction.Relative.new(type, :le_s, left, right)
type when Ops.is_primitive_float_type(type) ->
Orb.Instruction.Relative.new(type, :le, left, right)
end
end
def left >= right do
case Ops.extract_common_type(left, right) do
type when Ops.is_primitive_integer_type(type) ->
Orb.Instruction.Relative.new(type, :ge_s, left, right)
type when Ops.is_primitive_float_type(type) ->
Orb.Instruction.Relative.new(type, :ge, left, right)
end
end
@doc """
Bitwise OR operation for i32 or i64 integers.
## Examples
use Orb
defw bitwise_or_example(a: I32, b: I32), I32 do
a ||| b
end
"""
def left ||| right do
case Ops.extract_common_type(left, right) do
type when Ops.is_primitive_integer_type(type) ->
Orb.Instruction.new(type, :or, [left, right])
type when Ops.is_primitive_float_type(type) ->
raise ArgumentError, "Cannot ||| two expressions of type #{type}."
end
end
@doc """
Bitwise AND operation for i32 or i64 integers.
## Examples
use Orb
defw bitwise_and_example(a: I32, b: I32), I32 do
a &&& b
end
"""
def left &&& right do
case Ops.extract_common_type(left, right) do
type when Ops.is_primitive_integer_type(type) ->
Orb.Instruction.new(type, :and, [left, right])
type when Ops.is_primitive_float_type(type) ->
raise ArgumentError, "Cannot &&& two expressions of type #{type}."
end
end
@doc """
Left shift operation for i32 or i64 integers.
## Examples
use Orb
defw left_shift_by_4(a: I32), I32 do
a <<< 4
end
"""
def left <<< right do
case Ops.extract_common_type(left, right) do
type when Ops.is_primitive_integer_type(type) ->
Orb.Instruction.new(type, :shl, [left, right])
type when Ops.is_primitive_float_type(type) ->
raise ArgumentError, "Cannot <<< two expressions of type #{type}."
end
end
@doc """
Logical NOT operation for i32 or i64 integers. Returns i32.
Zero is considered false, all other numbers are considered true.
It does not support short-circuiting.
## Examples
use Orb
defw not_example(a: I32), I32 do
not a
end
"""
def not value do
case Ops.typeof(value, :primitive) do
type when Ops.is_primitive_integer_type(type) ->
Orb.Instruction.new(type, :eqz, [value])
type when Ops.is_primitive_float_type(type) ->
raise ArgumentError, "Cannot NOT two expressions of type #{type}."
end
end
@doc """
Logical OR operation for i32 or i64 integers. Returns i32.
Zero is considered false, all other numbers are considered true.
It does not support short-circuiting.
## Examples
use Orb
defw or_example(a: I32, b: I32), I32 do
a or b
end
"""
def left or right do
case Ops.extract_common_type(left, right) do
:i32 ->
Orb.Instruction.new(:i32, :or, [left, right])
type when Ops.is_primitive_float_type(type) ->
raise ArgumentError, "Cannot OR two expressions of type #{type}."
end
end
@doc """
Logical AND operation for i32 or i64 integers. Returns i32.
Zero is considered false, all other numbers are considered true.
It does not support short-circuiting.
## Examples
use Orb
defw and_example(a: I32, b: I32), I32 do
a and b
end
"""
def left and right do
case Ops.extract_common_type(left, right) do
:i32 ->
Orb.Instruction.new(:i32, :and, [left, right])
type when Ops.is_primitive_float_type(type) ->
raise ArgumentError, "Cannot AND two expressions of type #{type}."
end
end
end