Skip to content

Commit da37a57

Browse files
authored
Merge pull request #36 from yoheimuta/support-multiline-literal/35
feat: Support multiline string literals
2 parents 37e74c0 + eccf068 commit da37a57

File tree

3 files changed

+87
-1
lines changed

3 files changed

+87
-1
lines changed

_testdata/simple.proto

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ enum EnumAllowingAlias {
88
option allow_alias = true;
99
UNKNOWN = 0;
1010
STARTED = 1;
11-
RUNNING = 2 [(custom_option) = "hello world"];
11+
RUNNING = 2 [(custom_option) = "this is a "
12+
"string on two lines"
13+
];
1214
}
1315
message outer {
1416
option (my_option).a = true;

parser/enum.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package parser
22

33
import (
44
"fmt"
5+
"strings"
56

67
"github.com/yoheimuta/go-protoparser/internal/lexer/scanner"
78
"github.com/yoheimuta/go-protoparser/parser/meta"
@@ -313,8 +314,47 @@ func (p *Parser) parseEnumValueOption() (*EnumValueOption, error) {
313314
return nil, err
314315
}
315316

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+
316333
return &EnumValueOption{
317334
OptionName: optionName,
318335
Constant: constant,
319336
}, nil
320337
}
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/enum_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,50 @@ func TestParser_ParseEnum(t *testing.T) {
508508
},
509509
},
510510
},
511+
{
512+
name: "parsing an enum with multiple string literals. See #35",
513+
input: `enum EnumAllowingAlias {
514+
UNKNOWN = 0 [(custom_option) = "this is a "
515+
"string on two lines"
516+
];
517+
}
518+
`,
519+
permissive: true,
520+
wantEnum: &parser.Enum{
521+
EnumName: "EnumAllowingAlias",
522+
EnumBody: []parser.Visitee{
523+
&parser.EnumField{
524+
Ident: "UNKNOWN",
525+
Number: "0",
526+
EnumValueOptions: []*parser.EnumValueOption{
527+
{
528+
OptionName: "(custom_option)",
529+
Constant: `"this is a string on two lines"`,
530+
},
531+
},
532+
Meta: meta.Meta{
533+
Pos: meta.Position{
534+
Offset: 27,
535+
Line: 2,
536+
Column: 3,
537+
},
538+
},
539+
},
540+
},
541+
Meta: meta.Meta{
542+
Pos: meta.Position{
543+
Offset: 0,
544+
Line: 1,
545+
Column: 1,
546+
},
547+
LastPos: meta.Position{
548+
Offset: 143,
549+
Line: 5,
550+
Column: 1,
551+
},
552+
},
553+
},
554+
},
511555
}
512556

513557
for _, test := range tests {

0 commit comments

Comments
 (0)