173 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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),
 | |
| 	}
 | |
| 
 | |
| 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,
 | |
| 			})
 | |
| 		}
 | |
| 		p.nextToken()
 | |
| 	}
 | |
| 
 | |
| 	return context
 | |
| }
 | |
| 
 | |
| func (p *Parser) parseStatement() components.IDirective {
 | |
| 	d := &components.Directive{
 | |
| 		Name: p.currentToken.Literal,
 | |
| 	}
 | |
| 
 | |
| 	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)
 | |
| }
 | 
