diff --git a/_js/main.go b/_js/main.go index ce6eabafb..5ea891d9a 100644 --- a/_js/main.go +++ b/_js/main.go @@ -116,6 +116,9 @@ func (r streamReader) Read(p []byte) (n int, err error) { type jsParser struct { syntax.Parser + + accumulated []*syntax.Stmt + incomplete bytes.Buffer } func adaptReader(src *js.Object) io.Reader { @@ -151,6 +154,33 @@ func (p *jsParser) Interactive(src *js.Object, jsFn func([]*js.Object) bool) { } } +func (p *jsParser) InteractiveStep(line string) []*syntax.Stmt { + // pick up previous chunks of the incomplete statement + r := strings.NewReader(p.incomplete.String() + line) + lastEnd := uint(0) + err := p.Parser.Interactive(r, func(stmts []*syntax.Stmt) bool { + if len(stmts) > 0 { + // don't re-parse finished statements + lastEnd = stmts[len(stmts)-1].End().Offset() + } + p.accumulated = append(p.accumulated, stmts...) + return false + }) + if syntax.IsIncomplete(err) { + // starting or continuing an incomplete statement + p.incomplete.WriteString(line[lastEnd:]) + return p.accumulated + } + // complete; empty both fields and return + p.incomplete.Reset() + if err != nil { + throw(err) + } + acc := p.accumulated + p.accumulated = p.accumulated[:0] + return acc +} + type jsPrinter struct { *syntax.Printer } diff --git a/_js/testmain.js b/_js/testmain.js index 07a1f1290..73088642d 100644 --- a/_js/testmain.js +++ b/_js/testmain.js @@ -174,6 +174,38 @@ const printer = syntax.NewPrinter() assert.deepEqual(gotCallbacks, wantCallbacks) } +{ + // using the parser interactively with steps + const lines = [ + "foo\n", + "bar; baz\n", + "\n", + "foo; 'incom\n", + " \n", + "plete'\n", + ] + const wantResults = [ + {"count": 1, "incomplete": false}, + {"count": 2, "incomplete": false}, + {"count": 0, "incomplete": false}, + {"count": 1, "incomplete": true}, + {"count": 1, "incomplete": true}, + {"count": 2, "incomplete": false}, + ] + var gotResults = [] + for (var i = 0; i < lines.length; i++) { + var line = lines[i] + var want = wantResults[i] + + var stmts = parser.InteractiveStep(line) + gotResults.push({ + "count": stmts.length, + "incomplete": parser.Incomplete(), + }) + } + assert.deepEqual(gotResults, wantResults) +} + { // splitting brace expressions const parser = syntax.NewParser()