// This example shows a toy calculator AST and how custom actions can be
// introduced into the visitation flow. We've decided to use a visitor
// to stringify the Calculation. It's not how one would generally
// approach this problem, but it's useful to demonstrate more advanced
// flow-control.
This example shows a toy calculator AST and how custom actions can be
introduced into the visitation flow. We've decided to use a visitor
to stringify the Calculation. It's not how one would generally
approach this problem, but it's useful to demonstrate more advanced
flow-control.
// This example shows a toy calculator AST and how custom actions can be // introduced into the visitation flow . We ' ve decided to use a visitor // to stringify the Calculation . It ' s not how one would generally // approach this problem but it ' s useful to demonstrate more advanced // flow - control .
func Example_actions() {
	c := &Calculation{
		Expr: &Func{"Avg", []Expr{
			&BinaryOp{"+", &Scalar{1}, &Scalar{3}},
			&Func{"Sum", []Expr{
				&Scalar{10},
				&Func{"Random", []Expr{&Scalar{1}, &Scalar{10}}},
				&Scalar{99}}},
			&BinaryOp{"*", &Scalar{5}, &Scalar{3}},
		}},
	}
	var w strings.Builder
	_, _, err := WalkCalc(c, func(ctx CalcContext, x Calc) CalcDecision {
		switch t := x.(type) {
		case *BinaryOp:
			return ctx.Actions(
				ctx.ActionVisit(t.Left),
				ctx.ActionCall(func() error { w.WriteString(t.Operator); return nil }),
				ctx.ActionVisit(t.Right),
			)
		case *Func:
			w.WriteString(t.Fn)
			w.WriteString("(")
			comma := ""
			return ctx.Continue().Intercept(func(CalcContext, Calc) (ret CalcDecision) {
				w.WriteString(comma)
				comma = ", "
				return
			}).Post(func(CalcContext, Calc) (ret CalcDecision) {
				w.WriteString(")")
				return
			})
		case *Scalar:
			w.WriteString(strconv.Itoa(t.val))
		}
		return ctx.Continue()
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(w.String())
}
func Example_actions ( ) { c := & Calculation { Expr : & Func { " " , [ ] Expr { & BinaryOp { " " , & Scalar { 1 } , & Scalar { 3 } } , & Func { " " , [ ] Expr { & Scalar { 10 } , & Func { " " , [ ] Expr { & Scalar { 1 } , & Scalar { 10 } } } , & Scalar { 99 } } } , & BinaryOp { " " , & Scalar { 5 } , & Scalar { 3 } } , } } , } var w strings . Builder _ , _ , err := WalkCalc ( c , func ( ctx CalcContext , x Calc ) CalcDecision { switch t := x . ( type ) { case * BinaryOp : return ctx . Actions ( ctx . ActionVisit ( t . Left ) , ctx . ActionCall ( func ( ) error { w . WriteString ( t . Operator ) ; return nil } ) , ctx . ActionVisit ( t . Right ) , ) case * Func : w . WriteString ( t . Fn ) w . WriteString ( " " ) comma := " " return ctx . Continue ( ) . Intercept ( func ( CalcContext , Calc ) ( ret CalcDecision ) { w . WriteString ( comma ) comma = " " return } ) . Post ( func ( CalcContext , Calc ) ( ret CalcDecision ) { w . WriteString ( " " ) return } ) case * Scalar : w . WriteString ( strconv . Itoa ( t . val ) ) } return ctx . Continue ( ) } ) if err != nil { panic ( err ) } fmt . Println ( w . String ( ) ) }
This example shows a toy calculator AST and how custom actions can be
introduced into the visitation flow.
This example shows a toy calculator AST and how custom actions can be introduced into the visitation flow .
// With a BinaryOp, we want to visit left, print the operator, // then right. We'll generate a sequence of actions to be // executed. // With a function, we want to print commas between the arguments. // Rather than creating an arbitrarily number of actions to // perform, an Intercept() function can be registered to // traverse a struct normally and receive a pre-visit for // the immediate children. We combine Intercept() and Post() // to print the closing parenthesis. //Output: //Avg(1+3, Sum(10, Random(1, 10), 99), 5*3)