Skip to content

Commit

Permalink
better error messages + multi line error format
Browse files Browse the repository at this point in the history
  • Loading branch information
mandelsoft committed Feb 16, 2019
1 parent 40661de commit ed9d8b6
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 34 deletions.
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4108,11 +4108,12 @@ If a dynaml expression cannot be resolved to a value, it is reported by the
(( <failed expression> )) in <file> <path to node> (<referred path>) <tag><issue>
```
e.g.:
<details><summary><b>Example</b></summary>
```
(( min_ip("10") )) in source.yml node.a.[0] () *CIDR argument required
```
</details>
Cyclic dependencies are detected by iterative evaluation until the document is unchanged after a step.
Nodes involved in a cycle are therefore typically reported just as unresolved node without a specific issue.
Expand All @@ -4129,4 +4130,32 @@ tag. The following tags are used (in reporting order):
Problems occuring during inline template processing are reported as nested problems. The classification is
propagated to the outer node.
If a problem occurs in nested lamba calls the call stack together with the lamba function and is
local binding is listed.
<details><summary><b>Example</b></summary>
```text
(( 2 + .func(2) )) in local/err.yaml value () *evaluation of lambda expression failed: lambda|x|->x > 0 ? _(x - 1) : *(template): {x: 2}
... evaluation of lambda expression failed: lambda|x|->x > 0 ? _(x - 1) : *(template): {x: 1}
... evaluation of lambda expression failed: lambda|x|->x > 0 ? _(x - 1) : *(template): {x: 0}
... resolution of template 'template' failed
(( z )) in local/err.yaml val ()*'z' not found
```
</details>

In case of parsing errors in dynaml expressions, the error location is shown now.
If it is a multi line expression the line a character/symbol number in that line
is show, otherwise the line numer is omitted.

<details><summary><b>Example</b></summary>

```text
((
2 ++ .func(2)
)) in local/err.yaml faulty () *parse error near line 2 symbol 2 - line 2 symbol 3: " "
```
</details>

2 changes: 1 addition & 1 deletion dynaml/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func func_eval(arguments []interface{}, binding Binding, locally bool) (interfac

expr, err := Parse(str, binding.Path(), binding.StubPath())
if err != nil {
return info.Error("%s", err)
return info.Error("(%s)\t %s", str, err)
}
return expr.Evaluate(binding, locally)
}
3 changes: 2 additions & 1 deletion dynaml/lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,9 @@ func (e LambdaValue) Evaluate(args []interface{}, binding Binding, locally bool)
if !ok {
debug.Debug("failed LAMBDA CALL: %s", info.Issue)
nested := info.Issue
info.SetError("evaluation of lambda expression failed: %s", e)
info.SetError("evaluation of lambda expression failed: %s: %s", e, short(inp, false))
info.Issue.Nested = append(info.Issue.Nested, nested)
info.Issue.Sequence = true
return false, nil, info, ok
}
if isExpression(value) {
Expand Down
15 changes: 13 additions & 2 deletions dynaml/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ type operationHelper struct {
op string
}

func lineError(lines, syms, linee, syme int, txt string) string {
return fmt.Sprintf("parse error near symbol %v - symbol %v: %v", syms, syme, txt)
}

func docError(lines, syms, linee, syme int, txt string) string {
return fmt.Sprintf("parse error near line %v symbol %v - line %v symbol %v: %v", lines, syms, linee, syme, txt)
}

func (e *parseError) String() string {
tokens, error := []token32{e.max}, ""
positions, p := make([]int, 2*len(tokens)), 0
Expand All @@ -44,10 +52,13 @@ func (e *parseError) String() string {
positions[p], p = int(token.end), p+1
}
translations := translatePositions(e.p.buffer, positions)
format := "parse error near line %v symbol %v - line %v symbol %v: %v"
errf := lineError
if strings.Index(e.p.Buffer, "\n") >= 0 {
errf = docError
}
for _, token := range tokens {
begin, end := int(token.begin), int(token.end)
error += fmt.Sprintf(format,
error += errf(
translations[begin].line, translations[begin].symbol,
translations[end].line, translations[end].symbol,
strconv.Quote(string(e.p.buffer[begin:end])))
Expand Down
16 changes: 8 additions & 8 deletions dynaml/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,25 +60,25 @@ func (e SyncExpr) Evaluate(binding Binding, locally bool) (interface{}, Evaluati
return info.AnnotateError(infoc, "condition evaluation failed)")
}

if lambda, ok:=cond.(LambdaValue); ok {
args:=[]interface{}{}
if result[CATCH_VALUE]!=nil {
args=append(args, result[CATCH_VALUE].Value())
if lambda, ok := cond.(LambdaValue); ok {
args := []interface{}{}
if result[CATCH_VALUE] != nil {
args = append(args, result[CATCH_VALUE].Value())
} else {
args=append(args,nil)
args = append(args, nil)
}
switch len(lambda.lambda.Names) {
case 1:
case 2:
args=append(args, result[CATCH_ERROR].Value())
args = append(args, result[CATCH_ERROR].Value())
default:
return info.Error("lambda expression for catch must take one or two arguments")
}
resolved, result, sub, ok := lambda.Evaluate(args,binding,locally)
resolved, result, sub, ok := lambda.Evaluate(args, binding, locally)
if !resolved {
return e, sub, ok
}
cond=result
cond = result
}
switch v := cond.(type) {
case bool:
Expand Down
28 changes: 17 additions & 11 deletions dynaml/unresolved_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (e UnresolvedNodes) Issue(msgfmt string, args ...interface{}) (result yaml.
issue := node.Issue()
msg := issue.Issue
if msg != "" {
msg = "\t" + tag(node) + msg
msg = tag(node) + msg
}
if node.HasError() {
localError = true
Expand All @@ -38,14 +38,13 @@ func (e UnresolvedNodes) Issue(msgfmt string, args ...interface{}) (result yaml.
}
switch node.Value().(type) {
case Expression:
format = "\t(( %s ))\tin %s\t%s\t(%s)%s"
format = "(( %s ))\tin %s\t%s\t(%s)%s"
default:
format = "\t%s\tin %s\t%s\t(%s)%s"
format = "%s\tin %s\t%s\t(%s)%s"
}
val:=strings.Replace(fmt.Sprintf("%s", node.Value()),"\n\t", " ", -1 )
message := fmt.Sprintf(
format,
val,
node.Value(),
node.SourceName(),
strings.Join(node.Context, "."),
strings.Join(node.Path, "."),
Expand Down Expand Up @@ -84,7 +83,7 @@ func (e UnresolvedNodes) Error() string {
default:
format = "%s\n\t%s\tin %s\t%s\t(%s)%s"
}
val:=strings.Replace(fmt.Sprintf("%s", node.Value()),"\n", "\n\t", -1 )
val := strings.Replace(fmt.Sprintf("%s", node.Value()), "\n", "\n\t", -1)
message = fmt.Sprintf(
format,
message,
Expand All @@ -94,7 +93,7 @@ func (e UnresolvedNodes) Error() string {
strings.Join(node.Path, "."),
msg,
)
message += nestedIssues("\t", issue)
message += nestedIssues(issue)
}

return message
Expand All @@ -113,15 +112,22 @@ func tag(node yaml.Node) string {
return tag
}

func nestedIssues(gap string, issue yaml.Issue) string {
func nestedIssues(issue yaml.Issue) string {
prefix := "\n"
gap := ""
if issue.Sequence {
prefix = "\n\t\t... "
} else {
gap = "\t\t\t"
}
message := ""
if issue.Nested != nil {
for _, sub := range issue.Nested {
message = message + "\n" + sub.Issue
message += nestedIssues("\t", sub)
message = message + prefix + sub.Issue
message += nestedIssues(sub)
}
}
return strings.Replace(message,"\n", "\n"+gap, -1)
return strings.Replace(message, "\n", "\n"+gap, -1)
}

func FindUnresolvedNodes(root yaml.Node, context ...string) (result []UnresolvedNode) {
Expand Down
44 changes: 41 additions & 3 deletions flow/error_check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,35 @@ node: (( length( 5 ) ))
))
})

It("reports list error in select{}", func() {
source := parseYAML(`
---
node: (( select{[5]|x|->x} ))
`)
Expect(source).To(FlowToErr(
` (( select{[5]|x|->x} )) in test node () *list value not supported for select mapping`,
))
})

It("reports list error in map{}", func() {
source := parseYAML(`
---
node: (( map{[5]|x|->x} ))
`)
Expect(source).To(FlowToErr(
` (( map{[5]|x|->x} )) in test node () *list value not supported for map mapping`,
))
})

It("reports unparseable", func() {
source := parseYAML(`
---
node: (( a "." ) ))
`)
Expect(source).To(FlowToErr(
` (( a "." ) )) in test node () *parse error near line 1 symbol 7 - line 1 symbol 8: " "`,
` (( a "." ) )) in test node () *parse error near symbol 7 - symbol 8: " "`,
))
})

Expand All @@ -167,7 +189,7 @@ node:
- <<: (( a "." ) ))
`)
Expect(source).To(FlowToErr(
` (( a "." ) )) in test node.[0].<< () *parse error near line 1 symbol 7 - line 1 symbol 8: " "`,
` (( a "." ) )) in test node.[0].<< () *parse error near symbol 7 - symbol 8: " "`,
))
})

