Skip to content

Commit 549488d

Browse files
authored
Merge pull request #38 from pleask/master
Allow multiline string literal constants
2 parents b597e8e + d5a9f79 commit 549488d

File tree

7 files changed

+71
-50
lines changed

7 files changed

+71
-50
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,5 @@ atlassian-ide-plugin.xml
3939
# Cursive Clojure plugin
4040
.idea/replstate.xml
4141

42+
.config/
43+
tags/

internal/lexer/constant.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
package lexer
22

3-
import "github.com/yoheimuta/go-protoparser/internal/lexer/scanner"
3+
import (
4+
"strings"
45

5-
// ReadConstant reads a constant.
6+
"github.com/yoheimuta/go-protoparser/internal/lexer/scanner"
7+
)
8+
9+
// ReadConstant reads a constant. If permissive is true, accepts multiline string literals.
610
// constant = fullIdent | ( [ "-" | "+" ] intLit ) | ( [ "-" | "+" ] floatLit ) | strLit | boolLit
7-
func (lex *Lexer) ReadConstant() (string, scanner.Position, error) {
11+
func (lex *Lexer) ReadConstant(permissive bool) (string, scanner.Position, error) {
812
lex.NextLit()
913

1014
startPos := lex.Pos
1115
cons := lex.Text
1216

1317
switch {
1418
case lex.Token == scanner.TSTRLIT:
19+
if permissive {
20+
return lex.mergeMultilineStrLit(), startPos, nil
21+
}
1522
return cons, startPos, nil
1623
case lex.Token == scanner.TBOOLLIT:
1724
return cons, startPos, nil
@@ -38,3 +45,21 @@ func (lex *Lexer) ReadConstant() (string, scanner.Position, error) {
3845
return "", scanner.Position{}, lex.unexpected(lex.Text, "constant")
3946
}
4047
}
48+
49+
// Merges a multiline string literal into a single string.
50+
func (lex *Lexer) mergeMultilineStrLit() string {
51+
q := "'"
52+
if strings.HasPrefix(lex.Text, "\"") {
53+
q = "\""
54+
}
55+
var b strings.Builder
56+
b.WriteString(q)
57+
for lex.Token == scanner.TSTRLIT {
58+
strippedString := strings.Trim(lex.Text, q)
59+
b.WriteString(strippedString)
60+
lex.NextLit()
61+
}
62+
lex.UnNext()
63+
b.WriteString(q)
64+
return b.String()
65+
}

internal/lexer/constant_test.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,23 @@ func TestLexer2_ReadConstant(t *testing.T) {
5858
wantIsEOF: true,
5959
},
6060
{
61-
name: "strLit",
61+
name: "single line strLit",
6262
input: `"あいうえお''"`,
6363
wantText: `"あいうえお''"`,
6464
wantIsEOF: true,
6565
},
66+
{
67+
name: "multiline strLit with double quotes",
68+
input: "\"line1 \"\n\"line2 \" \n\"line3\" ",
69+
wantText: `"line1 line2 line3"`,
70+
wantIsEOF: true,
71+
},
72+
{
73+
name: "multiline strLit with single quotes",
74+
input: "'line1 '\n'line2 ' \n'line3' ",
75+
wantText: `'line1 line2 line3'`,
76+
wantIsEOF: true,
77+
},
6678
{
6779
name: "boolLit",
6880
input: "true",
@@ -89,7 +101,7 @@ func TestLexer2_ReadConstant(t *testing.T) {
89101
test := test
90102
t.Run(test.name, func(t *testing.T) {
91103
lex := lexer.NewLexer(strings.NewReader(test.input))
92-
got, pos, err := lex.ReadConstant()
104+
got, pos, err := lex.ReadConstant(true)
93105

94106
switch {
95107
case test.wantErr:

parser/enum.go

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package parser
22

33
import (
44
"fmt"
5-
"strings"
65

76
"github.com/yoheimuta/go-protoparser/internal/lexer/scanner"
87
"github.com/yoheimuta/go-protoparser/parser/meta"
@@ -309,52 +308,13 @@ func (p *Parser) parseEnumValueOption() (*EnumValueOption, error) {
309308
return nil, p.unexpected("=")
310309
}
311310

312-
constant, _, err := p.lex.ReadConstant()
311+
constant, _, err := p.lex.ReadConstant(p.permissive)
313312
if err != nil {
314313
return nil, err
315314
}
316315

317-
if p.permissive {
318-
// accept a multiple string literals. See https://github.com/yoheimuta/go-protoparser/issues/35.
319-
for {
320-
next := p.lex.Peek()
321-
if next == scanner.TCOMMA || next == scanner.TRIGHTSQUARE {
322-
break
323-
}
324-
325-
lit, _, err := p.lex.ReadConstant()
326-
if err != nil {
327-
return nil, err
328-
}
329-
constant = p.concatLiteral(constant, lit)
330-
}
331-
}
332-
333316
return &EnumValueOption{
334317
OptionName: optionName,
335318
Constant: constant,
336319
}, nil
337320
}
338-
339-
func (p *Parser) concatLiteral(base, next string) string {
340-
unQuoteNext, _, err := p.unQuote(next)
341-
if err != nil {
342-
return base + next
343-
}
344-
345-
unQuoteBase, quote, err := p.unQuote(base)
346-
if err != nil {
347-
return base + next
348-
}
349-
350-
return string(quote) + unQuoteBase + unQuoteNext + string(quote)
351-
}
352-
353-
func (p *Parser) unQuote(lit string) (string, rune, error) {
354-
for _, c := range []rune{'\'', '"'} {
355-
if strings.HasPrefix(lit, string(c)) && strings.HasSuffix(lit, string(c)) {
356-
return lit[1 : len(lit)-1], c, nil
357-
}
358-
}
359-
return lit, 0, p.unexpected("quote")
360-
}

parser/field.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (p *Parser) parseFieldOption() (*FieldOption, error) {
186186
return nil, err
187187
}
188188
default:
189-
constant, _, err = p.lex.ReadConstant()
189+
constant, _, err = p.lex.ReadConstant(p.permissive)
190190
if err != nil {
191191
return nil, err
192192
}
@@ -221,7 +221,7 @@ func (p *Parser) parseGoProtoValidatorFieldOptionConstant() (string, error) {
221221
}
222222
ret += p.lex.Text
223223

224-
constant, _, err := p.lex.ReadConstant()
224+
constant, _, err := p.lex.ReadConstant(p.permissive)
225225
if err != nil {
226226
return "", err
227227
}

parser/option.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (p *Parser) ParseOption() (*Option, error) {
7171
return nil, err
7272
}
7373
default:
74-
constant, _, err = p.lex.ReadConstant()
74+
constant, _, err = p.lex.ReadConstant(p.permissive)
7575
if err != nil {
7676
return nil, err
7777
}
@@ -114,7 +114,7 @@ func (p *Parser) parseCloudEndpointsOptionConstant() (string, error) {
114114
}
115115
ret += p.lex.Text
116116

117-
constant, _, err := p.lex.ReadConstant()
117+
constant, _, err := p.lex.ReadConstant(p.permissive)
118118
if err != nil {
119119
return "", err
120120
}

parser/option_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,28 @@ option (google.api.http) = {
110110
post: "/v1/resources",
111111
body: "resource",
112112
rest_method_name: "insert"
113+
};`,
114+
permissive: true,
115+
wantOption: &parser.Option{
116+
OptionName: "(google.api.http)",
117+
Constant: `{post:"/v1/resources",body:"resource",rest_method_name:"insert"}`,
118+
Meta: meta.Meta{
119+
Pos: meta.Position{
120+
Offset: 1,
121+
Line: 2,
122+
Column: 1,
123+
},
124+
},
125+
},
126+
},
127+
{
128+
name: "parses multiline string literal in multi-option annotation",
129+
input: `
130+
option (google.api.http) = {
131+
post: "/v1/resources",
132+
body: "res"
133+
"ource",
134+
rest_method_name: "insert"
113135
};`,
114136
permissive: true,
115137
wantOption: &parser.Option{

0 commit comments

Comments
 (0)