A Lisp implemented in AWK
# SPDX-License-Identifier: BSD-2-Clause

function _eval3_math(form, env, d,       car, a) {
    car = _car(form)
    if(car == _symbol("only2+"))
        return _only2_add(_eval3(_cadr(form), env, env, d+1),
                          _eval3(_caddr(form), env, env, d+1))
    else if(car == _symbol("only2*"))
        return _only2_multiply(_eval3(_cadr(form), env, env, d+1),
                               _eval3(_caddr(form), env, env, d+1))
    else if(car == _symbol("only2-"))
        return _only2_subtract(_eval3(_cadr(form), env, env, d+1),
                               _eval3(_caddr(form), env, env, d+1))
    else if(car == _symbol("only2/"))
        return _only2_divide(_eval3(_cadr(form), env, env, d+1),
                             _eval3(_caddr(form), env, env, d+1))
    else if(car == _symbol("only2//"))
        return _only2_quotient( \
            _eval3(_cadr(form), env, env, d+1),
            _eval3(_caddr(form), env, env, d+1))
    else if(car == _symbol("only2%"))
        return _only2_modulo(_eval3(_cadr(form), env, env, d+1),
                             _eval3(_caddr(form), env, env, d+1))
    else if(car == _symbol("only2**"))
        return _only2_power(_eval3(_cadr(form), env, env, d+1),
                            _eval3(_caddr(form), env, env, d+1))
    else if(car == _symbol("atan2"))
        return _atan2(_eval3(_cadr(form), env, env, d+1),
                      _eval3(_caddr(form), env, env, d+1))
    else if(car == _symbol("cos"))
        return _cos(_eval3(_cadr(form), env, env, d+1))
    else if(car == _symbol("sin"))
        return _sin(_eval3(_cadr(form), env, env, d+1))
    else if(car == _symbol("exp"))
        return _exp(_eval3(_cadr(form), env, env, d+1))
    else if(car == _symbol("log"))
        return _log(_eval3(_cadr(form), env, env, d+1))
    else if(car == _symbol("sqrt"))
        return _sqrt(_eval3(_cadr(form), env, env, d+1))
    else if(car == _symbol("rand"))
        return _number(rand())
    else if(car == _symbol("srand"))
        return _srand(_eval3(_cadr(form), env, env, d+1))
    else if(car == _symbol("int"))
        return _int(_eval3(_cadr(form), env, env, d+1))
    else _builtin_mischaracterization("_eval3_math", car)
}


function _only2_add(a, b,      tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        split(b, tv)
        if(tv[1] == "#") {
            b = tv[2]
            return _number(a+b)
        }
    }
    # if either a or b was not a number, we're here
    logg_err("_only2_add", "non-numeric operand", d)
    return _nil()
}

function _only2_multiply(a, b,      tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        split(b, tv)
        if(tv[1] == "#") {
            b = tv[2]
            return _number(a*b)
        }
    }
    # if either a or b was not a number, we're here
    logg_err("_only2_multiply", "non-numeric operand", d)
    return _nil()
}

function _only2_subtract(a, b,      tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        split(b, tv)
        if(tv[1] == "#") {
            b = tv[2]
            return _number(a-b)
        }
    }
    # if either a or b was not a number, we're here
    logg_err("_only2_subtract", "non-numeric operand", d)
    return _nil()
}

function _only2_divide(a, b,      tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        split(b, tv)
        if(tv[1] == "#") {
            b = tv[2]
            if(b==0) {
                logg_err("_only2_divide", "divide by zero", d)
                return _nil()
            }
            return _number(a/b)
        }
    }
    # if either a or b was not a number, we're here
    logg_err("_only2_divide", "non-numeric operand", d)
    return _nil()
}

function _only2_quotient(a, b,      tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        split(b, tv)
        if(tv[1] == "#") {
            b = tv[2]
            if(b==0) {
                logg_err("_only2_quotient", "quotient by zero", d)
                return _nil()
            }            
            return _number(int(a/b))
        }
    }
    # if either a or b was not a number, we're here
    logg_err("_only2_quotient", "non-numeric operand", d)
    return _nil()
}

function _only2_modulo(a, b,      tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        split(b, tv)
        if(tv[1] == "#") {
            b = tv[2]
            if(b==0) {
                logg_err("_only2_modulo", "modulo by zero", d)
                return _nil()
            }
            return _number(a%b)
        }
    }
    # if either a or b was not a number, we're here
    logg_err("_only2_modulo", "non-numeric operand", d)
    return _nil()
}

function _only2_power(a, b,      tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        split(b, tv)
        if(tv[1] == "#") {
            b = tv[2]
            return _number(a^b)
        }
    }
    # if either a or b was not a number, we're here
    logg_err("_only2_power", "non-numeric operand", d)
    return _nil()
}

function _atan2(a, b,      tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        split(b, tv)
        if(tv[1] == "#") {
            b = tv[2]
            return _number(atan2(a,b))
        }
    }
    # if either a or b was not a number, we're here
    logg_err("_atan2", "non-numeric operand", d)
    return _nil()
}

function _cos(a,     tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        return _number(cos(a))
    } else {
        logg_err("_cos", "non-numeric-operand", d)
        return _nil()
    }
}

function _sin(a,     tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        return _number(sin(a))
    } else {
        logg_err("_sin", "non-numeric-operand", d)
        return _nil()
    }
}

function _exp(a,     tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        return _number(exp(a))
    } else {
        logg_err("_exp", "non-numeric-operand", d)
        return _nil()
    }
}

function _log(a,     tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        return _number(log(a))
    } else {
        logg_err("_log", "non-numeric-operand", d)
        return _nil()
    }
}

function _sqrt(a,     tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        return _number(sqrt(a))
    } else {
        logg_err("_sqrt", "non-numeric-operand", d)
        return _nil()
    }
}

function _srand(a,     tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        return _number(srand(a))
    } else {
        logg_err("_srand", "non-numeric-operand", d)
        return _nil()
    }
}

function _int(a,     tv) {
    split(a, tv)
    if(tv[1] == "#") {
        a = tv[2]
        return _number(int(a))
    } else {
        logg_err("_int", "non-numeric-operand", d)
        return _nil()
    }
}