Skip to content

Commit

Permalink
fix resolve function, fix constant propagation
Browse files Browse the repository at this point in the history
  • Loading branch information
mandoway committed Sep 29, 2024
1 parent 402916f commit a3f03eb
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 13 deletions.
18 changes: 9 additions & 9 deletions languages/cue/strategy/astext/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,32 @@ import (
"github.com/mandoway/seru/util/collection"
)

// ResolveIdentifierInExpression NOT COMPLETE
// ResolveIdentifierValueInExpression NOT COMPLETE
// Check source code for supported expressions
func ResolveIdentifierInExpression(expr ast.Expr) ast.Expr {
func ResolveIdentifierValueInExpression(expr ast.Node) ast.Node {
switch typedExpr := expr.(type) {
case *ast.Ident:
resolved := resolveIdentValue(typedExpr)
if resolved == nil {
return expr
return nil
}
return resolved.(ast.Expr)
case *ast.Interpolation:
return NewInterpolation(resolveExpressions(typedExpr.Elts))
case *ast.BinaryExpr:
return ast.NewBinExpr(typedExpr.Op, ResolveIdentifierInExpression(typedExpr.X), ResolveIdentifierInExpression(typedExpr.Y))
return ast.NewBinExpr(typedExpr.Op, ResolveIdentifierValueInExpression(typedExpr.X).(ast.Expr), ResolveIdentifierValueInExpression(typedExpr.Y).(ast.Expr))
case *ast.UnaryExpr:
return CopyUnaryExpression(typedExpr, ResolveIdentifierInExpression(typedExpr.X))
return CopyUnaryExpression(typedExpr, ResolveIdentifierValueInExpression(typedExpr.X).(ast.Expr))
case *ast.CallExpr:
return ast.NewCall(typedExpr.Fun, resolveExpressions(typedExpr.Args)...)
case *ast.IndexExpr:
return CopyIndexExpression(typedExpr, ResolveIdentifierInExpression(typedExpr.Index))
return CopyIndexExpression(typedExpr, ResolveIdentifierValueInExpression(typedExpr.Index).(ast.Expr))
case *ast.SliceExpr:
return CopySliceExpression(typedExpr, ResolveIdentifierInExpression(typedExpr.Low), ResolveIdentifierInExpression(typedExpr.High))
return CopySliceExpression(typedExpr, ResolveIdentifierValueInExpression(typedExpr.Low).(ast.Expr), ResolveIdentifierValueInExpression(typedExpr.High).(ast.Expr))
case *ast.ListLit:
return ast.NewList(resolveExpressions(typedExpr.Elts)...)
case *ast.ParenExpr:
return CopyParenExpression(typedExpr, ResolveIdentifierInExpression(typedExpr.X))
return CopyParenExpression(typedExpr, ResolveIdentifierValueInExpression(typedExpr.X).(ast.Expr))
default:
return expr
}
Expand All @@ -48,7 +48,7 @@ func resolveIdentValue(node *ast.Ident) ast.Node {
return resolveIdentValue(expr)
case *ast.LetClause:
ast.SetRelPos(expr.Expr, token.NoRelPos)
return expr.Expr
return ResolveIdentifierValueInExpression(expr.Expr)
default:
ast.SetRelPos(expr, token.NoRelPos)
return expr
Expand Down
143 changes: 141 additions & 2 deletions languages/cue/strategy/astext/resolve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"testing"
)

func TestResolveIdentifierInExpression(t *testing.T) {
func TestResolveIdentifierInExpression_Field(t *testing.T) {
parsed, _ := language.Parser{}.Parse([]byte(getFile()))

instancesByName := map[string]struct {
Expand Down Expand Up @@ -51,6 +51,10 @@ func TestResolveIdentifierInExpression(t *testing.T) {
name: "paren expr",
expected: "(2)",
},
"k": {
name: "value of let",
expected: "2",
},
}

astutil.Apply(parsed, func(cursor astutil.Cursor) bool {
Expand All @@ -70,7 +74,133 @@ func TestResolveIdentifierInExpression(t *testing.T) {
}

t.Run(instance.name, func(t *testing.T) {
actual := ResolveIdentifierInExpression(field.Value)
actual := ResolveIdentifierValueInExpression(field.Value)
formatted, _ := format.Node(actual)
actualValue := string(formatted)

if actualValue != instance.expected {
t.Errorf("Wrong value, got %s, want %s", actualValue, instance.expected)
}
})

return true
}, nil)
}

func TestResolveIdentifierInExpression_LetClause(t *testing.T) {
parsed, _ := language.Parser{}.Parse([]byte(getFile()))

instancesByName := map[string]struct {
name string
expected string
}{
"j": {
name: "let clause",
expected: "2",
},
}
astutil.Apply(parsed, func(cursor astutil.Cursor) bool {
let, ok := cursor.Node().(*ast.LetClause)
if !ok {
return true
}

instance, ok := instancesByName[let.Ident.Name]
if !ok {
return true
}

t.Run(instance.name, func(t *testing.T) {
actual := ResolveIdentifierValueInExpression(let.Expr)
formatted, _ := format.Node(actual)
actualValue := string(formatted)

if actualValue != instance.expected {
t.Errorf("Wrong value, got %s, want %s", actualValue, instance.expected)
}
})

return true
}, nil)
}

func TestResolveIdentifierInExpression_IfClause(t *testing.T) {
parsed, _ := language.Parser{}.Parse([]byte(getFile()))

instance := struct {
name string
expected string
}{
name: "if clause",
expected: "2 < 2",
}
astutil.Apply(parsed, func(cursor astutil.Cursor) bool {
ifClause, ok := cursor.Node().(*ast.IfClause)
if !ok {
return true
}

t.Run(instance.name, func(t *testing.T) {
actual := ResolveIdentifierValueInExpression(ifClause.Condition)
formatted, _ := format.Node(actual)
actualValue := string(formatted)

if actualValue != instance.expected {
t.Errorf("Wrong value, got %s, want %s", actualValue, instance.expected)
}
})

return true
}, nil)
}

func TestResolveIdentifierInExpression_ForClause(t *testing.T) {
parsed, _ := language.Parser{}.Parse([]byte(getFile()))

instance := struct {
name string
expected string
}{
name: "for clause",
expected: "[1, 2]",
}
astutil.Apply(parsed, func(cursor astutil.Cursor) bool {
forClause, ok := cursor.Node().(*ast.ForClause)
if !ok {
return true
}

t.Run(instance.name, func(t *testing.T) {
actual := ResolveIdentifierValueInExpression(forClause.Source)
formatted, _ := format.Node(actual)
actualValue := string(formatted)

if actualValue != instance.expected {
t.Errorf("Wrong value, got %s, want %s", actualValue, instance.expected)
}
})

return true
}, nil)
}
func TestResolveIdentifierInExpression_Alias(t *testing.T) {
parsed, _ := language.Parser{}.Parse([]byte(getFile()))

instance := struct {
name string
expected string
}{
name: "alias clause",
expected: `"n\(2)"`,
}
astutil.Apply(parsed, func(cursor astutil.Cursor) bool {
alias, ok := cursor.Node().(*ast.Alias)
if !ok {
return true
}

t.Run(instance.name, func(t *testing.T) {
actual := ResolveIdentifierValueInExpression(alias.Expr)
formatted, _ := format.Node(actual)
actualValue := string(formatted)

Expand Down Expand Up @@ -98,6 +228,15 @@ func getFile() string {
g: arr[1:foo+1] // arr[1:2+1]
h: [1, foo] // [1, 2]
i: (foo) // (2)
let j = foo
k: j
if foo < 2 {
l: foo
}
for a in [1, foo] {
m: foo
}
X="n\(foo)": X
}
`
}
2 changes: 1 addition & 1 deletion languages/cue/strategy/constant_propagation.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type ConstantPropagationReduction struct {

func (l ConstantPropagationReduction) Apply(input []byte) []*ast.File {
return transform.ApplyTransformationToEveryApplicableStatement[*ast.Ident](input, func(node *ast.Ident, scope string) transform.Transformation {
resolvedValueNode := astext.ResolveIdentifierInExpression(node)
resolvedValueNode := astext.ResolveIdentifierValueInExpression(node)
if resolvedValueNode == nil {
return transform.NewNoopTransformation()
}
Expand Down
14 changes: 14 additions & 0 deletions languages/cue/strategy/constant_propagation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,17 @@ func TestConstantPropagation(t *testing.T) {

test.TestReduction(t, instances, ConstantPropagationReduction{})
}

func TestConstantPropagationRealWorld(t *testing.T) {
instance := test.ReductionInstance{
Title: "3 variants",
Given: "#B:\n{}\n{}\n{\n{\n{\nfor s in []{\nL\n}\n}\n}\n{\nNS : string\nv:{\n{\n\"\\(NS)/b\":\nL\n}\n}\n}\n}\nlet L=\n#B\n",
Expected: []string{
"#B: {}\n{}\n{\n{\n{\nfor s in [] {\n{}\n}\n}\n}\n{\nNS: string\nv: {\n{\n\"\\(NS)/b\":\nL\n}\n}\n}\n}\nlet L = #B",
"#B: {}\n{}\n{\n{\n{\nfor s in [] {\nL\n}\n}\n}\n{\nNS: string\nv: {\n{\n\"\\(NS)/b\": {}\n}\n}\n}\n}\nlet L = #B",
"#B: {}\n{}\n{\n{\n{\nfor s in [] {\nL\n}\n}\n}\n{\nNS: string\nv: {\n{\n\"\\(NS)/b\":\nL\n}\n}\n}\n}\nlet L = {}",
},
}

test.TestReduction(t, []test.ReductionInstance{instance}, ConstantPropagationReduction{})
}
2 changes: 1 addition & 1 deletion languages/cue/strategy/eval/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func BuildEvaluator(bytes []byte) func(expr ast.Expr) (cue.Value, error) {
scope := cue.Scope(ctx.CompileBytes(bytes))

return func(expr ast.Expr) (cue.Value, error) {
resolved := astext.ResolveIdentifierInExpression(expr)
resolved := astext.ResolveIdentifierValueInExpression(expr)
formattedExpr, err := format.Node(resolved)
if err != nil {
return cue.Value{}, err
Expand Down
1 change: 1 addition & 0 deletions reduction/reduction_loop.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ func applyFirstSemanticStrategy(ctx *context.RunContext, currentBytes []byte) ([
}

// TODO check termination criteria
// combine results of each strategy
func applySemanticStrategiesCombined(ctx *context.RunContext, currentBytes []byte) ([]*candidate.CandidateWithSize, error) {
logging.LogSemantic("Trying strategies and combine results")
var bestCandidate *candidate.CandidateWithSize
Expand Down

0 comments on commit a3f03eb

Please sign in to comment.