Skip to content

Commit 0f5040e

Browse files
committed
Backport formatter to old parser
1 parent f484778 commit 0f5040e

File tree

9 files changed

+143
-128
lines changed

9 files changed

+143
-128
lines changed

dump.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import (
1111
"github.com/fatih/color"
1212
"github.com/nokia/ntt/internal/fs"
1313
"github.com/nokia/ntt/ttcn3"
14+
printer "github.com/nokia/ntt/ttcn3/format"
1415
"github.com/nokia/ntt/ttcn3/syntax"
15-
"github.com/nokia/ntt/ttcn3/v2/printer"
1616
syntax2 "github.com/nokia/ntt/ttcn3/v2/syntax"
1717
"github.com/spf13/cobra"
1818
)

format.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88

99
"github.com/hashicorp/go-multierror"
1010
"github.com/nokia/ntt/internal/fs"
11-
"github.com/nokia/ntt/ttcn3/v2/printer"
11+
printer "github.com/nokia/ntt/ttcn3/format"
1212
"github.com/pmezard/go-difflib/difflib"
1313
"github.com/spf13/cobra"
1414
)

internal/lsp/formatter.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"github.com/nokia/ntt/internal/log"
99
"github.com/nokia/ntt/internal/lsp/protocol"
1010
"github.com/nokia/ntt/ttcn3"
11-
"github.com/nokia/ntt/ttcn3/v2/printer"
11+
"github.com/nokia/ntt/ttcn3/format"
1212
)
1313

