Beispiel #1
0
/**

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
}
Beispiel #2
0
/**
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
}