/** We here treat the property values as expressions: padding: {expression} {expression} {expression}; margin: {expression}; */ func (parser *Parser) ParseExpr(inParenthesis bool) ast.Expr { var pos = parser.Pos // plus or minus. This creates an unary expression that holds the later term. // this is for: +3 or -4 var expr ast.Expr = nil if tok := parser.acceptAnyOf2(ast.T_PLUS, ast.T_MINUS); tok != nil { if term := parser.ParseTerm(); term != nil { expr = ast.NewUnaryExpr(ast.NewOpWithToken(tok), term) if uexpr, ok := expr.(*ast.UnaryExpr); ok { // if it's evaluatable just return the evaluated value. if val, ok := runtime.ReduceExpr(uexpr, parser.GlobalContext); ok { expr = ast.Expr(val) } } } else { parser.restore(pos) return nil } } else { expr = parser.ParseTerm() } if expr == nil { debug("ParseExpr failed, got %+v, restoring to %d", expr, pos) parser.restore(pos) return nil } var rightTok = parser.peek() for rightTok.Type == ast.T_PLUS || rightTok.Type == ast.T_MINUS || rightTok.Type == ast.T_LITERAL_CONCAT { // accept plus or minus parser.advance() if rightTerm := parser.ParseTerm(); rightTerm != nil { // XXX: check parenthesis var bexpr = ast.NewBinaryExpr(ast.NewOpWithToken(rightTok), expr, rightTerm, inParenthesis) if val, ok := runtime.ReduceExpr(bexpr, parser.GlobalContext); ok { expr = ast.Expr(val) } else { // wrap the existing expression with the new binary expression object expr = ast.Expr(bexpr) } } else { panic(SyntaxError{ Reason: "Expecting term on the right side", ActualToken: parser.peek(), File: parser.File, }) } rightTok = parser.peek() } return expr }
/** The ParseFactor must return an Expr interface compatible object */ func (parser *Parser) ParseFactor() ast.Expr { var tok = parser.peek() if tok.Type == ast.T_PAREN_OPEN { parser.expect(ast.T_PAREN_OPEN) var expr = parser.ParseExpr(true) parser.expect(ast.T_PAREN_CLOSE) return expr } else if tok.Type == ast.T_INTERPOLATION_START { return parser.ParseInterp() } else if tok.Type == ast.T_QQ_STRING { parser.advance() return ast.NewStringWithQuote('"', tok) } else if tok.Type == ast.T_Q_STRING { parser.advance() return ast.NewStringWithQuote('\'', tok) } else if tok.Type == ast.T_UNQUOTE_STRING { parser.advance() return ast.NewStringWithQuote(0, tok) } else if tok.Type == ast.T_TRUE { parser.advance() return ast.NewBooleanTrue(tok) } else if tok.Type == ast.T_FALSE { parser.advance() return ast.NewBooleanFalse(tok) } else if tok.Type == ast.T_NULL { parser.advance() return ast.NewNullWithToken(tok) } else if tok.Type == ast.T_FUNCTION_NAME { var fcall = parser.ParseFunctionCall() return ast.Expr(fcall) } else if tok.Type == ast.T_VARIABLE { return parser.ParseVariable() } else if tok.Type == ast.T_IDENT { var tok2 = parser.peekBy(2) if tok2 != nil && tok2.Type == ast.T_PAREN_OPEN { return parser.ParseFunctionCall() } parser.advance() return ast.NewStringWithToken(tok) } else if tok.Type == ast.T_HEX_COLOR { parser.advance() return ast.NewHexColorFromToken(tok) } else if tok.Type == ast.T_INTEGER || tok.Type == ast.T_FLOAT { return parser.ParseNumber() } return nil }