Skip to content

Commit

Permalink
Simplify parser API
Browse files Browse the repository at this point in the history
  • Loading branch information
5nord committed May 1, 2023
1 parent 553fe9e commit 571ecce
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 47 deletions.
4 changes: 2 additions & 2 deletions interpreter/interpreter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,8 @@ func TestMapExpr(t *testing.T) {
}

func testEval(t *testing.T, input string) runtime.Object {
nodes, _, _, err := syntax.Parse("<stdin>", input)
if err != nil {
nodes, _, _ := syntax.Parse([]byte(input))
if err := nodes.Err(); err != nil {
t.Fatalf("%s\n %s", input, err.Error())
}
return interpreter.Eval(nodes, runtime.NewEnv(nil))
Expand Down
4 changes: 2 additions & 2 deletions repl.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ func repl() error {
break
}

root, _, _, err := syntax.Parse("<stdin>", s.Text())
if err != nil {
root, _, _ := syntax.Parse([]byte(s.Text()))
if err := root.Err(); err != nil {
fmt.Println(err.Error())
continue
}
Expand Down
79 changes: 45 additions & 34 deletions ttcn3/syntax/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,46 @@ import (
// parser functionality.
type Mode uint

type ParserOption func(*parser) error

func WithFilename(filename string) ParserOption {
return func(p *parser) error {
p.Filename = filename
return nil
}
}

const (
PedanticSemicolon = 1 << iota // expect semicolons pedantically
IgnoreComments // ignore comments
Trace // print a trace of parsed productions
)

func NewParser(src []byte) *parser {
var p parser
if s := os.Getenv("NTT_DEBUG"); s == "trace" {
p.mode |= Trace
}

p.trace = p.mode&Trace != 0 // for convenience (p.trace is used frequently)
p.semi = p.mode&PedanticSemicolon != 0

p.ppDefs = make(map[string]bool)
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
tok := p.peek(1)
p.tok = tok.Kind()

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.
Expand All @@ -41,15 +75,15 @@ const (
// 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(filename string, src interface{}) (root *Root, names map[string]bool, uses map[string]bool, err error) {
// get source
text, err := readSource(filename, src)
if err != nil {
return nil, nil, nil, err
}
func Parse(src []byte, opts ...ParserOption) (root *Root, names map[string]bool, uses map[string]bool) {

var p parser
p.init(filename, text, 0)
p := NewParser(src)
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
}
}
for p.tok != EOF {
p.Nodes = append(p.Nodes, p.parse())

Expand All @@ -63,7 +97,7 @@ func Parse(filename string, src interface{}) (root *Root, names map[string]bool,
}

}
return p.Root, p.names, p.uses, p.Err()
return p.Root, p.names, p.uses
}

// If src != nil, readSource converts src to a []byte if possible;
Expand Down Expand Up @@ -178,35 +212,12 @@ type parser struct {
syncCnt int // number of advance calls without progress
}

func newRoot(filename string, src []byte) *Root {
func newRoot(src []byte) *Root {
return &Root{
Filename: filename,
Scanner: NewScanner(src),
Scanner: NewScanner(src),
}
}

func (p *parser) init(filename string, src []byte, mode Mode) {
if s := os.Getenv("NTT_DEBUG"); s == "trace" {
mode |= Trace
}

p.mode = mode
p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
p.semi = mode&PedanticSemicolon != 0

p.ppDefs = make(map[string]bool)
p.ppDefs["0"] = false
p.ppDefs["1"] = true

p.names = make(map[string]bool)
p.uses = make(map[string]bool)

// fetch first token
p.Root = newRoot(filename, src)
tok := p.peek(1)
p.tok = tok.Kind()
}

// Usage pattern: defer un(trace(p, "..."))
func un(p *parser) {
p.indent--
Expand Down
5 changes: 2 additions & 3 deletions ttcn3/syntax/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,8 @@ func testParse(t *testing.T, tests []Test, f func(p *parser)) {
}

func anyParse(input string, f func(p *parser)) error {
var p parser
p.init("", []byte(input), Mode(0))
f(&p)
p := NewParser([]byte(input))
f(p)
// TODO(5nord) temporary hack until we have proper error handling
return p.Err()
}
2 changes: 1 addition & 1 deletion ttcn3/syntax/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package syntax

// Tokenize given source code and return a root node with all the tokens.
func Tokenize(src []byte) *Root {
root := newRoot("", src)
root := newRoot(src)
for {
kind, begin, end := root.Scan()
root.tokens = append(root.tokens, token{kind, begin, end})
Expand Down
4 changes: 2 additions & 2 deletions ttcn3/syntax/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ func TestDoc(t *testing.T) {
t.Parallel()

testDoc := func(t *testing.T, input string) string {
root, _, _, err := syntax.Parse(t.Name(), input)
if err != nil {
root, _, _ := syntax.Parse([]byte(input), syntax.WithFilename(t.Name()))
if err := root.Err(); err != nil {
t.Fatal(err)
}
return syntax.Doc(root)
Expand Down
6 changes: 3 additions & 3 deletions ttcn3/ttcn3.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ func parse(path string, input []byte) *Tree {
input = b
}

root, names, uses, err := syntax.Parse(path, input)
return &Tree{Root: root, Names: names, Uses: uses, Err: err, filename: path}
root, names, uses := syntax.Parse(input, syntax.WithFilename(path))
return &Tree{Root: root, Names: names, Uses: uses, Err: root.Err(), filename: path}
}

var builtins = `
/* The __int2char__ function converts an __integer__ value in the range of 0 to 127 (8-bit encoding) into a single-character-length __charstring__ value. The __integer__ value describes the 8-bit encoding of the character */
/* The __int2char__ function converts an __integer__ value in the range of 0 to 127 (8-bit encoding) into a single-character-length __charstring__ value. The __integer__ value describes the 8-bit encoding of the character */
external function int2char(in integer invalue) return charstring;
/*
Expand Down

0 comments on commit 571ecce

Please sign in to comment.