1414
func (s *Server) formatting(ctx context.Context, params *protocol.DocumentFormattingParams) ([]protocol.TextEdit, error) {
@@ -29,7 +29,7 @@ func (s *Server) formatting(ctx context.Context, params *protocol.DocumentFormat
2929
}
3030

3131
var out bytes.Buffer
32-
p := printer.NewCanonicalPrinter(&out)
32+
p := format.NewCanonicalPrinter(&out)
3333
p.TabWidth = int(params.Options.TabSize)
3434
if params.Options.InsertSpaces {
3535
p.UseSpaces = true

ttcn3/format/example_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package format_test
2+
3+
import (
4+
"os"
5+
6+
"github.com/nokia/ntt/ttcn3/format"
7+
)
8+
9+
func ExampleFprint() {
10+
input := "p := {\n x:=1, // Comment\ny := 234 // Comment 2\n}"
11+
if err := format.Fprint(os.Stdout, input); err != nil {
12+
panic(err)
13+
}
14+
// Output:
15+
// p := {
16+
// x := 1, // Comment
17+
// y := 234 // Comment 2
18+
// }
19+
}
20+
21+
func ExampleCanonicalPrinter() {
22+
input := "p := {\n x:=1, // Comment\ny := 234 // Comment 2\n}"
23+
p := format.NewCanonicalPrinter(os.Stdout)
24+
p.Indent = 1
25+
p.UseSpaces = true
26+
p.TabWidth = 2
27+
p.Fprint(input)
28+
// Output:
29+
// p := {
30+
// x := 1, // Comment
31+
// y := 234 // Comment 2
32+
// }
33+
}

ttcn3/v2/printer/printer.go ttcn3/format/format.go

+66-70
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
// Package printer implements pretty printers for TTCN-3 source code.
2-
package printer
1+
// Package format implements pretty printers for TTCN-3 source code.
2+
package format
33

44
import (
55
"fmt"
66
"io"
77
"strings"
88
"text/tabwriter"
99

10-
"github.com/nokia/ntt/ttcn3/v2/syntax"
10+
"github.com/nokia/ntt/ttcn3/syntax"
1111
)
1212

1313
type whiteSpace byte
@@ -45,6 +45,7 @@ type CanonicalPrinter struct {
4545
lastPos, currPos syntax.Position
4646
whiteBuf string
4747
firstToken bool
48+
stack []syntax.Node
4849
}
4950

5051
// NewCanonicalPrinter returns a new printer that formats source code.
@@ -73,7 +74,7 @@ func (p *CanonicalPrinter) Fprint(v interface{}) error {
7374
// The simple formatting rules do not need much context information.
7475
// This allows us to use the tokeniser and release initial
7576
// formatting experiments even before the parser is ready.
76-
n := syntax.Tokenize(b)
77+
n, _, _ := syntax.Parse(b)
7778

7879
// Only pretty print if there are no syntax errors.
7980
if n.Err() != nil {
@@ -91,72 +92,9 @@ func (p *CanonicalPrinter) tree(n syntax.Node) error {
9192
// white-spaces before the first token.
9293
p.firstToken = true
9394

94-
n.Inspect(func(n syntax.Node) bool {
95-
96-
// We figure out spacing by looking at the token stream only.
97-
// Because the parser for creating a syntax tree is not yet
98-
// implemented.
99-
if !n.IsToken() {
100-
return true
101-
}
102-
103-
// Incorporate user-defined line breaks and token separators
104-
// into output stream.
105-
currPos := n.Span()
106-
switch {
107-
case currPos.Begin.Line > p.lastPos.Line:
108-
p.print(newline)
109-
if currPos.Begin.Line-p.lastPos.Line > 1 {
110-
p.print(newline)
111-
}
112-
case currPos.Begin.Column > p.lastPos.Column:
113-
p.print(blank)
114-
}
115-
p.lastPos = currPos.End
116-
117-
switch k, s := n.Kind(), n.Text(); {
118-
119-
// Increment indentation after opening {, [, (.
120-
case k == syntax.LeftBrace, k == syntax.LeftBracket, k == syntax.LeftParen:
121-
p.print(s, indent)
122-
123-
// Decrement indentation before closing }, ], ).
124-
case k == syntax.RightBrace, k == syntax.RightBracket, k == syntax.RightParen:
125-
p.print(unindent, s)
126-
127-
// Add space after comma
128-
case k == syntax.Comma:
129-
p.print(",", blank)
130-
131-
// Align assignments.
132-
case k == syntax.Assign:
133-
p.print(blank, ":=", blank)
134-
135-
// Every line of a comment has to be indented individually.
136-
case k == syntax.Comment:
137-
p.print(cell)
138-
139-
// Before we split a comment into its lines, we have to
140-
// remove the trailing newline of `//` comments.
141-
//
142-
// This makes the logic of p.comment easier, because
143-
// printing `//` comments is then identical to printing
144-
// single line `/*` comments.
145-
p.comment(currPos.Begin.Column-1, strings.Split(strings.TrimSpace(s), "\n"))
146-
if strings.HasSuffix(s, "\n") {
147-
p.print(newline)
148-
}
149-
150-
// Only literals may contain newlines and \t and need to be quoted.
151-
case n.Kind().IsLiteral():
152-
p.print(quote(s))
153-
154-
// All other tokens are printed as is.
155-
default:
156-
p.print(s)
157-
}
158-
return true
159-
})
95+
for tok := n.FirstTok(); tok != nil && tok.Kind() != syntax.EOF; tok = tok.NextTok() {
96+
p.printToken(tok)
97+
}
16098

16199
// Terminate the last line with a newline.
162100
if !p.firstToken {
@@ -170,6 +108,64 @@ func (p *CanonicalPrinter) tree(n syntax.Node) error {
170108
return nil
171109
}
172110

111+
func (p *CanonicalPrinter) printToken(n syntax.Token) {
112+
// Incorporate user-defined line breaks and token separators
113+
// into output stream.
114+
currPos := syntax.SpanOf(n)
115+
switch {
116+
case currPos.Begin.Line > p.lastPos.Line:
117+
p.print(newline)
118+
if currPos.Begin.Line-p.lastPos.Line > 1 {
119+
p.print(newline)
120+
}
121+
case currPos.Begin.Column > p.lastPos.Column:
122+
p.print(blank)
123+
}
124+
p.lastPos = currPos.End
125+
126+
switch k, s := n.Kind(), n.String(); {
127+
128+
// Increment indentation after opening {, [, (.
129+
case k == syntax.LBRACE, k == syntax.LBRACK, k == syntax.LPAREN:
130+
p.print(s, indent)
131+
132+
// Decrement indentation before closing }, ], ).
133+
case k == syntax.RBRACE, k == syntax.RBRACK, k == syntax.RPAREN:
134+
p.print(unindent, s)
135+
136+
// Add space after comma
137+
case k == syntax.COMMA:
138+
p.print(",", blank)
139+
140+
// Align assignments.
141+
case k == syntax.ASSIGN:
142+
p.print(blank, ":=", blank)
143+
144+
// Every line of a comment has to be indented individually.
145+
case k == syntax.COMMENT:
146+
p.print(cell)
147+
148+
// Before we split a comment into its lines, we have to
149+
// remove the trailing newline of `//` comments.
150+
//
151+
// This makes the logic of p.comment easier, because
152+
// printing `//` comments is then identical to printing
153+
// single line `/*` comments.
154+
p.comment(currPos.Begin.Column-1, strings.Split(strings.TrimSpace(s), "\n"))
155+
if strings.HasSuffix(s, "\n") {
156+
p.print(newline)
157+
}
158+
159+
// Only literals may contain newlines and \t and need to be quoted.
160+
case n.Kind().IsLiteral():
161+
p.print(quote(s))
162+
163+
// All other tokens are printed as is.
164+
default:
165+
p.print(s)
166+
}
167+
}
168+
173169
// comment prints a comment line by line. It removes white-space prefixes from
174170
// multi-line comments, so they can be properly indented.
175171
func (p *CanonicalPrinter) comment(firstLineIndent int, lines []string) {

ttcn3/v2/printer/printer_test.go ttcn3/format/format_test.go

+21-19
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package printer
1+
package format
22

33
import (
44
"bytes"
@@ -27,10 +27,10 @@ func TestSimpleFormatter(t *testing.T) {
2727
{input: "trailing; ", want: "trailing;\n"},
2828

2929
// At max one blank between tokens.
30-
{input: "import from all", want: "import from all\n"},
30+
{input: "import from M all", want: "import from M all\n"},
3131

3232
// Convert all other whitespace to blanks.
33-
{input: "import \tfrom\tall", want: "import from all\n"},
33+
{input: "import \tfrom M\tall", want: "import from M all\n"},
3434

3535
// Replace line breaks with \n
3636
{input: "foo;\r\nbar;", want: "foo;\nbar;\n"},
@@ -51,26 +51,28 @@ func TestSimpleFormatter(t *testing.T) {
5151
{input: "control\n {}", want: "control\n{}\n"},
5252

5353
// Verify that {, [ and ( increment the indentation level
54-
{input: "{foo", want: "{foo\n"},
55-
{input: "{\nfoo", want: "{\n\tfoo\n"},
56-
{input: "{\n foo", want: "{\n\tfoo\n"},
57-
{input: "{\nfoo}\nbar", want: "{\n\tfoo}\nbar\n"},
58-
{input: "{\n[\n(\n1,2\n)\n]\n}", want: "{\n\t[\n\t\t(\n\t\t\t1, 2\n\t\t)\n\t]\n}\n"},
54+
{input: "{foo}", want: "{foo}\n"},
55+
{input: "{\nfoo}", want: "{\n\tfoo}\n"},
56+
{input: "{\n foo}", want: "{\n\tfoo}\n"},
57+
{input: "{\nfoo};\nbar", want: "{\n\tfoo};\nbar\n"},
58+
{input: "{\n[\n(\n1,2\n)\n] p.receive\n}", want: "{\n\t[\n\t\t(\n\t\t\t1, 2\n\t\t)\n\t] p.receive\n}\n"},
5959

6060
// Verify that tokens with newlines have correct indentation
61-
{input: "{// Foo\nBar", want: "{ // Foo\n\tBar\n"}, // Bar must be indented.
62-
{input: "{\n/*\n* foo\n*/", want: "{\n\t/*\n\t* foo\n\t*/\n"}, // Comment must be indented, with one extra space.
63-
{input: "{\n /* \n * foo\n*/", want: "{\n\t/*\n\t * foo\n\t*/\n"}, // the least indented line is the anchor. It gets alligned to the actual indentation level. All other lines are alligned relative to it
64-
{input: "{\n/*\n * foo\n * some prefix*/", want: "{\n\t/*\n\t * foo\n\t * some prefix*/\n"},
61+
{input: "{// Foo\nBar}", want: "{ // Foo\n\tBar}\n"}, // Bar must be indented.
62+
{input: "{\n/*\n* foo\n*/}", want: "{\n\t/*\n\t* foo\n\t*/}\n"}, // Comment must be indented, with one extra space.
63+
{input: "{\n /* \n * foo\n*/}", want: "{\n\t/*\n\t * foo\n\t*/}\n"}, // the least indented line is the anchor. It gets alligned to the actual indentation level. All other lines are alligned relative to it
64+
{input: "{\n/*\n * foo\n * some prefix*/}", want: "{\n\t/*\n\t * foo\n\t * some prefix*/}\n"},
65+
6566
// Indenting multi-line comments
66-
{input: "{\n /**\n * Foo \n */", want: "{\n\t/**\n\t * Foo\n\t */\n"},
67-
{input: "{\n /**\n * Bar\n */", want: "{\n\t/**\n\t * Bar\n\t */\n"},
68-
{input: "{\n x:=25 /**\n Bar\n */", want: "{\n\tx := 25 /**\n\t Bar\n\t */\n"},
69-
{input: "{\n /*function f() {\n var integer x;\n\n log(x);\n }*/\n", want: "{\n\t/*function f() {\n\t var integer x;\n\n\t log(x);\n\t}*/\n"}, // including an empty line
67+
{input: "{\n /**\n * Foo \n */}", want: "{\n\t/**\n\t * Foo\n\t */}\n"},
68+
{input: "{\n /**\n * Bar\n */}", want: "{\n\t/**\n\t * Bar\n\t */}\n"},
69+
{input: "{\n x:=25 /**\n Bar\n */}", want: "{\n\tx := 25 /**\n\t Bar\n\t */}\n"},
70+
{input: "{\n /*function f() {\n var integer x;\n\n log(x);\n }*/}\n", want: "{\n\t/*function f() {\n\t var integer x;\n\n\t log(x);\n\t}*/}\n"}, // including an empty line
71+
7072
// Verify that comments and := are aligned.
71-
{input: "{x := 1,\nx2:= 123}", want: "{x := 1,\n\tx2 := 123}\n"},
72-
{input: "{\nx := 1,\nx2:= 123}", want: "{\n\tx := 1,\n\tx2 := 123}\n"},
73-
{input: "{\nx := 1, // a\nx2:= 123 /* b */}", want: "{\n\tx := 1, // a\n\tx2 := 123 /* b */}\n"},
73+
{input: "p := {x := 1,\nx2:= 123}", want: "p := {x := 1,\n\tx2 := 123}\n"},
74+
{input: "p := {\nx := 1,\nx2:= 123}", want: "p := {\n\tx := 1,\n\tx2 := 123}\n"},
75+
{input: "p := {\nx := 1, // a\nx2:= 123 /* b */}", want: "p := {\n\tx := 1, // a\n\tx2 := 123 /* b */}\n"},
7476
}
7577

7678
for _, test := range tests {

ttcn3/syntax/nodes.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,20 @@ func (n *Root) PosFor(line, col int) int {
9393
return n.lines[line] + col - 1
9494
}
9595

96-
func (n *Root) FirstTok() Token { return n.NodeList.FirstTok() }
97-
func (n *Root) LastTok() Token { return n.NodeList.LastTok() }
96+
func (n *Root) FirstTok() Token {
97+
if len(n.tokens) == 0 {
98+
return nil
99+
}
100+
return &tokenNode{n, 0}
101+
}
102+
103+
func (n *Root) LastTok() Token {
104+
if len(n.tokens) == 0 {
105+
return nil
106+
}
107+
return &tokenNode{n, len(n.tokens) - 1}
108+
}
109+
98110
func (n *Root) Inspect(f func(Node) bool) { n.NodeList.Inspect(f) }
99111
func (n *Root) Children() []Node { return n.NodeList.Children() }
100112

ttcn3/syntax/syntax.go

+5
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ func Doc(n Node) string {
119119
return ""
120120
}
121121

122+
// Root is the only node that can have comments as first token.
123+
if r, ok := n.(*Root); ok && len(r.Nodes) > 0 {
124+
n = r.Nodes[0]
125+
}
126+
122127
tok := n.FirstTok()
123128
if tok == nil {
124129
return ""

ttcn3/v2/printer/example_test.go

-33
This file was deleted.

0 commit comments

Comments
 (0)