ast_expr.go 3.8 KB
package astexpr

import (
	"encoding/json"
	"fmt"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
)

const (
	TypeFunCallerExprAST = "FunCallerExprAST"
	TypeBinaryExprAST    = "BinaryExprAST"
	TypeFieldExprAST     = "FieldExprAST"
	TypeValueExprAST     = "ValueExprAST"
	TypeNumberExprAST    = "NumberExprAST"
)

type ExprAST interface {
	toStr() string
}

type NumberExprAST struct {
	ExprType string `json:"exprType"`
	Val      float64
	Str      string
}

type ValueExprAST struct {
	ExprType string `json:"exprType"`
	Val      string `json:"val"`
	Str      string `json:"str"`
}

type FieldExprAST struct {
	ExprType string             `json:"exprType"`
	Str      string             `json:"str"`
	Field    *domain.TableField `json:"field"`
}

type BinaryExprAST struct {
	ExprType string  `json:"exprType"`
	Op       string  `json:"op"`
	Lhs      ExprAST `json:"lhs"`
	Rhs      ExprAST `json:"rhs"`
}

type FunCallerExprAST struct {
	//ArrayFlag bool      `json:"arrayFlag"`
	ExprType string    `json:"exprType"`
	Name     string    `json:"name"`
	Args     []ExprAST `json:"args"`
}

func (n NumberExprAST) toStr() string {
	return fmt.Sprintf(
		"NumberExprAST:%s",
		n.Str,
	)
}

func (n ValueExprAST) toStr() string {
	return fmt.Sprintf(
		"ValueExprAST:%s",
		n.Str,
	)
}

func (n FieldExprAST) toStr() string {
	return fmt.Sprintf(
		"FieldExprAST:%s",
		n.Str,
	)
}

func (b BinaryExprAST) toStr() string {
	return fmt.Sprintf(
		"BinaryExprAST: (%s %s %s)",
		b.Op,
		b.Lhs.toStr(),
		b.Rhs.toStr(),
	)
}

func (n FunCallerExprAST) toStr() string {
	return fmt.Sprintf(
		"FunCallerExprAST:%s",
		n.Name,
	)
}

type CloneFunCallerExprAST struct {
	//ArrayFlag bool              `json:"arrayFlag"`
	Name string            `json:"name"`
	Arg  []json.RawMessage `json:"args"`
}

type CloneBinaryExprAST struct {
	Op  string          `json:"op"`
	Lhs json.RawMessage `json:"lhs"`
	Rhs json.RawMessage `json:"rhs"`
}

func ExprUnmarshal(data []byte) (interface{}, error) {
	var m = make(map[string]interface{})
	if err := json.Unmarshal(data, &m); err != nil {
		return nil, err
	}
	value, err := unmarshalMapInterface(m, data)
	if err != nil {
		return data, err
	}
	return value, nil
}

func unmarshalMapInterface(m map[string]interface{}, rawData []byte) (interface{}, error) {
	t, ok := m["exprType"]
	if !ok {
		return nil, nil
	}
	if t == TypeFunCallerExprAST {
		expr := &CloneFunCallerExprAST{}
		if err := json.Unmarshal(rawData, expr); err != nil {
			return nil, err
		}
		exprReturn := &FunCallerExprAST{Name: expr.Name, ExprType: TypeFunCallerExprAST}
		for i := range expr.Arg {
			subExpr, err := ExprUnmarshal(expr.Arg[i])
			if err != nil {
				return nil, err
			}
			if subExpr == nil {
				continue
			}
			exprReturn.Args = append(exprReturn.Args, subExpr.(ExprAST))
		}
		return exprReturn, nil
	}
	if t == TypeBinaryExprAST {
		expr := &CloneBinaryExprAST{}
		if err := json.Unmarshal(rawData, expr); err != nil {
			return nil, err
		}
		exprReturn := &BinaryExprAST{Op: expr.Op, ExprType: TypeBinaryExprAST}
		if len(expr.Lhs) > 0 {
			subExpr, err := ExprUnmarshal(expr.Lhs)
			if err != nil {
				return nil, err
			}
			if subExpr != nil {
				exprReturn.Lhs = subExpr.(ExprAST)
			}
		}
		if len(expr.Rhs) > 0 {
			subExpr, err := ExprUnmarshal(expr.Rhs)
			if err != nil {
				return nil, err
			}
			if subExpr != nil {
				exprReturn.Rhs = subExpr.(ExprAST)
			}
		}
		return exprReturn, nil
	}
	if t == TypeFieldExprAST {
		expr := &FieldExprAST{ExprType: TypeFieldExprAST}
		if err := json.Unmarshal(rawData, expr); err != nil {
			return nil, err
		}
		return expr, nil
	}
	if t == TypeValueExprAST {
		expr := &ValueExprAST{ExprType: TypeValueExprAST}
		if err := json.Unmarshal(rawData, expr); err != nil {
			return nil, err
		}
		return expr, nil
	}
	return nil, fmt.Errorf("unkonw expr type '%v'", t)
}