123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- package pongo2
- import (
- "bytes"
- "fmt"
- "math"
- )
- type Expression struct {
- // TODO: Add location token?
- expr1 IEvaluator
- expr2 IEvaluator
- op_token *Token
- }
- type relationalExpression struct {
- // TODO: Add location token?
- expr1 IEvaluator
- expr2 IEvaluator
- op_token *Token
- }
- type simpleExpression struct {
- negate bool
- negative_sign bool
- term1 IEvaluator
- term2 IEvaluator
- op_token *Token
- }
- type term struct {
- // TODO: Add location token?
- factor1 IEvaluator
- factor2 IEvaluator
- op_token *Token
- }
- type power struct {
- // TODO: Add location token?
- power1 IEvaluator
- power2 IEvaluator
- }
- func (expr *Expression) FilterApplied(name string) bool {
- return expr.expr1.FilterApplied(name) && (expr.expr2 == nil ||
- (expr.expr2 != nil && expr.expr2.FilterApplied(name)))
- }
- func (expr *relationalExpression) FilterApplied(name string) bool {
- return expr.expr1.FilterApplied(name) && (expr.expr2 == nil ||
- (expr.expr2 != nil && expr.expr2.FilterApplied(name)))
- }
- func (expr *simpleExpression) FilterApplied(name string) bool {
- return expr.term1.FilterApplied(name) && (expr.term2 == nil ||
- (expr.term2 != nil && expr.term2.FilterApplied(name)))
- }
- func (t *term) FilterApplied(name string) bool {
- return t.factor1.FilterApplied(name) && (t.factor2 == nil ||
- (t.factor2 != nil && t.factor2.FilterApplied(name)))
- }
- func (p *power) FilterApplied(name string) bool {
- return p.power1.FilterApplied(name) && (p.power2 == nil ||
- (p.power2 != nil && p.power2.FilterApplied(name)))
- }
- func (expr *Expression) GetPositionToken() *Token {
- return expr.expr1.GetPositionToken()
- }
- func (expr *relationalExpression) GetPositionToken() *Token {
- return expr.expr1.GetPositionToken()
- }
- func (expr *simpleExpression) GetPositionToken() *Token {
- return expr.term1.GetPositionToken()
- }
- func (expr *term) GetPositionToken() *Token {
- return expr.factor1.GetPositionToken()
- }
- func (expr *power) GetPositionToken() *Token {
- return expr.power1.GetPositionToken()
- }
- func (expr *Expression) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
- value, err := expr.Evaluate(ctx)
- if err != nil {
- return err
- }
- buffer.WriteString(value.String())
- return nil
- }
- func (expr *relationalExpression) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
- value, err := expr.Evaluate(ctx)
- if err != nil {
- return err
- }
- buffer.WriteString(value.String())
- return nil
- }
- func (expr *simpleExpression) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
- value, err := expr.Evaluate(ctx)
- if err != nil {
- return err
- }
- buffer.WriteString(value.String())
- return nil
- }
- func (expr *term) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
- value, err := expr.Evaluate(ctx)
- if err != nil {
- return err
- }
- buffer.WriteString(value.String())
- return nil
- }
- func (expr *power) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) *Error {
- value, err := expr.Evaluate(ctx)
- if err != nil {
- return err
- }
- buffer.WriteString(value.String())
- return nil
- }
- func (expr *Expression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
- v1, err := expr.expr1.Evaluate(ctx)
- if err != nil {
- return nil, err
- }
- if expr.expr2 != nil {
- v2, err := expr.expr2.Evaluate(ctx)
- if err != nil {
- return nil, err
- }
- switch expr.op_token.Val {
- case "and", "&&":
- return AsValue(v1.IsTrue() && v2.IsTrue()), nil
- case "or", "||":
- return AsValue(v1.IsTrue() || v2.IsTrue()), nil
- default:
- panic(fmt.Sprintf("unimplemented: %s", expr.op_token.Val))
- }
- } else {
- return v1, nil
- }
- }
- func (expr *relationalExpression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
- v1, err := expr.expr1.Evaluate(ctx)
- if err != nil {
- return nil, err
- }
- if expr.expr2 != nil {
- v2, err := expr.expr2.Evaluate(ctx)
- if err != nil {
- return nil, err
- }
- switch expr.op_token.Val {
- case "<=":
- if v1.IsFloat() || v2.IsFloat() {
- return AsValue(v1.Float() <= v2.Float()), nil
- } else {
- return AsValue(v1.Integer() <= v2.Integer()), nil
- }
- case ">=":
- if v1.IsFloat() || v2.IsFloat() {
- return AsValue(v1.Float() >= v2.Float()), nil
- } else {
- return AsValue(v1.Integer() >= v2.Integer()), nil
- }
- case "==":
- return AsValue(v1.EqualValueTo(v2)), nil
- case ">":
- if v1.IsFloat() || v2.IsFloat() {
- return AsValue(v1.Float() > v2.Float()), nil
- } else {
- return AsValue(v1.Integer() > v2.Integer()), nil
- }
- case "<":
- if v1.IsFloat() || v2.IsFloat() {
- return AsValue(v1.Float() < v2.Float()), nil
- } else {
- return AsValue(v1.Integer() < v2.Integer()), nil
- }
- case "!=", "<>":
- return AsValue(!v1.EqualValueTo(v2)), nil
- case "in":
- return AsValue(v2.Contains(v1)), nil
- default:
- panic(fmt.Sprintf("unimplemented: %s", expr.op_token.Val))
- }
- } else {
- return v1, nil
- }
- }
- func (expr *simpleExpression) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
- t1, err := expr.term1.Evaluate(ctx)
- if err != nil {
- return nil, err
- }
- result := t1
- if expr.negate {
- result = result.Negate()
- }
- if expr.negative_sign {
- if result.IsNumber() {
- switch {
- case result.IsFloat():
- result = AsValue(-1 * result.Float())
- case result.IsInteger():
- result = AsValue(-1 * result.Integer())
- default:
- panic("not possible")
- }
- } else {
- return nil, ctx.Error("Negative sign on a non-number expression", expr.GetPositionToken())
- }
- }
- if expr.term2 != nil {
- t2, err := expr.term2.Evaluate(ctx)
- if err != nil {
- return nil, err
- }
- switch expr.op_token.Val {
- case "+":
- if result.IsFloat() || t2.IsFloat() {
- // Result will be a float
- return AsValue(result.Float() + t2.Float()), nil
- } else {
- // Result will be an integer
- return AsValue(result.Integer() + t2.Integer()), nil
- }
- case "-":
- if result.IsFloat() || t2.IsFloat() {
- // Result will be a float
- return AsValue(result.Float() - t2.Float()), nil
- } else {
- // Result will be an integer
- return AsValue(result.Integer() - t2.Integer()), nil
- }
- default:
- panic("unimplemented")
- }
- }
- return result, nil
- }
- func (t *term) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
- f1, err := t.factor1.Evaluate(ctx)
- if err != nil {
- return nil, err
- }
- if t.factor2 != nil {
- f2, err := t.factor2.Evaluate(ctx)
- if err != nil {
- return nil, err
- }
- switch t.op_token.Val {
- case "*":
- if f1.IsFloat() || f2.IsFloat() {
- // Result will be float
- return AsValue(f1.Float() * f2.Float()), nil
- }
- // Result will be int
- return AsValue(f1.Integer() * f2.Integer()), nil
- case "/":
- if f1.IsFloat() || f2.IsFloat() {
- // Result will be float
- return AsValue(f1.Float() / f2.Float()), nil
- }
- // Result will be int
- return AsValue(f1.Integer() / f2.Integer()), nil
- case "%":
- // Result will be int
- return AsValue(f1.Integer() % f2.Integer()), nil
- default:
- panic("unimplemented")
- }
- } else {
- return f1, nil
- }
- }
- func (pw *power) Evaluate(ctx *ExecutionContext) (*Value, *Error) {
- p1, err := pw.power1.Evaluate(ctx)
- if err != nil {
- return nil, err
- }
- if pw.power2 != nil {
- p2, err := pw.power2.Evaluate(ctx)
- if err != nil {
- return nil, err
- }
- return AsValue(math.Pow(p1.Float(), p2.Float())), nil
- } else {
- return p1, nil
- }
- }
- func (p *Parser) parseFactor() (IEvaluator, *Error) {
- if p.Match(TokenSymbol, "(") != nil {
- expr, err := p.ParseExpression()
- if err != nil {
- return nil, err
- }
- if p.Match(TokenSymbol, ")") == nil {
- return nil, p.Error("Closing bracket expected after expression", nil)
- }
- return expr, nil
- }
- return p.parseVariableOrLiteralWithFilter()
- }
- func (p *Parser) parsePower() (IEvaluator, *Error) {
- pw := new(power)
- power1, err := p.parseFactor()
- if err != nil {
- return nil, err
- }
- pw.power1 = power1
- if p.Match(TokenSymbol, "^") != nil {
- power2, err := p.parsePower()
- if err != nil {
- return nil, err
- }
- pw.power2 = power2
- }
- if pw.power2 == nil {
- // Shortcut for faster evaluation
- return pw.power1, nil
- }
- return pw, nil
- }
- func (p *Parser) parseTerm() (IEvaluator, *Error) {
- return_term := new(term)
- factor1, err := p.parsePower()
- if err != nil {
- return nil, err
- }
- return_term.factor1 = factor1
- for p.PeekOne(TokenSymbol, "*", "/", "%") != nil {
- if return_term.op_token != nil {
- // Create new sub-term
- return_term = &term{
- factor1: return_term,
- }
- }
- op := p.Current()
- p.Consume()
- factor2, err := p.parsePower()
- if err != nil {
- return nil, err
- }
- return_term.op_token = op
- return_term.factor2 = factor2
- }
- if return_term.op_token == nil {
- // Shortcut for faster evaluation
- return return_term.factor1, nil
- }
- return return_term, nil
- }
- func (p *Parser) parseSimpleExpression() (IEvaluator, *Error) {
- expr := new(simpleExpression)
- if sign := p.MatchOne(TokenSymbol, "+", "-"); sign != nil {
- if sign.Val == "-" {
- expr.negative_sign = true
- }
- }
- if p.Match(TokenSymbol, "!") != nil || p.Match(TokenKeyword, "not") != nil {
- expr.negate = true
- }
- term1, err := p.parseTerm()
- if err != nil {
- return nil, err
- }
- expr.term1 = term1
- for p.PeekOne(TokenSymbol, "+", "-") != nil {
- if expr.op_token != nil {
- // New sub expr
- expr = &simpleExpression{
- term1: expr,
- }
- }
- op := p.Current()
- p.Consume()
- term2, err := p.parseTerm()
- if err != nil {
- return nil, err
- }
- expr.term2 = term2
- expr.op_token = op
- }
- if expr.negate == false && expr.negative_sign == false && expr.term2 == nil {
- // Shortcut for faster evaluation
- return expr.term1, nil
- }
- return expr, nil
- }
- func (p *Parser) parseRelationalExpression() (IEvaluator, *Error) {
- expr1, err := p.parseSimpleExpression()
- if err != nil {
- return nil, err
- }
- expr := &relationalExpression{
- expr1: expr1,
- }
- if t := p.MatchOne(TokenSymbol, "==", "<=", ">=", "!=", "<>", ">", "<"); t != nil {
- expr2, err := p.parseRelationalExpression()
- if err != nil {
- return nil, err
- }
- expr.op_token = t
- expr.expr2 = expr2
- } else if t := p.MatchOne(TokenKeyword, "in"); t != nil {
- expr2, err := p.parseSimpleExpression()
- if err != nil {
- return nil, err
- }
- expr.op_token = t
- expr.expr2 = expr2
- }
- if expr.expr2 == nil {
- // Shortcut for faster evaluation
- return expr.expr1, nil
- }
- return expr, nil
- }
- func (p *Parser) ParseExpression() (IEvaluator, *Error) {
- rexpr1, err := p.parseRelationalExpression()
- if err != nil {
- return nil, err
- }
- exp := &Expression{
- expr1: rexpr1,
- }
- if p.PeekOne(TokenSymbol, "&&", "||") != nil || p.PeekOne(TokenKeyword, "and", "or") != nil {
- op := p.Current()
- p.Consume()
- expr2, err := p.ParseExpression()
- if err != nil {
- return nil, err
- }
- exp.expr2 = expr2
- exp.op_token = op
- }
- if exp.expr2 == nil {
- // Shortcut for faster evaluation
- return exp.expr1, nil
- }
- return exp, nil
- }
|