haven/nexgb/xgbgen/expression.go

276 lines
4.9 KiB
Go

package main
import (
"fmt"
"log"
)
type Expression interface {
Concrete() bool
Eval() uint
Reduce(prefix, fun string) string
String() string
Initialize(p *Protocol)
}
type BinaryOp struct {
Op string
Expr1 Expression
Expr2 Expression
}
func newBinaryOp(op string, expr1, expr2 Expression) Expression {
switch {
case expr1 != nil && expr2 != nil:
return &BinaryOp{
Op: op,
Expr1: expr1,
Expr2: expr2,
}
case expr1 != nil && expr2 == nil:
return expr1
case expr1 == nil && expr2 != nil:
return expr2
case expr1 == nil && expr2 == nil:
return nil
}
panic("unreachable")
}
func (e *BinaryOp) Concrete() bool {
return e.Expr1.Concrete() && e.Expr2.Concrete()
}
func (e *BinaryOp) Eval() uint {
switch e.Op {
case "+":
return e.Expr1.Eval() + e.Expr2.Eval()
case "-":
return e.Expr1.Eval() - e.Expr2.Eval()
case "*":
return e.Expr1.Eval() * e.Expr2.Eval()
case "/":
return e.Expr1.Eval() / e.Expr2.Eval()
case "&":
return e.Expr1.Eval() & e.Expr2.Eval()
case "<<":
return e.Expr1.Eval() << e.Expr2.Eval()
}
log.Fatalf("Invalid binary operator '%s' for expression.", e.Op)
panic("unreachable")
}
func (e *BinaryOp) Reduce(prefix, fun string) string {
if e.Concrete() {
return fmt.Sprintf("%d", e.Eval())
}
return fmt.Sprintf("(%s %s %s)",
e.Expr1.Reduce(prefix, fun), e.Op, e.Expr2.Reduce(prefix, fun))
}
func (e *BinaryOp) String() string {
return e.Reduce("", "")
}
func (e *BinaryOp) Initialize(p *Protocol) {
e.Expr1.Initialize(p)
e.Expr2.Initialize(p)
}
type UnaryOp struct {
Op string
Expr Expression
}
func (e *UnaryOp) Concrete() bool {
return e.Expr.Concrete()
}
func (e *UnaryOp) Eval() uint {
switch e.Op {
case "~":
return ^e.Expr.Eval()
}
log.Fatalf("Invalid unary operator '%s' for expression.", e.Op)
panic("unreachable")
}
func (e *UnaryOp) Reduce(prefix, fun string) string {
if e.Concrete() {
return fmt.Sprintf("%d", e.Eval())
}
return fmt.Sprintf("(%s (%s))", e.Op, e.Expr.Reduce(prefix, fun))
}
func (e *UnaryOp) String() string {
return e.Reduce("", "")
}
func (e *UnaryOp) Initialize(p *Protocol) {
e.Expr.Initialize(p)
}
type PopCount struct {
Expr Expression
}
func (e *PopCount) Concrete() bool {
return e.Expr.Concrete()
}
func (e *PopCount) Eval() uint {
return popCount(e.Expr.Eval())
}
func (e *PopCount) Reduce(prefix, fun string) string {
if e.Concrete() {
return fmt.Sprintf("%d", e.Eval())
}
return fmt.Sprintf("popCount(%s)", e.Expr.Reduce(prefix, fun))
}
func (e *PopCount) String() string {
return e.Reduce("", "")
}
func (e *PopCount) Initialize(p *Protocol) {
e.Expr.Initialize(p)
}
type Value struct {
v uint
}
func (e *Value) Concrete() bool {
return true
}
func (e *Value) Eval() uint {
return e.v
}
func (e *Value) Reduce(prefix, fun string) string {
return fmt.Sprintf("%d", e.v)
}
func (e *Value) String() string {
return e.Reduce("", "")
}
func (e *Value) Initialize(p *Protocol) {}
type Bit struct {
b uint
}
func (e *Bit) Concrete() bool {
return true
}
func (e *Bit) Eval() uint {
return 1 << e.b
}
func (e *Bit) Reduce(prefix, fun string) string {
return fmt.Sprintf("%d", e.Eval())
}
func (e *Bit) String() string {
return e.Reduce("", "")
}
func (e *Bit) Initialize(p *Protocol) {}
type FieldRef struct {
Name string
}
func (e *FieldRef) Concrete() bool {
return false
}
func (e *FieldRef) Eval() uint {
log.Fatalf("Cannot evaluate a 'FieldRef'. It is not concrete.")
panic("unreachable")
}
func (e *FieldRef) Reduce(prefix, fun string) string {
val := e.Name
if len(prefix) > 0 {
val = fmt.Sprintf("%s%s", prefix, val)
}
if len(fun) > 0 {
val = fmt.Sprintf("%s(%s)", fun, val)
}
return val
}
func (e *FieldRef) String() string {
return e.Reduce("", "")
}
func (e *FieldRef) Initialize(p *Protocol) {
e.Name = SrcName(e.Name)
}
type EnumRef struct {
EnumKind Type
EnumItem string
}
func (e *EnumRef) Concrete() bool {
return false
}
func (e *EnumRef) Eval() uint {
log.Fatalf("Cannot evaluate an 'EnumRef'. It is not concrete.")
panic("unreachable")
}
func (e *EnumRef) Reduce(prefix, fun string) string {
val := fmt.Sprintf("%s%s", e.EnumKind, e.EnumItem)
if len(fun) > 0 {
val = fmt.Sprintf("%s(%s)", fun, val)
}
return val
}
func (e *EnumRef) String() string {
return e.Reduce("", "")
}
func (e *EnumRef) Initialize(p *Protocol) {
e.EnumKind = e.EnumKind.(*Translation).RealType(p)
e.EnumItem = SrcName(e.EnumItem)
}
type SumOf struct {
Name string
}
func (e *SumOf) Concrete() bool {
return false
}
func (e *SumOf) Eval() uint {
log.Fatalf("Cannot evaluate a 'SumOf'. It is not concrete.")
panic("unreachable")
}
func (e *SumOf) Reduce(prefix, fun string) string {
if len(prefix) > 0 {
return fmt.Sprintf("sum(%s%s)", prefix, e.Name)
}
return fmt.Sprintf("sum(%s)", e.Name)
}
func (e *SumOf) String() string {
return e.Reduce("", "")
}
func (e *SumOf) Initialize(p *Protocol) {
e.Name = SrcName(e.Name)
}