Skip to content

Commit

Permalink
Refactoring (#7)
Browse files Browse the repository at this point in the history
* Refactored evaluation

Also improved a technicality in the AST

* Use Go's formatting

* Refactor naming to account for package naming

* Improve comments and address linter warnings

* Update to use struct to reduce parameters in expression evaluation

Also updated dependencies varaiable name for consistency

* Refactor dependencies internal code

Also changed it from map access to bracket access to account for list access
  • Loading branch information
jaredoconnell authored Apr 5, 2023
1 parent 6bd08b9 commit dd56a64
Show file tree
Hide file tree
Showing 17 changed files with 796 additions and 684 deletions.
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# IDE folders
.idea/
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work
118 changes: 61 additions & 57 deletions expression.go
Original file line number Diff line number Diff line change
@@ -1,87 +1,91 @@
package expressions

import (
"fmt"
"fmt"

"go.flow.arcalot.io/expressions/internal/ast"
"go.flow.arcalot.io/pluginsdk/schema"
"go.flow.arcalot.io/expressions/internal/ast"
"go.flow.arcalot.io/pluginsdk/schema"
)

// New parses the specified expression and returns the expression structure.
func New(expressionString string) (Expression, error) {
parser, err := ast.InitParser(expressionString, "workflow.yaml")
if err != nil {
return nil, fmt.Errorf("failed to parse expression: %s (%w)", expressionString, err)
}
exprAst, err := parser.ParseExpression()
if err != nil {
return nil, fmt.Errorf("failed to parse expression: %s (%v)", expressionString, err)
}
parser, err := ast.InitParser(expressionString, "workflow.yaml")
if err != nil {
return nil, fmt.Errorf("failed to parse expression: %s (%w)", expressionString, err)
}
exprAst, err := parser.ParseExpression()
if err != nil {
return nil, fmt.Errorf("failed to parse expression: %s (%v)", expressionString, err)
}

return &expression{
ast: exprAst,
expression: expressionString,
}, nil
return &expression{
ast: exprAst,
expression: expressionString,
}, nil
}

// Expression is an interface describing how expressions should behave.
type Expression interface {
// Type evaluates the expression and evaluates the type on the specified schema.
Type(schema schema.Scope, workflowContext map[string][]byte) (schema.Type, error)
// Dependencies traverses the passed scope and evaluates the items this expression depends on. This is useful to
// construct a dependency tree based on expressions.
Dependencies(schema schema.Scope, workflowContext map[string][]byte) ([]Path, error)
// Evaluate evaluates the expression on the given data set regardless of any
// schema. The caller is responsible for validating the expected schema.
Evaluate(data any, workflowContext map[string][]byte) (any, error)
// String returns the string representation of the expression.
String() string
// Type evaluates the expression and evaluates the type on the specified schema.
Type(schema schema.Scope, workflowContext map[string][]byte) (schema.Type, error)
// Dependencies traverses the passed scope and evaluates the items this expression depends on. This is useful to
// construct a dependency tree based on expressions.
Dependencies(schema schema.Scope, workflowContext map[string][]byte) ([]Path, error)
// Evaluate evaluates the expression on the given data set regardless of any
// schema. The caller is responsible for validating the expected schema.
Evaluate(data any, workflowContext map[string][]byte) (any, error)
// String returns the string representation of the expression.
String() string
}

// expression is the implementation of Expression. It holds the original expression, as well as the parsed AST.
type expression struct {
expression string
ast ast.ASTNode
expression string
ast ast.Node
}

func (e expression) String() string {
return e.expression
return e.expression
}

func (e expression) Type(scope schema.Scope, workflowContext map[string][]byte) (schema.Type, error) {
tree := &PathTree{
PathItem: "$",
Subtrees: nil,
}
d := &dependencyContext{
rootType: scope,
rootPath: tree,
workflowContext: workflowContext,
}
result, _, err := d.dependencies(e.ast, scope, tree)
if err != nil {
return nil, err
}
return result, nil
tree := &PathTree{
PathItem: "$",
Subtrees: nil,
}
d := &dependencyContext{
rootType: scope,
rootPath: tree,
workflowContext: workflowContext,
}
result, _, err := d.dependencies(e.ast, scope, tree)
if err != nil {
return nil, err
}
return result, nil
}

func (e expression) Dependencies(scope schema.Scope, workflowContext map[string][]byte) ([]Path, error) {
tree := &PathTree{
PathItem: "$",
Subtrees: nil,
}
d := &dependencyContext{
rootType: scope,
rootPath: tree,
workflowContext: workflowContext,
}
_, _, err := d.dependencies(e.ast, scope, tree)
if err != nil {
return nil, err
}
return tree.Unpack(), nil
tree := &PathTree{
PathItem: "$",
Subtrees: nil,
}
d := &dependencyContext{
rootType: scope,
rootPath: tree,
workflowContext: workflowContext,
}
_, _, err := d.dependencies(e.ast, scope, tree)
if err != nil {
return nil, err
}
return tree.Unpack(), nil
}

func (e expression) Evaluate(data any, workflowContext map[string][]byte) (any, error) {
return evaluate(e.ast, data, data, workflowContext)
context := &evaluateContext{
rootData: data,
workflowContext: workflowContext,
}
return context.evaluate(e.ast, data)
}
92 changes: 46 additions & 46 deletions expression_data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,50 @@ package expressions_test
import "go.flow.arcalot.io/pluginsdk/schema"

var testScope = schema.NewScopeSchema(
schema.NewObjectSchema(
"root",
map[string]*schema.PropertySchema{
"foo": schema.NewPropertySchema(
schema.NewObjectSchema(
"foo",
map[string]*schema.PropertySchema{
"bar": schema.NewPropertySchema(
schema.NewStringSchema(nil, nil, nil),
nil,
true,
nil,
nil,
nil,
nil,
nil,
),
},
),
nil,
true,
nil,
nil,
nil,
nil,
nil,
),
"faz": schema.NewPropertySchema(
schema.NewMapSchema(
schema.NewStringSchema(nil, nil, nil),
schema.NewObjectSchema(
"foo",
map[string]*schema.PropertySchema{},
),
nil, nil,
),
nil,
true,
nil,
nil,
nil,
nil,
nil,
),
},
),
schema.NewObjectSchema(
"root",
map[string]*schema.PropertySchema{
"foo": schema.NewPropertySchema(
schema.NewObjectSchema(
"foo",
map[string]*schema.PropertySchema{
"bar": schema.NewPropertySchema(
schema.NewStringSchema(nil, nil, nil),
nil,
true,
nil,
nil,
nil,
nil,
nil,
),
},
),
nil,
true,
nil,
nil,
nil,
nil,
nil,
),
"faz": schema.NewPropertySchema(
schema.NewMapSchema(
schema.NewStringSchema(nil, nil, nil),
schema.NewObjectSchema(
"foo",
map[string]*schema.PropertySchema{},
),
nil, nil,
),
nil,
true,
nil,
nil,
nil,
nil,
nil,
),
},
),
)
Loading

0 comments on commit dd56a64

Please sign in to comment.