Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Unexpected token QuotedString#65 #66

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions config/location.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func NewLocation(directive IDirective) (*Location, error) {
return nil, errors.New("too many arguments for location directive")
}

// FindDirectives find directives by name
func (l *Location) FindDirectives(directiveName string) []IDirective {
block := l.GetBlock()
if block == nil {
Expand All @@ -65,6 +66,7 @@ func (l *Location) FindDirectives(directiveName string) []IDirective {
return block.FindDirectives(directiveName)
}

// GetDirectives get all directives
func (l *Location) GetDirectives() []IDirective {
block := l.GetBlock()
if block == nil {
Expand Down
15 changes: 9 additions & 6 deletions config/statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,23 @@ type IDirective interface {

// InlineCommenter represents the inline comment holder
type InlineCommenter interface {
GetInlineComment() string
SetInlineComment(comment string)
GetInlineComment() []InlineComment
SetInlineComment(comment InlineComment)
}

// DefaultInlineComment represents the default inline comment holder
type DefaultInlineComment struct {
InlineComment string
InlineComment []InlineComment
}

// GetInlineComment returns the inline comment
func (d *DefaultInlineComment) GetInlineComment() string {
func (d *DefaultInlineComment) GetInlineComment() []InlineComment {
return d.InlineComment
}

// SetInlineComment sets the inline comment
func (d *DefaultInlineComment) SetInlineComment(comment string) {
d.InlineComment = comment
func (d *DefaultInlineComment) SetInlineComment(comment InlineComment) {
d.InlineComment = append(d.InlineComment, comment)
}

// FileDirective a statement that saves its own file
Expand Down Expand Up @@ -84,3 +84,6 @@ func (p *Parameter) SetRelativeLineIndex(i int) {
func (p *Parameter) GetRelativeLineIndex() int {
return p.RelativeLineIndex
}

// InlineComment represents an inline comment
type InlineComment Parameter
36 changes: 25 additions & 11 deletions dumper/dumper.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,31 +88,45 @@ func DumpDirective(d config.IDirective, style *Style) string {
if style.SpaceBeforeBlocks && d.GetBlock() != nil {
buf.WriteString("\n")
}
// outline comment
if len(d.GetComment()) > 0 {
for _, comment := range d.GetComment() {
buf.WriteString(fmt.Sprintf("%s%s\n", strings.Repeat(" ", style.StartIndent), comment))
}
}
buf.WriteString(fmt.Sprintf("%s%s", strings.Repeat(" ", style.StartIndent), d.GetName()))
if len(d.GetParameters()) > 0 {
// Use relative line index to handle different line number arrangements of instruction parameters
relativeLineIndex := 0
for _, parameter := range d.GetParameters() {
// If the parameter line index is not the same as the previous one, add a new line
if parameter.GetRelativeLineIndex() != relativeLineIndex {
buf.WriteString("\n")
buf.WriteString(fmt.Sprintf("%s%s", strings.Repeat(" ", style.StartIndent), parameter.GetValue()))
relativeLineIndex = parameter.GetRelativeLineIndex()

inlineComments := make(map[int]config.InlineComment)
for _, comment := range d.GetInlineComment() {
inlineComments[comment.RelativeLineIndex] = comment
}

// Use relative line index to handle different line number arrangements of instruction parameters
relativeLineIndex := 0
for _, parameter := range d.GetParameters() {
// If the parameter line index is not the same as the previous one, add a new line
if parameter.GetRelativeLineIndex() != relativeLineIndex {
// write param comment
if comment, ok := inlineComments[relativeLineIndex]; ok {
buf.WriteString(fmt.Sprintf(" %s\n", comment.Value))
} else {
buf.WriteString(fmt.Sprintf(" %s", parameter.GetValue()))
buf.WriteString("\n")
}
buf.WriteString(fmt.Sprintf("%s%s", strings.Repeat(" ", style.StartIndent+style.Indent), parameter.GetValue()))
relativeLineIndex = parameter.GetRelativeLineIndex()
} else {
buf.WriteString(fmt.Sprintf(" %s", parameter.GetValue()))
}
}

if d.GetBlock() == nil {
if d.GetName() != "" {
buf.WriteRune(';')
}
buf.WriteString(d.GetInlineComment())
// the last inline comment
if comment, ok := inlineComments[relativeLineIndex]; ok {
buf.WriteString(comment.Value)
}
} else {
buf.WriteString(" {\n")
buf.WriteString(DumpBlock(d.GetBlock(), style.Iterate()))
Expand Down
119 changes: 58 additions & 61 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,18 +236,8 @@ parsingLoop:
if p.opts.skipComments {
break
}
// inline comment
if line == p.currentToken.Line {
if s == nil && len(context.Directives) > 0 {
s = context.Directives[len(context.Directives)-1]
}
s.SetInlineComment(p.currentToken.Literal)
s.SetLine(line)
p.commentBuffer = nil
} else {
p.commentBuffer = append(p.commentBuffer, p.currentToken.Literal)
}

// outline comment
p.commentBuffer = append(p.commentBuffer, p.currentToken.Literal)
}
p.nextToken()
}
Expand All @@ -274,67 +264,74 @@ func (p *Parser) parseStatement(isSkipValidDirective bool) (config.IDirective, e
return sp()
}

// set outline comment
if len(p.commentBuffer) > 0 {
d.Comment = p.commentBuffer
p.commentBuffer = nil
p.commentBuffer = make([]string, 0)
}

//parse parameters until the end.
// keep track of the line index of the directive
directiveLineIndex := p.currentToken.Line
for p.nextToken(); p.currentToken.IsParameterEligible(); p.nextToken() {
d.Parameters = append(d.Parameters, config.Parameter{
Value: p.currentToken.Literal,
RelativeLineIndex: p.currentToken.Line - directiveLineIndex}) // save the relative line index of the parameter
if p.currentToken.Is(token.BlockEnd) {
directiveLineIndex := p.currentToken.Line // keep track of the line index of the directive
// Parse parameters until reaching the semicolon that ends the directive.
for {
p.nextToken()
if p.currentToken.IsParameterEligible() {
d.Parameters = append(d.Parameters, config.Parameter{
Value: p.currentToken.Literal,
RelativeLineIndex: p.currentToken.Line - directiveLineIndex}) // save the relative line index of the parameter
if p.currentToken.Is(token.BlockEnd) {
return d, nil
}
} else if p.curTokenIs(token.Semicolon) {
// inline comment in following token
if !p.opts.skipComments {
if p.followingTokenIs(token.Comment) && p.followingToken.Line == p.currentToken.Line {
// if following token is a comment, then it is an inline comment, fetch next token
p.nextToken()
d.SetInlineComment(config.InlineComment{
Value: p.currentToken.Literal,
RelativeLineIndex: p.currentToken.Line - directiveLineIndex,
})
}
}
if iw, ok := p.includeWrappers[d.Name]; ok {
include, err := iw(d)
if err != nil {
return nil, err
}
return p.ParseInclude(include.(*config.Include))
} else if dw, ok := p.directiveWrappers[d.Name]; ok {
return dw(d)
}
return d, nil
}
}

//if we find a semicolon it is a directive, we will check directive converters
if p.curTokenIs(token.Semicolon) {
if iw, ok := p.includeWrappers[d.Name]; ok {
include, err := iw(d)
} else if p.curTokenIs(token.Comment) {
// param comment
d.SetInlineComment(config.InlineComment{
Value: p.currentToken.Literal,
RelativeLineIndex: p.currentToken.Line - directiveLineIndex,
})
} else if p.curTokenIs(token.BlockStart) {
_, blockSkip1 := SkipValidBlocks[d.Name]
_, blockSkip2 := p.opts.skipValidSubDirectiveBlock[d.Name]
isSkipBlockSubDirective := blockSkip1 || blockSkip2 || isSkipValidDirective

b, err := p.parseBlock(true, isSkipBlockSubDirective)
if err != nil {
return nil, err
}
return p.ParseInclude(include.(*config.Include))
} else if dw, ok := p.directiveWrappers[d.Name]; ok {
return dw(d)
}
return d, nil
}
for {
if p.curTokenIs(token.Comment) {
p.commentBuffer = append(p.commentBuffer, p.currentToken.Literal)
p.nextToken()
} else {
break
}
}
d.Block = b

//ok, it does not end with a semicolon but a block starts, we will convert that block if we have a converter
if p.curTokenIs(token.BlockStart) {
_, blockSkip1 := SkipValidBlocks[d.Name]
_, blockSkip2 := p.opts.skipValidSubDirectiveBlock[d.Name]
isSkipBlockSubDirective := blockSkip1 || blockSkip2 || isSkipValidDirective
b, err := p.parseBlock(true, isSkipBlockSubDirective)
if err != nil {
return nil, err
}
d.Block = b

if strings.HasSuffix(d.Name, "_by_lua_block") {
return p.blockWrappers["_by_lua_block"](d)
}
if strings.HasSuffix(d.Name, "_by_lua_block") {
return p.blockWrappers["_by_lua_block"](d)
}

if bw, ok := p.blockWrappers[d.Name]; ok {
return bw(d)
if bw, ok := p.blockWrappers[d.Name]; ok {
return bw(d)
}
return d, nil
} else {
return nil, fmt.Errorf("unexpected token %s (%s) on line %d, column %d", p.currentToken.Type.String(), p.currentToken.Literal, p.currentToken.Line, p.currentToken.Column)
}
return d, nil
}

return nil, fmt.Errorf("unexpected token %s (%s) on line %d, column %d", p.currentToken.Type.String(), p.currentToken.Literal, p.currentToken.Line, p.currentToken.Column)
}

// ParseInclude just parse include confs
Expand Down
28 changes: 23 additions & 5 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,14 +574,14 @@ stream {

func TestParser_KeepDataInMultiLine01(t *testing.T) {
p := NewStringParser(`log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';`)
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';`)
conf, err := p.Parse()
assert.NilError(t, err, "no error expected here")
s := dumper.DumpConfig(conf, dumper.IndentedStyle)
assert.Equal(t, `log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';`, s)
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';`, s)

}

Expand All @@ -594,7 +594,25 @@ func TestParser_KeepDataInMultiLine02(t *testing.T) {
s := dumper.DumpConfig(conf, dumper.IndentedStyle)
assert.Equal(t, `events {
worker_connections
4096;
4096;
}`, s)

}

func TestParser_QuotedString_ISSUE65(t *testing.T) {
p := NewStringParser(`log_format json_analytics escape=json '{' # json start
'"msec": "$msec", ' # request unixtime in seconds with a milliseconds resolution
'"connection": "$connection", ' # connection serial number
'"connection_requests": "$connection_requests", ' # number of requests made in connection
'}'; # inline comment
error_log off; # error_log inline comment`)
conf, err := p.Parse()
assert.NilError(t, err, "no error expected here")
s := dumper.DumpConfig(conf, dumper.IndentedStyle)
assert.Equal(t, `log_format json_analytics escape=json '{' # json start
'"msec": "$msec", ' # request unixtime in seconds with a milliseconds resolution
'"connection": "$connection", ' # connection serial number
'"connection_requests": "$connection_requests", ' # number of requests made in connection
'}';# inline comment
error_log off;# error_log inline comment`, s)
}
Loading