From efc74260df8d3f3d5ca667b1f31555721575bb20 Mon Sep 17 00:00:00 2001 From: tyru Date: Sun, 22 Apr 2018 16:14:07 +0900 Subject: [PATCH] refactor: unify Func,Macro interfaces to Op interface --- dsl/deparse.go | 4 ++-- dsl/op/array.go | 27 ++++++++++++++++----------- dsl/op/do.go | 13 ++++++------- dsl/op/eval.go | 25 ++++++++++++++----------- dsl/op/invert.go | 27 ++++++++++++++++----------- dsl/op/lookup.go | 20 +++++--------------- dsl/op/macro.go | 24 ++++++++++++++++++++++++ dsl/parse.go | 14 ++++++++------ dsl/types/expr.go | 18 +++++++++--------- dsl/types/op.go | 19 ++++++------------- 10 files changed, 106 insertions(+), 85 deletions(-) create mode 100644 dsl/op/macro.go diff --git a/dsl/deparse.go b/dsl/deparse.go index b0a08ce3..36b7090c 100644 --- a/dsl/deparse.go +++ b/dsl/deparse.go @@ -41,8 +41,8 @@ func deparse(value types.Value) (interface{}, error) { case *types.Expr: a := make([]interface{}, 0, len(val.Args())+1) // Do not include "@" in array literal - if val.Func().String() != op.ArrayOp.String() { - a = append(a, types.NewString(val.Func().String())) + if val.Op().String() != op.ArrayOp.String() { + a = append(a, types.NewString(val.Op().String())) } for i := range a { v, err := deparse(val.Args()[i]) diff --git a/dsl/op/array.go b/dsl/op/array.go index 86ad7713..a90b0ddd 100644 --- a/dsl/op/array.go +++ b/dsl/op/array.go @@ -1,26 +1,31 @@ package op import ( + "context" + "github.com/vim-volt/volt/dsl/types" ) func init() { - s := arrayOp("$array") - ArrayOp = &s - macroMap[string(*ArrayOp)] = ArrayOp + opsMap[ArrayOp.String()] = ArrayOp +} + +type arrayOp struct { + macroBase } -type arrayOp string +// ArrayOp is "$array" operator +var ArrayOp = &arrayOp{macroBase("$array")} -// ArrayOp is "$array" operation -var ArrayOp *arrayOp +func (op *arrayOp) InvertExpr(args []types.Value) (types.Value, error) { + return op.macroInvertExpr(op.Execute(context.Background(), args)) +} -// String returns "$array" -func (*arrayOp) String() string { - return string(*ArrayOp) +func (*arrayOp) Bind(args ...types.Value) (*types.Expr, error) { + expr := types.NewExpr(ArrayOp, args, types.NewArrayType(types.AnyValue)) + return expr, nil } -// Execute executes "$array" operation -func (*arrayOp) Expand(args []types.Value) (types.Value, func(), error) { +func (*arrayOp) Execute(ctx context.Context, args []types.Value) (types.Value, func(), error) { return types.NewArray(args, types.AnyValue), NoRollback, nil } diff --git a/dsl/op/do.go b/dsl/op/do.go index f4a6f95d..302657d6 100644 --- a/dsl/op/do.go +++ b/dsl/op/do.go @@ -9,7 +9,7 @@ import ( func init() { opName := doOp("do") DoOp = &opName - funcMap["do"] = DoOp + opsMap["do"] = DoOp } type doOp string @@ -17,12 +17,14 @@ type doOp string // DoOp is "do" operation var DoOp *doOp -// String returns operator name func (*doOp) String() string { return string(*DoOp) } -// Bind binds its arguments, and check if the types of values are correct. +func (*doOp) IsMacro() bool { + return false +} + func (*doOp) Bind(args ...types.Value) (*types.Expr, error) { sig := make([]types.Type, 0, len(args)) for i := 0; i < len(args); i++ { @@ -35,9 +37,7 @@ func (*doOp) Bind(args ...types.Value) (*types.Expr, error) { return types.NewExpr(DoOp, args, retType), nil } -// InvertExpr returns inverted expression: Call Value.Invert() for each argument, -// and reverse arguments order. -func (*doOp) InvertExpr(args []types.Value) (*types.Expr, error) { +func (*doOp) InvertExpr(args []types.Value) (types.Value, error) { newargs := make([]types.Value, len(args)) for i := range args { a, err := args[i].Invert() @@ -49,7 +49,6 @@ func (*doOp) InvertExpr(args []types.Value) (*types.Expr, error) { return DoOp.Bind(newargs...) } -// Execute executes "do" operation func (*doOp) Execute(ctx context.Context, args []types.Value) (val types.Value, rollback func(), err error) { g := funcGuard(DoOp.String()) defer func() { err = g.rollback(recover()) }() diff --git a/dsl/op/eval.go b/dsl/op/eval.go index 246fdcd7..2f8e9bed 100644 --- a/dsl/op/eval.go +++ b/dsl/op/eval.go @@ -7,23 +7,26 @@ import ( ) func init() { - s := evalOp("$eval") - EvalOp = &s - macroMap[string(*EvalOp)] = EvalOp + opsMap[EvalOp.String()] = EvalOp } -type evalOp string +type evalOp struct { + macroBase +} + +// EvalOp is "$eval" operator +var EvalOp = &evalOp{macroBase("$eval")} -// EvalOp is "$eval" operation -var EvalOp *evalOp +func (op *evalOp) InvertExpr(args []types.Value) (types.Value, error) { + return op.macroInvertExpr(op.Execute(context.Background(), args)) +} -// String returns "$eval" -func (*evalOp) String() string { - return string(*EvalOp) +func (*evalOp) Bind(args ...types.Value) (*types.Expr, error) { + expr := types.NewExpr(ArrayOp, args, types.NewArrayType(types.AnyValue)) + return expr, nil } -// Execute executes "$eval" operation -func (*evalOp) Expand(args []types.Value) (types.Value, func(), error) { +func (*evalOp) Execute(ctx context.Context, args []types.Value) (types.Value, func(), error) { if err := signature(types.AnyValue).check(args); err != nil { return nil, NoRollback, err } diff --git a/dsl/op/invert.go b/dsl/op/invert.go index b1892150..956abaf9 100644 --- a/dsl/op/invert.go +++ b/dsl/op/invert.go @@ -1,27 +1,32 @@ package op import ( + "context" + "github.com/vim-volt/volt/dsl/types" ) func init() { - s := invertOp("$invert") - InvertOp = &s - macroMap[string(*InvertOp)] = InvertOp + opsMap[InvertOp.String()] = InvertOp +} + +type invertOp struct { + macroBase } -type invertOp string +// InvertOp is "$invert" operator +var InvertOp = &invertOp{macroBase("$invert")} -// InvertOp is "$invert" operation -var InvertOp *invertOp +func (op *invertOp) InvertExpr(args []types.Value) (types.Value, error) { + return op.macroInvertExpr(op.Execute(context.Background(), args)) +} -// String returns "$invert" -func (*invertOp) String() string { - return string(*InvertOp) +func (*invertOp) Bind(args ...types.Value) (*types.Expr, error) { + expr := types.NewExpr(ArrayOp, args, types.NewArrayType(types.AnyValue)) + return expr, nil } -// Execute executes "$invert" operation -func (*invertOp) Expand(args []types.Value) (types.Value, func(), error) { +func (*invertOp) Execute(ctx context.Context, args []types.Value) (types.Value, func(), error) { if err := signature(types.AnyValue).check(args); err != nil { return nil, NoRollback, err } diff --git a/dsl/op/lookup.go b/dsl/op/lookup.go index 5d15a5d3..ce63e008 100644 --- a/dsl/op/lookup.go +++ b/dsl/op/lookup.go @@ -2,22 +2,12 @@ package op import "github.com/vim-volt/volt/dsl/types" -// funcMap holds all operation structs. +// opsMap holds all operation structs. // All operations in dsl/op/*.go sets its struct to this in init() -var funcMap map[string]types.Func +var opsMap map[string]types.Op -// LookupFunc looks up function name -func LookupFunc(name string) (types.Func, bool) { - op, exists := funcMap[name] - return op, exists -} - -// macroMap holds all operation structs. -// All operations in dsl/op/*.go sets its struct to this in init() -var macroMap map[string]types.Macro - -// LookupMacro looks up macro name -func LookupMacro(name string) (types.Macro, bool) { - op, exists := macroMap[name] +// Lookup looks up operator name +func Lookup(name string) (types.Op, bool) { + op, exists := opsMap[name] return op, exists } diff --git a/dsl/op/macro.go b/dsl/op/macro.go new file mode 100644 index 00000000..cf620404 --- /dev/null +++ b/dsl/op/macro.go @@ -0,0 +1,24 @@ +package op + +import ( + "github.com/vim-volt/volt/dsl/types" +) + +type macroBase string + +// String returns "$array" +func (m *macroBase) String() string { + return string(*m) +} + +func (*macroBase) IsMacro() bool { + return true +} + +// Invert the result of op.Execute() which expands an expression +func (*macroBase) macroInvertExpr(val types.Value, _ func(), err error) (types.Value, error) { + if err != nil { + return nil, err + } + return val.Invert() +} diff --git a/dsl/parse.go b/dsl/parse.go index 09c911a6..643288da 100644 --- a/dsl/parse.go +++ b/dsl/parse.go @@ -51,14 +51,16 @@ func parseArray(array []interface{}) (types.Value, error) { } args = append(args, v) } - if macro, exists := op.LookupMacro(opName); exists { - val, _, err := macro.Expand(args) - return val, err + op, exists := op.Lookup(opName) + if !exists { + return nil, fmt.Errorf("no such operation '%s'", opName) } - if fn, exists := op.LookupFunc(opName); exists { - return fn.Bind(args...) + // Expand macro's expression at parsing time + if op.IsMacro() { + val, _, err := op.Execute(args) + return val, err } - return nil, fmt.Errorf("no such operation '%s'", opName) + return op.Bind(args...) } func parse(value interface{}) (types.Value, error) { diff --git a/dsl/types/expr.go b/dsl/types/expr.go index 612fb615..cf959782 100644 --- a/dsl/types/expr.go +++ b/dsl/types/expr.go @@ -4,14 +4,14 @@ import "context" // Expr has an operation and its arguments type Expr struct { - fun Func + op Op args []Value retType Type } -// Func returns function of Expr -func (expr *Expr) Func() Func { - return expr.fun +// Op returns operator of Expr +func (expr *Expr) Op() Op { + return expr.op } // Args returns arguments of Expr @@ -25,19 +25,19 @@ func (expr *Expr) RetType() Type { } // NewExpr creates Expr instance -func NewExpr(fun Func, args []Value, retType Type) *Expr { - return &Expr{fun: fun, args: args, retType: retType} +func NewExpr(op Op, args []Value, retType Type) *Expr { + return &Expr{op: op, args: args, retType: retType} } // Eval evaluates given expression expr with given transaction ID trxID. func (expr *Expr) Eval(ctx context.Context) (val Value, rollback func(), err error) { - return expr.fun.Execute(ctx, expr.args) + return expr.op.Execute(ctx, expr.args) } // Invert inverts this expression. -// This just calls Func.InvertExpr() with arguments. +// This just calls Op().InvertExpr() with saved arguments. func (expr *Expr) Invert() (Value, error) { - return expr.fun.InvertExpr(expr.args) + return expr.op.InvertExpr(expr.args) } // Type returns the type. diff --git a/dsl/types/op.go b/dsl/types/op.go index 751d76d3..fafeec38 100644 --- a/dsl/types/op.go +++ b/dsl/types/op.go @@ -2,27 +2,20 @@ package types import "context" -// Func is an operation of JSON DSL -type Func interface { +// Op is an operation of JSON DSL +type Op interface { // String returns function name String() string // InvertExpr returns inverted expression - InvertExpr(args []Value) (*Expr, error) + InvertExpr(args []Value) (Value, error) - // Bind binds its arguments, and check if the types of values are correct. + // Bind binds its arguments, and check if the types of values are correct Bind(args ...Value) (*Expr, error) // Execute executes this operation and returns its result value and error Execute(ctx context.Context, args []Value) (ret Value, rollback func(), err error) -} - -// Macro is an operation of JSON DSL -type Macro interface { - // String returns macro name - String() string - // Expand expands this expression (operator + args). - // If argument type or arity is different, this returns non-nil error. - Expand(args []Value) (val Value, rollback func(), err error) + // IsMacro returns true if this operator is a macro + IsMacro() bool }