Skip to content

Commit

Permalink
refactor: unify Func,Macro interfaces to Op interface
Browse files Browse the repository at this point in the history
  • Loading branch information
tyru committed Apr 22, 2018
1 parent f3d9e28 commit efc7426
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 85 deletions.
4 changes: 2 additions & 2 deletions dsl/deparse.go
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
27 changes: 16 additions & 11 deletions dsl/op/array.go
Original file line number Diff line number Diff line change
@@ -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
}
13 changes: 6 additions & 7 deletions dsl/op/do.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,22 @@ import (
func init() {
opName := doOp("do")
DoOp = &opName
funcMap["do"] = DoOp
opsMap["do"] = DoOp
}

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++ {
Expand All @@ -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()
Expand All @@ -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()) }()
Expand Down
25 changes: 14 additions & 11 deletions dsl/op/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
27 changes: 16 additions & 11 deletions dsl/op/invert.go
Original file line number Diff line number Diff line change
@@ -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
}
Expand Down
20 changes: 5 additions & 15 deletions dsl/op/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
24 changes: 24 additions & 0 deletions dsl/op/macro.go
Original file line number Diff line number Diff line change
@@ -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()
}
14 changes: 8 additions & 6 deletions dsl/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
18 changes: 9 additions & 9 deletions dsl/types/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
19 changes: 6 additions & 13 deletions dsl/types/op.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit efc7426

Please sign in to comment.