Expand All @@ -178,7 +200,23 @@ node:
<<: (( a "." ) ))
`)
Expect(source).To(FlowToErr(
` (( a "." ) )) in test node.<< () *parse error near line 1 symbol 7 - line 1 symbol 8: " "`,
` (( a "." ) )) in test node.<< () *parse error near symbol 7 - symbol 8: " "`,
))
})

It("reports unparseable map insert operator in multi line expression", func() {
source := parseYAML(`
---
node:
<<: |-
((
a "." )
))
`)
Expect(source).To(FlowToErr(
` ((
a "." )
)) in test node.<< () *parse error near line 2 symbol 6 - line 2 symbol 7: " "`,
))
})
})
15 changes: 8 additions & 7 deletions yaml/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,13 @@ type AnnotatedNode struct {
}

type Issue struct {
Issue string
Nested []Issue
Issue string
Nested []Issue
Sequence bool
}

func NewIssue(msg string, args ...interface{}) Issue {
return Issue{fmt.Sprintf(msg, args...), []Issue{}}
return Issue{fmt.Sprintf(msg, args...), []Issue{}, false}
}

const (
Expand Down Expand Up @@ -410,10 +411,10 @@ func EmbeddedDynaml(root Node) *string {
if !ok {
return nil
}
if strings.HasPrefix(rootString,"((") &&
strings.HasSuffix(rootString,"))") {
sub:=rootString[2:len(rootString)-2]
if !strings.HasPrefix(sub,"!") {
if strings.HasPrefix(rootString, "((") &&
strings.HasSuffix(rootString, "))") {
sub := rootString[2 : len(rootString)-2]
if !strings.HasPrefix(sub, "!") {
return &sub
}
}
Expand Down

0 comments on commit ed9d8b6

Please sign in to comment.