diff --git a/interpreter/interpreter_test.go b/interpreter/interpreter_test.go index cf8b1ff6..19edf1c4 100644 --- a/interpreter/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -437,7 +437,7 @@ func TestMapExpr(t *testing.T) { } func testEval(t *testing.T, input string) runtime.Object { - nodes, _, _ := syntax.Parse([]byte(input)) + nodes := syntax.Parse([]byte(input)) if err := nodes.Err(); err != nil { t.Fatalf("%s\n %s", input, err.Error()) } diff --git a/k3/t3xf/compiler_test.go b/k3/t3xf/compiler_test.go index 3147430b..50f6908e 100644 --- a/k3/t3xf/compiler_test.go +++ b/k3/t3xf/compiler_test.go @@ -345,7 +345,7 @@ func TestCompiler(t *testing.T) { if tt.skip { t.Skip() } - root, _, _ := syntax.Parse([]byte(tt.input)) + root := syntax.Parse([]byte(tt.input)) if root.Err() != nil { t.Fatalf("syntax.Parse(%q) returned error: %v", tt.input, root.Err()) } diff --git a/repl.go b/repl.go index ed711159..1286e90b 100644 --- a/repl.go +++ b/repl.go @@ -21,7 +21,7 @@ func repl() error { break } - root, _, _ := syntax.Parse([]byte(s.Text())) + root := syntax.Parse([]byte(s.Text())) if err := root.Err(); err != nil { fmt.Println(err.Error()) continue diff --git a/ttcn3/format/format.go b/ttcn3/format/format.go index 4541c707..5de64d53 100644 --- a/ttcn3/format/format.go +++ b/ttcn3/format/format.go @@ -74,7 +74,7 @@ func (p *CanonicalPrinter) Fprint(v interface{}) error { // The simple formatting rules do not need much context information. // This allows us to use the tokeniser and release initial // formatting experiments even before the parser is ready. - n, _, _ := syntax.Parse(b) + n := syntax.Parse(b) // Only pretty print if there are no syntax errors. if n.Err() != nil { diff --git a/ttcn3/syntax/nodes_test.go b/ttcn3/syntax/nodes_test.go index 147b032c..d340f620 100644 --- a/ttcn3/syntax/nodes_test.go +++ b/ttcn3/syntax/nodes_test.go @@ -27,7 +27,7 @@ func TestFindChildOf(t *testing.T) { } for _, tt := range tests { input, cursor := ntttest.CutCursor(tt.input) - root, _, _ := syntax.Parse([]byte(input), syntax.WithFilename(tt.input)) + root := syntax.Parse([]byte(input), syntax.WithFilename(tt.input)) actual := printNode(syntax.FindChildOf(root, cursor)) if actual != tt.want { t.Errorf("FindChildOf(%q) = %q, want %q", tt.input, actual, tt.want) diff --git a/ttcn3/syntax/parser.go b/ttcn3/syntax/parser.go index abdcd2f0..2d341714 100644 --- a/ttcn3/syntax/parser.go +++ b/ttcn3/syntax/parser.go @@ -22,6 +22,7 @@ type Mode uint type ParserOption func(*parser) error +// WithFilename sets the filename of the source code. func WithFilename(filename string) ParserOption { return func(p *parser) error { p.Filename = filename @@ -29,6 +30,24 @@ func WithFilename(filename string) ParserOption { } } +// WithNames sets the names map in which the parser will store the names of the +// parsed entities. +func WithNames(names map[string]bool) ParserOption { + return func(p *parser) error { + p.names = names + return nil + } +} + +// WithUses sets the uses map in which the parser will store the uses of the +// parsed entities. +func WithUses(uses map[string]bool) ParserOption { + return func(p *parser) error { + p.uses = uses + return nil + } +} + const ( PedanticSemicolon = 1 << iota // expect semicolons pedantically IgnoreComments // ignore comments @@ -48,9 +67,6 @@ func NewParser(src []byte) *parser { p.ppDefs["0"] = false p.ppDefs["1"] = true - p.names = make(map[string]bool) - p.uses = make(map[string]bool) - p.Root = newRoot(src) // fetch first token @@ -60,24 +76,8 @@ func NewParser(src []byte) *parser { return &p } -// Parse the source code of a single file and return the corresponding syntax -// tree. The source code may be provided via the filename of the source file, -// or via the src parameter. -// -// If src != nil, Parse parses the source from src and the filename is only -// used when recording position information. The type of the argument for the -// src parameter must be string, []byte, or io.Reader. If src == nil, Parse -// parses the file specified by filename. -// -// The mode parameter controls the amount of source text parsed and other -// optional parser functionality. -// -// If the source couldn't be read, the returned AST is nil and the error -// indicates the specific failure. If the source was read but syntax errors -// were found, the result is a partial AST (with Bad* nodes representing the -// fragments of erroneous source code). Multiple errors are returned via a -// ErrorList which is sorted by file position. -func Parse(src []byte, opts ...ParserOption) (root *Root, names map[string]bool, uses map[string]bool) { +// Parse parses the source code of a TTCN-3 module and returns the corresponding AST. +func Parse(src []byte, opts ...ParserOption) (root *Root) { region := trc.StartRegion(context.Background(), "syntax.Parse") defer region.End() @@ -86,7 +86,7 @@ func Parse(src []byte, opts ...ParserOption) (root *Root, names map[string]bool, for _, opt := range opts { if err := opt(p); err != nil { p.Root.errs = append(p.Root.errs, err) - return p.Root, p.names, p.uses + return p.Root } } for p.tok != EOF { @@ -102,7 +102,7 @@ func Parse(src []byte, opts ...ParserOption) (root *Root, names map[string]bool, } } - return p.Root, p.names, p.uses + return p.Root } // If src != nil, readSource converts src to a []byte if possible; @@ -1009,7 +1009,9 @@ func (p *parser) parseName() *Ident { switch p.tok { case IDENT, ADDRESS, CONTROL, CLASS: id := &Ident{Tok: p.consume(), IsName: true} - p.names[id.String()] = true + if p.names != nil { + p.names[id.String()] = true + } return id } p.expect(IDENT) @@ -1278,7 +1280,7 @@ func (p *parser) addName(n Node) { p.addName(n) } default: - if name := Name(n); name != "" { + if name := Name(n); p.names != nil && name != "" { p.names[name] = true } } @@ -1293,10 +1295,14 @@ func (p *parser) make_use(toks ...Token) *Ident { panic("No support for multi-token identifiers.") } id := &Ident{Tok: toks[0]} - p.uses[toks[0].String()] = true + if p.uses != nil { + p.uses[toks[0].String()] = true + } if len(toks) == 2 { id.Tok2 = toks[1] - p.uses[toks[1].String()] = true + if p.uses != nil { + p.uses[toks[1].String()] = true + } } return id } @@ -1807,7 +1813,7 @@ func (p *parser) parseEnum() Expr { } } x := p.parseExpr() - if id := firstIdent(x); id != nil { + if id := firstIdent(x); p.names != nil && id != nil { p.names[id.String()] = true id.IsName = true } diff --git a/ttcn3/syntax/syntax_test.go b/ttcn3/syntax/syntax_test.go index 1fd1a3b6..f3d32747 100644 --- a/ttcn3/syntax/syntax_test.go +++ b/ttcn3/syntax/syntax_test.go @@ -11,7 +11,7 @@ func TestDoc(t *testing.T) { t.Parallel() testDoc := func(t *testing.T, input string) string { - root, _, _ := syntax.Parse([]byte(input), syntax.WithFilename(t.Name())) + root := syntax.Parse([]byte(input), syntax.WithFilename(t.Name())) if err := root.Err(); err != nil { t.Fatal(err) } diff --git a/ttcn3/ttcn3.go b/ttcn3/ttcn3.go index 99a12c21..1f49219b 100644 --- a/ttcn3/ttcn3.go +++ b/ttcn3/ttcn3.go @@ -70,7 +70,9 @@ func parse(path string, input []byte) *Tree { input = b } - root, names, uses := syntax.Parse(input, syntax.WithFilename(path)) + names := make(map[string]bool) + uses := make(map[string]bool) + root := syntax.Parse(input, syntax.WithFilename(path), syntax.WithNames(names), syntax.WithUses(uses)) return &Tree{Root: root, Names: names, Uses: uses, Err: root.Err(), filename: path} }