2022-10-24 23:06:49 +08:00
package parser
import (
"bufio"
2024-02-06 14:02:12 +08:00
"errors"
2022-10-24 23:06:49 +08:00
"fmt"
components "github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser/flag"
"os"
2024-02-06 14:02:12 +08:00
"strings"
2022-10-24 23:06:49 +08:00
)
type Parser struct {
lexer * lexer
currentToken flag . Flag
followingToken flag . Flag
2024-02-06 14:02:12 +08:00
blockWrappers map [ string ] func ( * components . Directive ) ( components . IDirective , error )
2022-10-24 23:06:49 +08:00
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 ( )
2024-02-06 14:02:12 +08:00
parser . blockWrappers = map [ string ] func ( * components . Directive ) ( components . IDirective , error ) {
"http" : func ( directive * components . Directive ) ( components . IDirective , error ) {
return parser . wrapHttp ( directive ) , nil
2022-10-24 23:06:49 +08:00
} ,
2024-02-06 14:02:12 +08:00
"server" : func ( directive * components . Directive ) ( components . IDirective , error ) {
return parser . wrapServer ( directive ) , nil
} ,
"location" : func ( directive * components . Directive ) ( components . IDirective , error ) {
return parser . wrapLocation ( directive ) , nil
2022-10-24 23:06:49 +08:00
} ,
2024-02-06 14:02:12 +08:00
"upstream" : func ( directive * components . Directive ) ( components . IDirective , error ) {
return parser . wrapUpstream ( directive ) , nil
2022-10-24 23:06:49 +08:00
} ,
2024-02-06 14:02:12 +08:00
"_by_lua_block" : func ( directive * components . Directive ) ( components . IDirective , error ) {
return parser . wrapLuaBlock ( directive )
2022-10-24 23:06:49 +08:00
} ,
}
parser . directiveWrappers = map [ string ] func ( * components . Directive ) components . IDirective {
"server" : func ( directive * components . Directive ) components . IDirective {
2024-03-19 13:50:06 +08:00
return parser . wrapServer ( directive )
2022-10-24 23:06:49 +08:00
} ,
}
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
}
2024-02-06 14:02:12 +08:00
func ( p * Parser ) Parse ( ) ( * components . Config , error ) {
parsedBlock , err := p . parseBlock ( false )
if err != nil {
return nil , err
}
c := & components . Config {
2022-10-24 23:06:49 +08:00
FilePath : p . lexer . file ,
2024-02-06 14:02:12 +08:00
Block : parsedBlock ,
2022-10-24 23:06:49 +08:00
}
2024-02-06 14:02:12 +08:00
return c , err
2022-10-24 23:06:49 +08:00
}
2024-02-06 14:02:12 +08:00
func ( p * Parser ) parseBlock ( inBlock bool ) ( * components . Block , error ) {
2022-10-24 23:06:49 +08:00
context := & components . Block {
Comment : "" ,
Directives : make ( [ ] components . IDirective , 0 ) ,
2022-11-30 17:33:30 +08:00
Line : p . currentToken . Line ,
2022-10-24 23:06:49 +08:00
}
parsingloop :
for {
switch {
2024-02-06 14:02:12 +08:00
case p . curTokenIs ( flag . EOF ) :
if inBlock {
return nil , errors . New ( "unexpected eof in block" )
}
break parsingloop
case p . curTokenIs ( flag . BlockEnd ) :
2022-10-24 23:06:49 +08:00
break parsingloop
2024-02-06 14:02:12 +08:00
case p . curTokenIs ( flag . LuaCode ) :
context . IsLuaBlock = true
context . LiteralCode = p . currentToken . Literal
2024-03-19 13:50:06 +08:00
case p . curTokenIs ( flag . Keyword ) || p . curTokenIs ( flag . QuotedString ) :
2024-02-06 14:02:12 +08:00
s , err := p . parseStatement ( )
if err != nil {
return nil , err
}
context . Directives = append ( context . Directives , s )
2022-10-24 23:06:49 +08:00
case p . curTokenIs ( flag . Comment ) :
context . Directives = append ( context . Directives , & components . Comment {
Detail : p . currentToken . Literal ,
2022-11-30 17:33:30 +08:00
Line : p . currentToken . Line ,
2022-10-24 23:06:49 +08:00
} )
}
p . nextToken ( )
}
2024-02-06 14:02:12 +08:00
return context , nil
2022-10-24 23:06:49 +08:00
}
2024-02-06 14:02:12 +08:00
func ( p * Parser ) parseStatement ( ) ( components . IDirective , error ) {
2022-10-24 23:06:49 +08:00
d := & components . Directive {
Name : p . currentToken . Literal ,
2022-11-30 17:33:30 +08:00
Line : p . currentToken . Line ,
2022-10-24 23:06:49 +08: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 {
2024-02-06 14:02:12 +08:00
return dw ( d ) , nil
2022-10-24 23:06:49 +08:00
}
if p . followingTokenIs ( flag . Comment ) && p . currentToken . Line == p . followingToken . Line {
d . Comment = p . followingToken . Literal
p . nextToken ( )
}
2024-02-06 14:02:12 +08:00
return d , nil
2022-10-24 23:06:49 +08:00
}
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 ( )
}
2024-02-06 14:02:12 +08:00
block , err := p . parseBlock ( false )
if err != nil {
return nil , err
}
2022-10-24 23:06:49 +08:00
block . Comment = inLineComment
d . Block = block
2024-02-06 14:02:12 +08:00
if strings . HasSuffix ( d . Name , "_by_lua_block" ) {
return p . blockWrappers [ "_by_lua_block" ] ( d )
}
2022-10-24 23:06:49 +08:00
if bw , ok := p . blockWrappers [ d . Name ] ; ok {
return bw ( d )
}
2024-02-06 14:02:12 +08:00
return d , nil
2022-10-24 23:06:49 +08:00
}
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
}
2024-02-06 14:02:12 +08:00
func ( p * Parser ) wrapLuaBlock ( directive * components . Directive ) ( * components . LuaBlock , error ) {
return components . NewLuaBlock ( directive )
}
2022-10-24 23:06:49 +08:00
func ( p * Parser ) parseUpstreamServer ( directive * components . Directive ) * components . UpstreamServer {
return components . NewUpstreamServer ( directive )
}