From 6f3eff438ea64c149263ae006e76ff2fb495a56a Mon Sep 17 00:00:00 2001 From: Ryan Bullock Date: Wed, 22 May 2024 15:58:51 -0700 Subject: [PATCH] Do separate patcher phase for those that require multiple passes (Currently only need for Operator overloading). This patcher phase is run after other patchers. --- checker/checker.go | 64 +++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/checker/checker.go b/checker/checker.go index cef2c012..917a9d7c 100644 --- a/checker/checker.go +++ b/checker/checker.go @@ -13,6 +13,40 @@ import ( "github.com/expr-lang/expr/parser" ) +// Run visitors in a given config over the given tree +// runRepeatable controls whether to filter for only vistors that require multiple passes or not +func runVisitors(tree *parser.Tree, config *conf.Config, runRepeatable bool) { + for { + more := false + for _, v := range config.Visitors { + // We need to perform types check, because some visitors may rely on + // types information available in the tree. + _, _ = Check(tree, config) + + r, repeatable := v.(interface { + Reset() + ShouldRepeat() bool + }) + + if repeatable { + if runRepeatable { + r.Reset() + ast.Walk(&tree.Node, v) + more = more || r.ShouldRepeat() + } + } else { + if !runRepeatable { + ast.Walk(&tree.Node, v) + } + } + } + + if !more { + break + } + } +} + // ParseCheck parses input expression and checks its types. Also, it applies // all provided patchers. In case of error, it returns error with a tree. func ParseCheck(input string, config *conf.Config) (*parser.Tree, error) { @@ -22,33 +56,11 @@ func ParseCheck(input string, config *conf.Config) (*parser.Tree, error) { } if len(config.Visitors) > 0 { - for { - more := false - for _, v := range config.Visitors { - // We need to perform types check, because some visitors may rely on - // types information available in the tree. - _, _ = Check(tree, config) - - r, repeatable := v.(interface { - Reset() - ShouldRepeat() bool - }); - - if repeatable { - r.Reset() - } - - ast.Walk(&tree.Node, v) - - if repeatable { - more = more || r.ShouldRepeat() - } - } + // Run all patchers that dont support being run repeatedly first + runVisitors(tree, config, false) - if !more { - break - } - } + // Run patchers that require multiple passes next (currently only Operator patching) + runVisitors(tree, config, true) } _, err = Check(tree, config) if err != nil {