#!/usr/bin/ruby

class Base { }

class Log < Base {}
class Exp < Base {}
class Sin < Base {}

class Exp(v) {

    method *(Exp o) {
        "Exp: #{self} * #{o}"
    }

    method *(Log o) {
        "Exp: #{self} * #{o}"
    }

    method to_s {
        "Exp"
    }
}

class Log(v) {

    method *(Log o) {
        "Log: #{self} * #{o}"
    }

    method to_s {
        "Log"
    }
}

class Sin(v) {

    method *(Log o) {
        "Sin: #{self} * #{o}"
    }

    method to_s {
        "Sin"
    }
}

class Base {

    method *(Exp o) {
        "Base1: #{self} * #{o}"
    }

    method *(Object o) {
        "Base2: #{self} * #{o}"
    }
}

var e = Exp(1)
var l = Log(5)
var s = Sin(7)

say l*l
say l*e
say s*l

assert_eq(l*l, "Log: Log * Log")
assert_eq(l*e, "Base1: Log * Exp")
assert_eq(e*e, "Exp: Exp * Exp")
assert_eq(e*l, "Exp: Exp * Log")
assert_eq(e*s, "Base2: Exp * Sin")
assert_eq(l*s, "Base2: Log * Sin")
assert_eq(s*s, "Base2: Sin * Sin")
assert_eq(s*l, "Sin: Sin * Log")
assert_eq(s*e, "Base1: Sin * Exp")
assert_eq(l*3, "Base2: Log * 3")
assert_eq(e*4, "Base2: Exp * 4")
assert_eq(s*e, "Base1: Sin * Exp")