Ejemplo n.º 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
}
Ejemplo n.º 2
0
/*
This method parses media type first, then expecting more that on media
expressions.

media_query: [[only | not]? <media_type> [ and <expression> ]*]
  | <expression> [ and <expression> ]*
expression: ( <media_feature> [: <value>]? )

Specification: http://dev.w3.org/csswg/mediaqueries-3
*/
func (parser *Parser) ParseMediaQuery() *ast.MediaQuery {

	// the leading media type is optional
	var mediaType = parser.ParseMediaType()
	if mediaType != nil {
		// Check if there is an expression after the media type.
		var tok = parser.peek()
		if tok.Type != ast.T_LOGICAL_AND {
			return ast.NewMediaQuery(mediaType, nil)
		}
		parser.advance() // skip the and operator token
	}

	// parse the media expression after the media type.
	var mediaExpr = parser.ParseMediaQueryExpr()
	if mediaExpr == nil {
		if mediaType == nil {
			return nil
		}
		return ast.NewMediaQuery(mediaType, mediaExpr)
	}

	// @media query only allows AND operator here..
	for tok := parser.accept(ast.T_LOGICAL_AND); tok != nil; tok = parser.accept(ast.T_LOGICAL_AND) {
		// parse another mediq query expression
		var expr2 = parser.ParseMediaQueryExpr()
		mediaExpr = ast.NewBinaryExpr(ast.NewOpWithToken(tok), mediaExpr, expr2, false)
	}
	return ast.NewMediaQuery(mediaType, mediaExpr)
}
Ejemplo n.º 3
0
func (parser *Parser) ParseLogicExpr() ast.Expr {
	debug("ParseLogicExpr")
	var expr = parser.ParseLogicANDExpr()
	for tok := parser.accept(ast.T_LOGICAL_OR); tok != nil; tok = parser.accept(ast.T_LOGICAL_OR) {
		if subexpr := parser.ParseLogicANDExpr(); subexpr != nil {
			expr = ast.NewBinaryExpr(ast.NewOpWithToken(tok), expr, subexpr, false)
		}
	}
	return expr
}
Ejemplo n.º 4
0
/*
The operator precedence is described here

@see http://introcs.cs.princeton.edu/java/11precedence/
*/
func (parser *Parser) ParseCondition() ast.Expr {
	debug("ParseCondition")

	// Boolean 'Not'
	if tok := parser.accept(ast.T_LOGICAL_NOT); tok != nil {
		var logicexpr = parser.ParseLogicExpr()
		return ast.NewUnaryExpr(ast.NewOpWithToken(tok), logicexpr)
	}
	return parser.ParseLogicExpr()
}
Ejemplo n.º 5
0
/*
ParseMediaType returns Ident Node or UnaryExpr as ast.Expr
*/
func (parser *Parser) ParseMediaType() *ast.MediaType {
	if tok := parser.acceptAnyOf2(ast.T_LOGICAL_NOT, ast.T_ONLY); tok != nil {
		var mediaType = parser.expect(ast.T_IDENT)
		return ast.NewMediaType(ast.NewUnaryExpr(ast.NewOpWithToken(tok), mediaType))
	}

	var tok = parser.peek()
	if tok.Type == ast.T_PAREN_OPEN {
		// the begining of the media expression
		return nil
	}

	var expr = parser.ParseExpr(false)
	if expr != nil {
		return ast.NewMediaType(expr)
	}

	// parse media type fail
	return nil
}
Ejemplo n.º 6
0
func (parser *Parser) ParseComparisonExpr() ast.Expr {
	debug("ParseComparisonExpr")

	var expr ast.Expr = nil
	if parser.accept(ast.T_PAREN_OPEN) != nil {
		expr = parser.ParseLogicExpr()
		parser.expect(ast.T_PAREN_CLOSE)
	} else {
		expr = parser.ParseExpr(false)
	}

	var tok = parser.peek()
	for tok != nil && tok.IsComparisonOperator() {
		parser.advance()
		if subexpr := parser.ParseExpr(false); subexpr != nil {
			expr = ast.NewBinaryExpr(ast.NewOpWithToken(tok), expr, subexpr, false)
		}
		tok = parser.peek()
	}
	return expr
}
Ejemplo n.º 7
0
func (parser *Parser) ParseTerm() ast.Expr {
	var pos = parser.Pos
	var factor = parser.ParseFactor()
	if factor == nil {
		parser.restore(pos)
		return nil
	}

	// see if the next token is '*' or '/'
	if tok := parser.acceptAnyOf2(ast.T_MUL, ast.T_DIV); tok != nil {
		if term := parser.ParseTerm(); term != nil {
			return ast.NewBinaryExpr(ast.NewOpWithToken(tok), factor, term, false)
		} else {
			panic(SyntaxError{
				Reason:      "Expecting term after '*' or '/'",
				ActualToken: parser.peek(),
				File:        parser.File,
			})
		}
	}
	return factor
}