mirror of
https://codeberg.org/scip/tablizer.git
synced 2025-12-18 04:51:05 +01:00
247 lines
5.7 KiB
Go
247 lines
5.7 KiB
Go
package zygo
|
|
|
|
import (
|
|
"errors"
|
|
"math"
|
|
)
|
|
|
|
type IntegerOp int
|
|
|
|
const (
|
|
ShiftLeft IntegerOp = iota
|
|
ShiftRightArith
|
|
ShiftRightLog
|
|
Modulo
|
|
BitAnd
|
|
BitOr
|
|
BitXor
|
|
)
|
|
|
|
var WrongType error = errors.New("operands have invalid type")
|
|
|
|
func IntegerDo(op IntegerOp, a, b Sexp) (Sexp, error) {
|
|
var ia *SexpInt
|
|
var ib *SexpInt
|
|
|
|
switch i := a.(type) {
|
|
case *SexpInt:
|
|
ia = i
|
|
case *SexpUint64:
|
|
return UintegerDo(op, i, b)
|
|
case *SexpChar:
|
|
ia = &SexpInt{Val: int64(i.Val)}
|
|
default:
|
|
return SexpNull, WrongType
|
|
}
|
|
|
|
switch i := b.(type) {
|
|
case *SexpInt:
|
|
ib = i
|
|
case *SexpUint64:
|
|
return UintegerDo(op, &SexpUint64{Val: uint64(ia.Val)}, b)
|
|
case *SexpChar:
|
|
ib = &SexpInt{Val: int64(i.Val)}
|
|
default:
|
|
return SexpNull, WrongType
|
|
}
|
|
|
|
switch op {
|
|
case ShiftLeft:
|
|
return &SexpInt{Val: ia.Val << uint(ib.Val)}, nil
|
|
case ShiftRightArith:
|
|
return &SexpInt{Val: ia.Val >> uint(ib.Val)}, nil
|
|
case ShiftRightLog:
|
|
return &SexpInt{Val: int64(uint(ia.Val) >> uint(ib.Val))}, nil
|
|
case Modulo:
|
|
return &SexpInt{Val: ia.Val % ib.Val}, nil
|
|
case BitAnd:
|
|
return &SexpInt{Val: ia.Val & ib.Val}, nil
|
|
case BitOr:
|
|
return &SexpInt{Val: ia.Val | ib.Val}, nil
|
|
case BitXor:
|
|
return &SexpInt{Val: ia.Val ^ ib.Val}, nil
|
|
}
|
|
return SexpNull, errors.New("unrecognized shift operation")
|
|
}
|
|
|
|
func UintegerDo(op IntegerOp, ia *SexpUint64, b Sexp) (Sexp, error) {
|
|
var ib *SexpUint64
|
|
|
|
switch i := b.(type) {
|
|
case *SexpUint64:
|
|
ib = i
|
|
case *SexpInt:
|
|
ib = &SexpUint64{Val: uint64(i.Val)}
|
|
case *SexpChar:
|
|
ib = &SexpUint64{Val: uint64(i.Val)}
|
|
default:
|
|
return SexpNull, WrongType
|
|
}
|
|
|
|
switch op {
|
|
case ShiftLeft:
|
|
return &SexpUint64{Val: ia.Val << ib.Val}, nil
|
|
case ShiftRightArith:
|
|
return &SexpUint64{Val: ia.Val >> ib.Val}, nil
|
|
case ShiftRightLog:
|
|
return &SexpUint64{Val: ia.Val >> ib.Val}, nil
|
|
case Modulo:
|
|
return &SexpUint64{Val: ia.Val % ib.Val}, nil
|
|
case BitAnd:
|
|
return &SexpUint64{Val: ia.Val & ib.Val}, nil
|
|
case BitOr:
|
|
return &SexpUint64{Val: ia.Val | ib.Val}, nil
|
|
case BitXor:
|
|
return &SexpUint64{Val: ia.Val ^ ib.Val}, nil
|
|
}
|
|
return SexpNull, errors.New("unrecognized shift operation")
|
|
}
|
|
|
|
type NumericOp int
|
|
|
|
const (
|
|
Add NumericOp = iota
|
|
Sub
|
|
Mult
|
|
Div
|
|
Pow
|
|
)
|
|
|
|
func NumericFloatDo(op NumericOp, a, b *SexpFloat) Sexp {
|
|
switch op {
|
|
case Add:
|
|
return &SexpFloat{Val: a.Val + b.Val}
|
|
case Sub:
|
|
return &SexpFloat{Val: a.Val - b.Val}
|
|
case Mult:
|
|
return &SexpFloat{Val: a.Val * b.Val}
|
|
case Div:
|
|
return &SexpFloat{Val: a.Val / b.Val}
|
|
case Pow:
|
|
return &SexpFloat{Val: math.Pow(float64(a.Val), float64(b.Val))}
|
|
}
|
|
return SexpNull
|
|
}
|
|
|
|
func NumericIntDo(op NumericOp, a, b *SexpInt) Sexp {
|
|
switch op {
|
|
case Add:
|
|
return &SexpInt{Val: a.Val + b.Val}
|
|
case Sub:
|
|
return &SexpInt{Val: a.Val - b.Val}
|
|
case Mult:
|
|
return &SexpInt{Val: a.Val * b.Val}
|
|
case Div:
|
|
if a.Val%b.Val == 0 {
|
|
return &SexpInt{Val: a.Val / b.Val}
|
|
} else {
|
|
return &SexpFloat{Val: float64(a.Val) / float64(b.Val)}
|
|
}
|
|
case Pow:
|
|
return &SexpInt{Val: int64(math.Pow(float64(a.Val), float64(b.Val)))}
|
|
}
|
|
return SexpNull
|
|
}
|
|
|
|
func NumericUint64Do(op NumericOp, a, b *SexpUint64) Sexp {
|
|
switch op {
|
|
case Add:
|
|
return &SexpUint64{Val: a.Val + b.Val}
|
|
case Sub:
|
|
return &SexpUint64{Val: a.Val - b.Val}
|
|
case Mult:
|
|
return &SexpUint64{Val: a.Val * b.Val}
|
|
case Div:
|
|
if a.Val%b.Val == 0 {
|
|
return &SexpUint64{Val: a.Val / b.Val}
|
|
} else {
|
|
return &SexpFloat{Val: float64(a.Val) / float64(b.Val)}
|
|
}
|
|
case Pow:
|
|
return &SexpUint64{Val: uint64(math.Pow(float64(a.Val), float64(b.Val)))}
|
|
}
|
|
return SexpNull
|
|
}
|
|
|
|
func NumericMatchFloat(op NumericOp, a *SexpFloat, b Sexp) (Sexp, error) {
|
|
var fb *SexpFloat
|
|
switch tb := b.(type) {
|
|
case *SexpFloat:
|
|
fb = tb
|
|
case *SexpInt:
|
|
fb = &SexpFloat{Val: float64(tb.Val)}
|
|
case *SexpUint64:
|
|
fb = &SexpFloat{Val: float64(tb.Val)}
|
|
case *SexpChar:
|
|
fb = &SexpFloat{Val: float64(tb.Val)}
|
|
default:
|
|
return SexpNull, WrongType
|
|
}
|
|
return NumericFloatDo(op, a, fb), nil
|
|
}
|
|
|
|
func NumericMatchInt(op NumericOp, a *SexpInt, b Sexp) (Sexp, error) {
|
|
switch tb := b.(type) {
|
|
case *SexpFloat:
|
|
return NumericFloatDo(op, &SexpFloat{Val: float64(a.Val)}, tb), nil
|
|
case *SexpInt:
|
|
return NumericIntDo(op, a, tb), nil
|
|
case *SexpUint64:
|
|
return NumericUint64Do(op, &SexpUint64{Val: uint64(a.Val)}, tb), nil
|
|
case *SexpChar:
|
|
return NumericIntDo(op, a, &SexpInt{Val: int64(tb.Val)}), nil
|
|
}
|
|
return SexpNull, WrongType
|
|
}
|
|
|
|
func NumericMatchUint64(op NumericOp, a *SexpUint64, b Sexp) (Sexp, error) {
|
|
switch tb := b.(type) {
|
|
case *SexpFloat:
|
|
return NumericFloatDo(op, &SexpFloat{Val: float64(a.Val)}, tb), nil
|
|
case *SexpInt:
|
|
return NumericUint64Do(op, a, &SexpUint64{Val: uint64(tb.Val)}), nil
|
|
case *SexpUint64:
|
|
return NumericUint64Do(op, a, tb), nil
|
|
case *SexpChar:
|
|
return NumericUint64Do(op, a, &SexpUint64{Val: uint64(tb.Val)}), nil
|
|
}
|
|
return SexpNull, WrongType
|
|
}
|
|
|
|
func NumericMatchChar(op NumericOp, a *SexpChar, b Sexp) (Sexp, error) {
|
|
var res Sexp
|
|
switch tb := b.(type) {
|
|
case *SexpFloat:
|
|
res = NumericFloatDo(op, &SexpFloat{Val: float64(a.Val)}, tb)
|
|
case *SexpInt:
|
|
res = NumericIntDo(op, &SexpInt{Val: int64(a.Val)}, tb)
|
|
case *SexpUint64:
|
|
return NumericUint64Do(op, &SexpUint64{Val: uint64(a.Val)}, tb), nil
|
|
case *SexpChar:
|
|
res = NumericIntDo(op, &SexpInt{Val: int64(a.Val)}, &SexpInt{Val: int64(tb.Val)})
|
|
default:
|
|
return SexpNull, WrongType
|
|
}
|
|
switch tres := res.(type) {
|
|
case *SexpFloat:
|
|
return tres, nil
|
|
case *SexpInt:
|
|
return &SexpChar{Val: rune(tres.Val)}, nil
|
|
}
|
|
return SexpNull, errors.New("unexpected result")
|
|
}
|
|
|
|
func NumericDo(op NumericOp, a, b Sexp) (Sexp, error) {
|
|
switch ta := a.(type) {
|
|
case *SexpFloat:
|
|
return NumericMatchFloat(op, ta, b)
|
|
case *SexpInt:
|
|
return NumericMatchInt(op, ta, b)
|
|
case *SexpUint64:
|
|
return NumericMatchUint64(op, ta, b)
|
|
case *SexpChar:
|
|
return NumericMatchChar(op, ta, b)
|
|
}
|
|
return SexpNull, WrongType
|
|
}
|