Repository: openconfig/goyang
Pull request #145 (2020-09-30 14:47:31)

Detect missing closing brace from input
Consider the case of the following yang that is missing the final
closing brace for ```module foo```

```
module foo {
  namespace foo;
  prefix f;

  container top {
     leaf f1 {
        type string;
     }
  }

```

parsing that with ```./goyang -f tree test.yang``` results in no error
and no output.

With this patch we output an error that says we are missing a closing
brace.


Patch:
diff --git a/pkg/yang/parse.go b/pkg/yang/parse.go
index 10a3fab..33913a9 100644
--- a/pkg/yang/parse.go
+++ b/pkg/yang/parse.go
@@ -35,6 +35,9 @@ type parser struct {
 	errout *bytes.Buffer
 	tokens []*token // stack of pushed tokens (for backing up)
 
+	// Depth of statements in nested braces
+	statementDepth int
+
 	// hitBrace is returned when we encounter a '}'.  The statement location
 	// is updated with the location of the '}'.  The brace may be legitimate
 	// but only the caller will know if it is.  That is, the brace may be
@@ -188,6 +191,8 @@ Loop:
 		}
 	}
 
+	p.checkStatementDepth()
+
 	if p.errout.Len() == 0 {
 		return statements, nil
 	}
@@ -270,6 +275,7 @@ func (p *parser) nextStatement() *Statement {
 	case tEOF:
 		return nil
 	case closeBrace:
+		p.statementDepth -= 1
 		p.hitBrace.file = t.File
 		p.hitBrace.line = t.Line
 		p.hitBrace.col = t.Col
@@ -306,6 +312,7 @@ func (p *parser) nextStatement() *Statement {
 	case ';':
 		return s
 	case openBrace:
+		p.statementDepth += 1
 		for {
 			switch ns := p.nextStatement(); ns {
 			case nil:
@@ -321,3 +328,24 @@ func (p *parser) nextStatement() *Statement {
 		return ignoreMe
 	}
 }
+
+// Checks that we have a statement depth of 0. It's an error to exit
+// the parser with a depth of > 0, it means we are missing closing
+// braces. Note: the parser will error out for the case where we
+// start with an unmatched close brace, eg. depth < 0
+//
+// This test is only done if there are no other errors as
+// we may exit early due to those errors -- and therefore there *might*
+// not really be a mismatched brace issue.
+func (p *parser) checkStatementDepth() {
+	if p.errout.Len() > 0 || p.statementDepth < 1 {
+		return
+	}
+
+	plural := ""
+	if p.statementDepth > 1 {
+		plural = "s"
+	}
+	fmt.Fprintf(p.errout, "%s:%d:%d: missing %d closing brace%s\n",
+		p.lex.file, p.lex.line, p.lex.col, p.statementDepth, plural)
+}


Test patch:
diff --git a/pkg/yang/parse_test.go b/pkg/yang/parse_test.go
index fef9db7..22ab03f 100644
--- a/pkg/yang/parse_test.go
+++ b/pkg/yang/parse_test.go
@@ -269,6 +269,25 @@ test.yang:9:9: invalid escape sequence: \3
 test.yang:9:9: missing closing "
 test.yang: unexpected EOF`,
 		},
+		{line: line(), in: `
+module base {
+   container top-missing-close-brace {
+      leaf my-leaf {
+        type string;
+      }
+   }
+`,
+			err: "test.yang:8:0: missing 1 closing brace",
+		},
+		{line: line(), in: `
+module base {
+   container top-missing-close-brace {
+      leaf my-leaf {
+        type string;
+   }
+`,
+			err: "test.yang:7:0: missing 2 closing braces",
+		},
 	} {
 		s, err := Parse(tt.in, "test.yang")
 		if (s == nil) != (tt.out == nil) {