2022-10-24 15:06:49 +00:00
package parser
import (
"bufio"
"fmt"
components "github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser/flag"
"os"
)
type Parser struct {
lexer * lexer
currentToken flag . Flag
followingToken flag . Flag
blockWrappers map [ string ] func ( * components . Directive ) components . IDirective
directiveWrappers map [ string ] func ( * components . Directive ) components . IDirective
}
func NewStringParser ( str string ) * Parser {
return NewParserFromLexer ( lex ( str ) )
}
func NewParser ( filePath string ) ( * Parser , error ) {
f , err := os . Open ( filePath )
if err != nil {
return nil , err
}
l := newLexer ( bufio . NewReader ( f ) )
l . file = filePath
p := NewParserFromLexer ( l )
return p , nil
}
func NewParserFromLexer ( lexer * lexer ) * Parser {
parser := & Parser {
lexer : lexer ,
}
parser . nextToken ( )
parser . nextToken ( )
parser . blockWrappers = map [ string ] func ( * components . Directive ) components . IDirective {
"http" : func ( directive * components . Directive ) components . IDirective {
return parser . wrapHttp ( directive )
} ,
"server" : func ( directive * components . Directive ) components . IDirective {
return parser . wrapServer ( directive )
} ,
"location" : func ( directive * components . Directive ) components . IDirective {
return parser . wrapLocation ( directive )
} ,
"upstream" : func ( directive * components . Directive ) components . IDirective {
return parser . wrapUpstream ( directive )
} ,
}
parser . directiveWrappers = map [ string ] func ( * components . Directive ) components . IDirective {
"server" : func ( directive * components . Directive ) components . IDirective {
return parser . parseUpstreamServer ( directive )
} ,
}
return parser
}
func ( p * Parser ) nextToken ( ) {
p . currentToken = p . followingToken
p . followingToken = p . lexer . scan ( )
}
func ( p * Parser ) curTokenIs ( t flag . Type ) bool {
return p . currentToken . Type == t
}
func ( p * Parser ) followingTokenIs ( t flag . Type ) bool {
return p . followingToken . Type == t
}
func ( p * Parser ) Parse ( ) * components . Config {
return & components . Config {
FilePath : p . lexer . file ,
Block : p . parseBlock ( ) ,
}
}
func ( p * Parser ) parseBlock ( ) * components . Block {
context := & components . Block {
Comment : "" ,
Directives : make ( [ ] components . IDirective , 0 ) ,
2022-11-30 09:33:30 +00:00
Line : p . currentToken . Line ,
2022-10-24 15:06:49 +00:00
}
parsingloop :
for {
switch {
case p . curTokenIs ( flag . EOF ) || p . curTokenIs ( flag . BlockEnd ) :
break parsingloop
case p . curTokenIs ( flag . Keyword ) :
context . Directives = append ( context . Directives , p . parseStatement ( ) )
case p . curTokenIs ( flag . Comment ) :
context . Directives = append ( context . Directives , & components . Comment {
Detail : p . currentToken . Literal ,
2022-11-30 09:33:30 +00:00
Line : p . currentToken . Line ,
2022-10-24 15:06:49 +00:00
} )
}
p . nextToken ( )
}
return context
}
func ( p * Parser ) parseStatement ( ) components . IDirective {
d := & components . Directive {
Name : p . currentToken . Literal ,
2022-11-30 09:33:30 +00:00
Line : p . currentToken . Line ,
2022-10-24 15:06:49 +00:00
}
for p . nextToken ( ) ; p . currentToken . IsParameterEligible ( ) ; p . nextToken ( ) {
d . Parameters = append ( d . Parameters , p . currentToken . Literal )
}
if p . curTokenIs ( flag . Semicolon ) {
if dw , ok := p . directiveWrappers [ d . Name ] ; ok {
return dw ( d )
}
if p . followingTokenIs ( flag . Comment ) && p . currentToken . Line == p . followingToken . Line {
d . Comment = p . followingToken . Literal
p . nextToken ( )
}
return d
}
if p . curTokenIs ( flag . BlockStart ) {
inLineComment := ""
if p . followingTokenIs ( flag . Comment ) && p . currentToken . Line == p . followingToken . Line {
inLineComment = p . followingToken . Literal
p . nextToken ( )
p . nextToken ( )
}
block := p . parseBlock ( )
block . Comment = inLineComment
d . Block = block
if bw , ok := p . blockWrappers [ d . Name ] ; ok {
return bw ( d )
}
return d
}
panic ( fmt . Errorf ( "unexpected token %s (%s) on line %d, column %d" , p . currentToken . Type . String ( ) , p . currentToken . Literal , p . currentToken . Line , p . currentToken . Column ) )
}
func ( p * Parser ) wrapLocation ( directive * components . Directive ) * components . Location {
return components . NewLocation ( directive )
}
func ( p * Parser ) wrapServer ( directive * components . Directive ) * components . Server {
s , _ := components . NewServer ( directive )
return s
}
func ( p * Parser ) wrapUpstream ( directive * components . Directive ) * components . Upstream {
s , _ := components . NewUpstream ( directive )
return s
}
func ( p * Parser ) wrapHttp ( directive * components . Directive ) * components . Http {
h , _ := components . NewHttp ( directive )
return h
}
func ( p * Parser ) parseUpstreamServer ( directive * components . Directive ) * components . UpstreamServer {
return components . NewUpstreamServer ( directive )
}