Files
trivy/pkg/licensing/expression/parser/parser.go

103 lines
2.2 KiB
Go

package parser
import (
"fmt"
"strings"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/licensing/expression/lexer"
"github.com/aquasecurity/trivy/pkg/licensing/expression/token"
)
var (
ErrInvalidExpression = xerrors.New("invalid expression error")
)
type Parser struct {
lex *lexer.Lexer
normalizeFn []NormalizeFunc
}
type LicenseExpression struct {
Node Node
Operator string
Next *LicenseExpression
}
type Node struct {
License string
LicenseExpression *LicenseExpression
}
type NormalizeFunc func(n string) string
func New(lex *lexer.Lexer) *Parser {
return &Parser{
lex: lex,
}
}
func (p *Parser) RegisterNormalizeFunc(fn ...NormalizeFunc) *Parser {
p.normalizeFn = append(p.normalizeFn, fn...)
return p
}
func (p *Parser) Parse() (*LicenseExpression, error) {
root := &LicenseExpression{}
cursor := root
stack := Stack{}
for tok := p.lex.NextToken(); tok.Type != token.EOF; tok = p.lex.NextToken() {
switch tok.Type {
case token.IDENT:
if cursor.Node.License == "" {
cursor.Node = Node{License: tok.Literal}
} else {
cursor.Node.License = fmt.Sprintf("%s %s", cursor.Node.License, tok.Literal)
}
case token.AND, token.OR:
cursor.Operator = string(tok.Type)
cursor.Next = &LicenseExpression{}
cursor = cursor.Next
case token.LPAREN:
p := Pair{root: root, cursor: cursor, bracket: tok.Type}
stack.Push(p)
root = &LicenseExpression{}
cursor = root
case token.RPAREN:
e := stack.Pop()
if e.bracket == token.LPAREN && tok.Type != token.RPAREN {
return nil, ErrInvalidExpression
}
e.cursor.Node.LicenseExpression = root
cursor = e.cursor
root = e.root
}
}
if !stack.IsEmpty() {
return nil, ErrInvalidExpression
}
return root, nil
}
func (p *Parser) Normalize(l *LicenseExpression) string {
cursor := l
var str string
for ; cursor != nil; cursor = cursor.Next {
str = strings.Join([]string{str, p.normalize(cursor.Node), cursor.Operator}, " ")
}
return strings.TrimSpace(str)
}
func (p *Parser) normalize(n Node) string {
if n.LicenseExpression != nil {
return fmt.Sprintf("( %s )", p.Normalize(n.LicenseExpression))
}
for _, fn := range p.normalizeFn {
n.License = fn(n.License)
}
return n.License
}