Change-Id: Ieb7834fb12cdba5c0794a26de20b3c8c2d509642tags/7.1.0.beta1
/* | |||||
* Copyright 2000-2013 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.sass.internal.expression; | |||||
import static com.vaadin.sass.internal.parser.SCSSLexicalUnit.SCSS_VARIABLE; | |||||
import java.util.Stack; | |||||
import com.vaadin.sass.internal.expression.exception.ArithmeticException; | |||||
import com.vaadin.sass.internal.parser.LexicalUnitImpl; | |||||
import com.vaadin.sass.internal.parser.SCSSLexicalUnit; | |||||
public class ArithmeticExpressionEvaluator { | |||||
private static ArithmeticExpressionEvaluator instance; | |||||
public static ArithmeticExpressionEvaluator get() { | |||||
if (instance == null) { | |||||
instance = new ArithmeticExpressionEvaluator(); | |||||
} | |||||
return instance; | |||||
} | |||||
private void createNewOperand(BinaryOperator operator, | |||||
Stack<Object> operands) { | |||||
Object rightOperand = operands.pop(); | |||||
operands.push(new BinaryExpression(operands.pop(), operator, | |||||
rightOperand)); | |||||
} | |||||
public boolean containsArithmeticalOperator(LexicalUnitImpl term) { | |||||
LexicalUnitImpl current = term; | |||||
while (current != null) { | |||||
for (BinaryOperator operator : BinaryOperator.values()) { | |||||
/* | |||||
* '/' is treated as an arithmetical operator when one of its | |||||
* operands is Variable, or there is another binary operator. | |||||
* Otherwise, '/' is treated as a CSS operator. | |||||
*/ | |||||
if (current.getLexicalUnitType() == operator.type) { | |||||
if (current.getLexicalUnitType() != BinaryOperator.DIV.type) { | |||||
return true; | |||||
} else { | |||||
if (current.getPreviousLexicalUnit() | |||||
.getLexicalUnitType() == SCSS_VARIABLE | |||||
|| current.getNextLexicalUnit() | |||||
.getLexicalUnitType() == SCSS_VARIABLE) { | |||||
return true; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
current = current.getNextLexicalUnit(); | |||||
} | |||||
return false; | |||||
} | |||||
private Object createExpression(LexicalUnitImpl term) { | |||||
LexicalUnitImpl current = term; | |||||
boolean afterOperand = false; | |||||
Stack<Object> operands = new Stack<Object>(); | |||||
Stack<Object> operators = new Stack<Object>(); | |||||
inputTermLoop: while (current != null) { | |||||
if (afterOperand) { | |||||
if (current.getLexicalUnitType() == SCSSLexicalUnit.SCSS_OPERATOR_RIGHT_PAREN) { | |||||
Object operator = null; | |||||
while (!operators.isEmpty() | |||||
&& ((operator = operators.pop()) != Parentheses.LEFT)) { | |||||
createNewOperand((BinaryOperator) operator, operands); | |||||
} | |||||
current = current.getNextLexicalUnit(); | |||||
continue; | |||||
} | |||||
afterOperand = false; | |||||
for (BinaryOperator operator : BinaryOperator.values()) { | |||||
if (current.getLexicalUnitType() == operator.type) { | |||||
while (!operators.isEmpty() | |||||
&& (operators.peek() != Parentheses.LEFT) | |||||
&& (((BinaryOperator) operators.peek()).precedence >= operator.precedence)) { | |||||
createNewOperand((BinaryOperator) operators.pop(), | |||||
operands); | |||||
} | |||||
operators.push(operator); | |||||
current = current.getNextLexicalUnit(); | |||||
continue inputTermLoop; | |||||
} | |||||
} | |||||
throw new ArithmeticException(); | |||||
} | |||||
if (current.getLexicalUnitType() == SCSSLexicalUnit.SCSS_OPERATOR_LEFT_PAREN) { | |||||
operators.push(Parentheses.LEFT); | |||||
current = current.getNextLexicalUnit(); | |||||
continue; | |||||
} | |||||
afterOperand = true; | |||||
operands.push(current); | |||||
current = current.getNextLexicalUnit(); | |||||
} | |||||
while (!operators.isEmpty()) { | |||||
Object operator = operators.pop(); | |||||
if (operator == Parentheses.LEFT) { | |||||
throw new ArithmeticException("Unexpected \"(\" found"); | |||||
} | |||||
createNewOperand((BinaryOperator) operator, operands); | |||||
} | |||||
Object expression = operands.pop(); | |||||
if (!operands.isEmpty()) { | |||||
LexicalUnitImpl operand = (LexicalUnitImpl) operands.peek(); | |||||
throw new ArithmeticException("Unexpected operand " | |||||
+ operand.toString() + " found"); | |||||
} | |||||
return expression; | |||||
} | |||||
public LexicalUnitImpl evaluate(LexicalUnitImpl term) { | |||||
Object result = ArithmeticExpressionEvaluator.get().createExpression( | |||||
term); | |||||
if (result instanceof BinaryExpression) { | |||||
return ((BinaryExpression) result).eval(); | |||||
} | |||||
return term; | |||||
} | |||||
} |
/* | |||||
* Copyright 2000-2013 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.sass.internal.expression; | |||||
import com.vaadin.sass.internal.parser.LexicalUnitImpl; | |||||
public class BinaryExpression { | |||||
public Object leftOperand = null; | |||||
public BinaryOperator operator = null; | |||||
public Object rightOperand = null; | |||||
public BinaryExpression(Object leftOperand, BinaryOperator operator, | |||||
Object rightOperand) { | |||||
this.leftOperand = leftOperand; | |||||
this.operator = operator; | |||||
this.rightOperand = rightOperand; | |||||
} | |||||
public LexicalUnitImpl eval() { | |||||
LexicalUnitImpl leftValue = (leftOperand instanceof BinaryExpression) ? ((BinaryExpression) leftOperand) | |||||
.eval() : (LexicalUnitImpl) leftOperand; | |||||
LexicalUnitImpl rightValue = (rightOperand instanceof BinaryExpression) ? ((BinaryExpression) rightOperand) | |||||
.eval() : (LexicalUnitImpl) rightOperand; | |||||
return operator.eval(leftValue, rightValue); | |||||
} | |||||
@Override | |||||
public String toString() { | |||||
return "(" + leftOperand + " " + operator.type + " " + rightOperand | |||||
+ ")"; | |||||
} | |||||
} |
/* | |||||
* Copyright 2000-2013 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.sass.internal.expression; | |||||
import org.w3c.css.sac.LexicalUnit; | |||||
import com.vaadin.sass.internal.parser.LexicalUnitImpl; | |||||
public enum BinaryOperator { | |||||
ADD(LexicalUnit.SAC_OPERATOR_PLUS, 1) { | |||||
@Override | |||||
public LexicalUnitImpl eval(LexicalUnitImpl leftValue, | |||||
LexicalUnitImpl rightValue) { | |||||
return leftValue.add(rightValue); | |||||
} | |||||
}, | |||||
MINUS(LexicalUnit.SAC_OPERATOR_MINUS, 1) { | |||||
@Override | |||||
public LexicalUnitImpl eval(LexicalUnitImpl leftValue, | |||||
LexicalUnitImpl rightValue) { | |||||
return leftValue.minus(rightValue); | |||||
} | |||||
}, | |||||
MUL(LexicalUnit.SAC_OPERATOR_MULTIPLY, 2) { | |||||
@Override | |||||
public LexicalUnitImpl eval(LexicalUnitImpl leftValue, | |||||
LexicalUnitImpl rightValue) { | |||||
return leftValue.multiply(rightValue); | |||||
} | |||||
}, | |||||
DIV(LexicalUnit.SAC_OPERATOR_SLASH, 2) { | |||||
@Override | |||||
public LexicalUnitImpl eval(LexicalUnitImpl leftValue, | |||||
LexicalUnitImpl rightValue) { | |||||
return leftValue.divide(rightValue); | |||||
} | |||||
}, | |||||
MOD(LexicalUnit.SAC_OPERATOR_MOD, 2) { | |||||
@Override | |||||
public LexicalUnitImpl eval(LexicalUnitImpl leftValue, | |||||
LexicalUnitImpl rightValue) { | |||||
return leftValue.modulo(rightValue); | |||||
} | |||||
}; | |||||
public final short type; | |||||
public final int precedence; | |||||
BinaryOperator(short type, int precedence) { | |||||
this.type = type; | |||||
this.precedence = precedence; | |||||
} | |||||
public abstract LexicalUnitImpl eval(LexicalUnitImpl leftValue, | |||||
LexicalUnitImpl rightValue); | |||||
} |
/* | |||||
* Copyright 2000-2013 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.sass.internal.expression; | |||||
public enum Parentheses { | |||||
LEFT, RIGHT | |||||
} |
/* | |||||
* Copyright 2000-2013 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.sass.internal.expression.exception; | |||||
public class ArithmeticException extends RuntimeException { | |||||
public ArithmeticException(String errorMsg) { | |||||
super(errorMsg); | |||||
} | |||||
public ArithmeticException() { | |||||
super("Illegal arithmetic expression"); | |||||
} | |||||
} |
/* | |||||
* Copyright 2000-2013 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.sass.internal.expression.exception; | |||||
public class IncompatibleUnitsException extends ArithmeticException { | |||||
public IncompatibleUnitsException(String errorExpr) { | |||||
super(getErrorMsg(errorExpr)); | |||||
} | |||||
private static String getErrorMsg(String errorExpr) { | |||||
StringBuilder builder = new StringBuilder(); | |||||
builder.append("Incompatible units found in: "); | |||||
builder.append("'").append(errorExpr).append("'"); | |||||
return builder.toString(); | |||||
} | |||||
} |
import org.w3c.css.sac.LexicalUnit; | import org.w3c.css.sac.LexicalUnit; | ||||
import com.vaadin.sass.internal.expression.exception.IncompatibleUnitsException; | |||||
import com.vaadin.sass.internal.util.ColorUtil; | import com.vaadin.sass.internal.util.ColorUtil; | ||||
import com.vaadin.sass.internal.util.DeepCopy; | import com.vaadin.sass.internal.util.DeepCopy; | ||||
LexicalUnitImpl(int line, int column, LexicalUnitImpl previous, int i) { | LexicalUnitImpl(int line, int column, LexicalUnitImpl previous, int i) { | ||||
this(SAC_INTEGER, line, column, previous); | this(SAC_INTEGER, line, column, previous); | ||||
this.i = i; | this.i = i; | ||||
f = i; | |||||
} | } | ||||
LexicalUnitImpl(int line, int column, LexicalUnitImpl previous, | LexicalUnitImpl(int line, int column, LexicalUnitImpl previous, | ||||
short dimension, String sdimension, float f) { | short dimension, String sdimension, float f) { | ||||
this(dimension, line, column, previous); | this(dimension, line, column, previous); | ||||
this.f = f; | this.f = f; | ||||
i = (int) f; | |||||
this.dimension = dimension; | this.dimension = dimension; | ||||
this.sdimension = sdimension; | this.sdimension = sdimension; | ||||
} | } | ||||
void setIntegerValue(int i) { | void setIntegerValue(int i) { | ||||
this.i = i; | this.i = i; | ||||
f = i; | |||||
} | } | ||||
@Override | @Override | ||||
public void setFloatValue(float f) { | public void setFloatValue(float f) { | ||||
this.f = f; | this.f = f; | ||||
i = (int) f; | |||||
} | } | ||||
@Override | @Override | ||||
@Override | @Override | ||||
public LexicalUnitImpl divide(LexicalUnitImpl denominator) { | public LexicalUnitImpl divide(LexicalUnitImpl denominator) { | ||||
setFloatValue(getFloatValue() / denominator.getIntegerValue()); | |||||
if (denominator.getLexicalUnitType() != SAC_INTEGER | |||||
&& denominator.getLexicalUnitType() != SAC_REAL | |||||
&& getLexicalUnitType() != denominator.getLexicalUnitType()) { | |||||
throw new IncompatibleUnitsException(toString()); | |||||
} | |||||
setFloatValue(getFloatValue() / denominator.getFloatValue()); | |||||
if (getLexicalUnitType() == denominator.getLexicalUnitType()) { | |||||
setLexicalUnitType(SAC_REAL); | |||||
} | |||||
setNextLexicalUnit(denominator.getNextLexicalUnit()); | |||||
return this; | return this; | ||||
} | } | ||||
@Override | @Override | ||||
public LexicalUnitImpl add(LexicalUnitImpl another) { | public LexicalUnitImpl add(LexicalUnitImpl another) { | ||||
checkAndSetUnit(another); | |||||
setFloatValue(getFloatValue() + another.getFloatValue()); | setFloatValue(getFloatValue() + another.getFloatValue()); | ||||
return this; | return this; | ||||
} | } | ||||
@Override | @Override | ||||
public LexicalUnitImpl minus(LexicalUnitImpl another) { | public LexicalUnitImpl minus(LexicalUnitImpl another) { | ||||
checkAndSetUnit(another); | |||||
setFloatValue(getFloatValue() - another.getFloatValue()); | setFloatValue(getFloatValue() - another.getFloatValue()); | ||||
return this; | return this; | ||||
} | } | ||||
@Override | @Override | ||||
public LexicalUnitImpl multiply(LexicalUnitImpl another) { | public LexicalUnitImpl multiply(LexicalUnitImpl another) { | ||||
checkAndSetUnit(another); | |||||
setFloatValue(getFloatValue() * another.getIntegerValue()); | setFloatValue(getFloatValue() * another.getIntegerValue()); | ||||
return this; | return this; | ||||
} | } | ||||
protected void checkAndSetUnit(LexicalUnitImpl another) { | |||||
if (getLexicalUnitType() != SAC_INTEGER | |||||
&& getLexicalUnitType() != SAC_REAL | |||||
&& another.getLexicalUnitType() != SAC_INTEGER | |||||
&& another.getLexicalUnitType() != SAC_REAL | |||||
&& getLexicalUnitType() != another.getLexicalUnitType()) { | |||||
throw new IncompatibleUnitsException(toString()); | |||||
} | |||||
if (another.getLexicalUnitType() != SAC_INTEGER | |||||
&& another.getLexicalUnitType() != SAC_REAL) { | |||||
setLexicalUnitType(another.getLexicalUnitType()); | |||||
} | |||||
setNextLexicalUnit(another.getNextLexicalUnit()); | |||||
} | |||||
@Override | |||||
public LexicalUnitImpl modulo(LexicalUnitImpl another) { | |||||
if (getLexicalUnitType() != another.getLexicalUnitType()) { | |||||
throw new IncompatibleUnitsException(toString()); | |||||
} | |||||
setIntegerValue(getIntegerValue() % another.getIntegerValue()); | |||||
setNextLexicalUnit(another.getNextLexicalUnit()); | |||||
return this; | |||||
} | |||||
public void replaceValue(LexicalUnitImpl another) { | public void replaceValue(LexicalUnitImpl another) { | ||||
// shouldn't modify 'another' directly, should only modify its copy. | // shouldn't modify 'another' directly, should only modify its copy. | ||||
LexicalUnitImpl deepCopyAnother = (LexicalUnitImpl) DeepCopy | LexicalUnitImpl deepCopyAnother = (LexicalUnitImpl) DeepCopy | ||||
return new LexicalUnitImpl(line, column, previous, SAC_EX, null, v); | return new LexicalUnitImpl(line, column, previous, SAC_EX, null, v); | ||||
} | } | ||||
public static LexicalUnitImpl createPixel(float p) { | |||||
return new LexicalUnitImpl(0, 0, null, SAC_PIXEL, null, p); | |||||
} | |||||
static LexicalUnitImpl createPX(int line, int column, | |||||
public static LexicalUnitImpl createPX(int line, int column, | |||||
LexicalUnitImpl previous, float v) { | LexicalUnitImpl previous, float v) { | ||||
return new LexicalUnitImpl(line, column, previous, SAC_PIXEL, null, v); | return new LexicalUnitImpl(line, column, previous, SAC_PIXEL, null, v); | ||||
} | } | ||||
static LexicalUnitImpl createCM(int line, int column, | |||||
public static LexicalUnitImpl createCM(int line, int column, | |||||
LexicalUnitImpl previous, float v) { | LexicalUnitImpl previous, float v) { | ||||
return new LexicalUnitImpl(line, column, previous, SAC_CENTIMETER, | return new LexicalUnitImpl(line, column, previous, SAC_CENTIMETER, | ||||
null, v); | null, v); | ||||
return new LexicalUnitImpl(SAC_OPERATOR_SLASH, line, column, previous); | return new LexicalUnitImpl(SAC_OPERATOR_SLASH, line, column, previous); | ||||
} | } | ||||
public static LexicalUnitImpl createAdd(int line, int column, | |||||
LexicalUnitImpl previous) { | |||||
return new LexicalUnitImpl(SAC_OPERATOR_PLUS, line, column, previous); | |||||
} | |||||
public static LexicalUnitImpl createMinus(int line, int column, | |||||
LexicalUnitImpl previous) { | |||||
return new LexicalUnitImpl(SAC_OPERATOR_MINUS, line, column, previous); | |||||
} | |||||
public static LexicalUnitImpl createMultiply(int line, int column, | |||||
LexicalUnitImpl previous) { | |||||
return new LexicalUnitImpl(SAC_OPERATOR_MULTIPLY, line, column, | |||||
previous); | |||||
} | |||||
public static LexicalUnitImpl createModulo(int line, int column, | |||||
LexicalUnitImpl previous) { | |||||
return new LexicalUnitImpl(SAC_OPERATOR_MOD, line, column, previous); | |||||
} | |||||
public static LexicalUnitImpl createLeftParenthesis(int line, int column, | |||||
LexicalUnitImpl previous) { | |||||
return new LexicalUnitImpl(SCSS_OPERATOR_LEFT_PAREN, line, column, | |||||
previous); | |||||
} | |||||
public static LexicalUnitImpl createRightParenthesis(int line, int column, | |||||
LexicalUnitImpl previous) { | |||||
return new LexicalUnitImpl(SCSS_OPERATOR_LEFT_PAREN, line, column, | |||||
previous); | |||||
} | |||||
@Override | @Override | ||||
public LexicalUnitImpl clone() { | public LexicalUnitImpl clone() { | ||||
LexicalUnitImpl cloned = new LexicalUnitImpl(type, line, column, prev); | LexicalUnitImpl cloned = new LexicalUnitImpl(type, line, column, prev); |
| < LBRACKET : "[" > | | < LBRACKET : "[" > | ||||
| < RBRACKET : "]" > | | < RBRACKET : "]" > | ||||
| < ANY : "*" > | | < ANY : "*" > | ||||
| < MOD : "%" > | |||||
| < PARENT : "&" > | | < PARENT : "&" > | ||||
| < DOT : "." > | | < DOT : "." > | ||||
| < LPARAN : "(" > | | < LPARAN : "(" > | ||||
LexicalUnitImpl operator(LexicalUnitImpl prev) : | LexicalUnitImpl operator(LexicalUnitImpl prev) : | ||||
{Token n;} | {Token n;} | ||||
{ | { | ||||
n="/" ( <S> )* { return LexicalUnitImpl.createSlash(n.beginLine, | |||||
n.beginColumn, | |||||
prev); } | |||||
| n="," ( <S> )* { return LexicalUnitImpl.createComma(n.beginLine, | |||||
n.beginColumn, | |||||
prev); } | |||||
/* (comments copied from basic_arithmetics.scss) | |||||
*supports: | |||||
* 1. standard arithmetic operations (+, -, *, /, %) | |||||
* 2. / is treated as css operator, unless one of its operands is variable or there is another binary arithmetic operator | |||||
*limits: | |||||
* 1. cannot mix arithmetic and css operations, e.g. "margin: 1px + 3px 2px" will fail | |||||
* 2. space between add and minus operator and their following operand is mandatory. e.g. "1 + 2" is valid, "1+2" is not | |||||
* 3. parenthesis is not supported now. | |||||
*/ | |||||
n="," ( <S> )* { return LexicalUnitImpl.createComma(n.beginLine, | |||||
n.beginColumn, | |||||
prev); } | |||||
|n="/" ( <S> )* { return LexicalUnitImpl.createSlash(n.beginLine, | |||||
n.beginColumn, | |||||
prev); } | |||||
| n="*" ( <S> )* { return LexicalUnitImpl.createMultiply(n.beginLine, | |||||
n.beginColumn, | |||||
prev); } | |||||
| n="%" ( <S> )* { return LexicalUnitImpl.createModulo(n.beginLine, | |||||
n.beginColumn, | |||||
prev); } | |||||
/* | |||||
* for '+', since it can be either a binary operator or an unary operator, | |||||
* which is ambiguous. To avoid this, the binary operator '+' always has | |||||
* a space before the following term. so '2+3' is not a valid binary expression, | |||||
* but '2 + 3' is. The same for '-' operator. | |||||
*/ | |||||
| n="+" ( <S> )+{ return LexicalUnitImpl.createAdd(n.beginLine, | |||||
n.beginColumn, | |||||
prev); } | |||||
| n="-" ( <S> )+{ return LexicalUnitImpl.createMinus(n.beginLine, | |||||
n.beginColumn, | |||||
prev); } | |||||
} | } | ||||
/** | /** | ||||
} | } | ||||
{ | { | ||||
first=term(null){ res = first; } | first=term(null){ res = first; } | ||||
( LOOKAHEAD(2) ( res=operator(res) )? res=term(res))* | |||||
( LOOKAHEAD(2) ( LOOKAHEAD(2) res=operator(res) )? res=term(res))* | |||||
{ return first; } | { return first; } | ||||
} | } | ||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int ANY = 30; | int ANY = 30; | ||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int PARENT = 31; | |||||
int MOD = 31; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int DOT = 32; | |||||
int PARENT = 32; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int LPARAN = 33; | |||||
int DOT = 33; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RPARAN = 34; | |||||
int LPARAN = 34; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int COMPARE = 35; | |||||
int RPARAN = 35; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int OR = 36; | |||||
int COMPARE = 36; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int AND = 37; | |||||
int OR = 37; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int NOT_EQ = 38; | |||||
int AND = 38; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int COLON = 39; | |||||
int NOT_EQ = 39; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int INTERPOLATION = 40; | |||||
int COLON = 40; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int NONASCII = 41; | |||||
int INTERPOLATION = 41; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int H = 42; | |||||
int NONASCII = 42; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int UNICODE = 43; | |||||
int H = 43; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int ESCAPE = 44; | |||||
int UNICODE = 44; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int NMSTART = 45; | |||||
int ESCAPE = 45; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int NMCHAR = 46; | |||||
int NMSTART = 46; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int STRINGCHAR = 47; | |||||
int NMCHAR = 47; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int D = 48; | |||||
int STRINGCHAR = 48; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int NAME = 49; | |||||
int D = 49; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int TO = 50; | |||||
int NAME = 50; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int THROUGH = 51; | |||||
int TO = 51; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int EACH_IN = 52; | |||||
int THROUGH = 52; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int FROM = 53; | |||||
int EACH_IN = 53; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int MIXIN_SYM = 54; | |||||
int FROM = 54; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int INCLUDE_SYM = 55; | |||||
int MIXIN_SYM = 55; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int FUNCTION_SYM = 56; | |||||
int INCLUDE_SYM = 56; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RETURN_SYM = 57; | |||||
int FUNCTION_SYM = 57; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int DEBUG_SYM = 58; | |||||
int RETURN_SYM = 58; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int WARN_SYM = 59; | |||||
int DEBUG_SYM = 59; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int FOR_SYM = 60; | |||||
int WARN_SYM = 60; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int EACH_SYM = 61; | |||||
int FOR_SYM = 61; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int WHILE_SYM = 62; | |||||
int EACH_SYM = 62; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int IF_SYM = 63; | |||||
int WHILE_SYM = 63; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int ELSE_SYM = 64; | |||||
int IF_SYM = 64; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int EXTEND_SYM = 65; | |||||
int ELSE_SYM = 65; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int MOZ_DOCUMENT_SYM = 66; | |||||
int EXTEND_SYM = 66; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int SUPPORTS_SYM = 67; | |||||
int MOZ_DOCUMENT_SYM = 67; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int MICROSOFT_RULE = 68; | |||||
int SUPPORTS_SYM = 68; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int IF = 69; | |||||
int MICROSOFT_RULE = 69; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int GUARDED_SYM = 70; | |||||
int IF = 70; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int STRING = 71; | |||||
int GUARDED_SYM = 71; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int IDENT = 72; | |||||
int STRING = 72; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int NUMBER = 73; | |||||
int IDENT = 73; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int _URL = 74; | |||||
int NUMBER = 74; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int URL = 75; | |||||
int _URL = 75; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int VARIABLE = 76; | |||||
int URL = 76; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int PERCENTAGE = 77; | |||||
int VARIABLE = 77; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int PT = 78; | |||||
int PERCENTAGE = 78; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int MM = 79; | |||||
int PT = 79; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int CM = 80; | |||||
int MM = 80; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int PC = 81; | |||||
int CM = 81; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int IN = 82; | |||||
int PC = 82; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int PX = 83; | |||||
int IN = 83; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int EMS = 84; | |||||
int PX = 84; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int LEM = 85; | |||||
int EMS = 85; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int REM = 86; | |||||
int LEM = 86; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int EXS = 87; | |||||
int REM = 87; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int DEG = 88; | |||||
int EXS = 88; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RAD = 89; | |||||
int DEG = 89; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int GRAD = 90; | |||||
int RAD = 90; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int MS = 91; | |||||
int GRAD = 91; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int SECOND = 92; | |||||
int MS = 92; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int HZ = 93; | |||||
int SECOND = 93; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int KHZ = 94; | |||||
int HZ = 94; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int DIMEN = 95; | |||||
int KHZ = 95; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int HASH = 96; | |||||
int DIMEN = 96; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int IMPORT_SYM = 97; | |||||
int HASH = 97; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int MEDIA_SYM = 98; | |||||
int IMPORT_SYM = 98; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int CHARSET_SYM = 99; | |||||
int MEDIA_SYM = 99; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int PAGE_SYM = 100; | |||||
int CHARSET_SYM = 100; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int FONT_FACE_SYM = 101; | |||||
int PAGE_SYM = 101; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int KEY_FRAME_SYM = 102; | |||||
int FONT_FACE_SYM = 102; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int ATKEYWORD = 103; | |||||
int KEY_FRAME_SYM = 103; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int IMPORTANT_SYM = 104; | |||||
int ATKEYWORD = 104; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RANGE0 = 105; | |||||
int IMPORTANT_SYM = 105; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RANGE1 = 106; | |||||
int RANGE0 = 106; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RANGE2 = 107; | |||||
int RANGE1 = 107; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RANGE3 = 108; | |||||
int RANGE2 = 108; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RANGE4 = 109; | |||||
int RANGE3 = 109; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RANGE5 = 110; | |||||
int RANGE4 = 110; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RANGE6 = 111; | |||||
int RANGE5 = 111; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int RANGE = 112; | |||||
int RANGE6 = 112; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int UNI = 113; | |||||
int RANGE = 113; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int UNICODERANGE = 114; | |||||
int UNI = 114; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int REMOVE = 115; | |||||
int UNICODERANGE = 115; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int APPEND = 116; | |||||
int REMOVE = 116; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int CONTAINS = 117; | |||||
int APPEND = 117; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int FUNCTION = 118; | |||||
int CONTAINS = 118; | |||||
/** RegularExpression Id. */ | /** RegularExpression Id. */ | ||||
int UNKNOWN = 119; | |||||
int FUNCTION = 119; | |||||
/** RegularExpression Id. */ | |||||
int UNKNOWN = 120; | |||||
/** Lexical state. */ | /** Lexical state. */ | ||||
int DEFAULT = 0; | int DEFAULT = 0; | ||||
"\"*/\"", "<token of kind 9>", "\"<!--\"", "\"-->\"", "\"{\"", | "\"*/\"", "<token of kind 9>", "\"<!--\"", "\"-->\"", "\"{\"", | ||||
"\"}\"", "\"|=\"", "\"^=\"", "\"$=\"", "\"*=\"", "\"~=\"", "\"=\"", | "\"}\"", "\"|=\"", "\"^=\"", "\"$=\"", "\"*=\"", "\"~=\"", "\"=\"", | ||||
"\"+\"", "\"-\"", "\",\"", "\";\"", "\">\"", "\"~\"", "\"<\"", | "\"+\"", "\"-\"", "\",\"", "\";\"", "\">\"", "\"~\"", "\"<\"", | ||||
"\"/\"", "\"[\"", "\"]\"", "\"*\"", "\"&\"", "\".\"", "\"(\"", | |||||
"\")\"", "\"==\"", "\"||\"", "\"&&\"", "\"!=\"", "\":\"", | |||||
"\"/\"", "\"[\"", "\"]\"", "\"*\"", "\"%\"", "\"&\"", "\".\"", | |||||
"\"(\"", "\")\"", "\"==\"", "\"||\"", "\"&&\"", "\"!=\"", "\":\"", | |||||
"<INTERPOLATION>", "<NONASCII>", "<H>", "<UNICODE>", "<ESCAPE>", | "<INTERPOLATION>", "<NONASCII>", "<H>", "<UNICODE>", "<ESCAPE>", | ||||
"<NMSTART>", "<NMCHAR>", "<STRINGCHAR>", "<D>", "<NAME>", "\"to\"", | "<NMSTART>", "<NMCHAR>", "<STRINGCHAR>", "<D>", "<NAME>", "\"to\"", | ||||
"\"through\"", "\"in\"", "\"from\"", "\"@mixin\"", "\"@include\"", | "\"through\"", "\"in\"", "\"from\"", "\"@mixin\"", "\"@include\"", |
public interface SCSSLexicalUnit extends LexicalUnit { | public interface SCSSLexicalUnit extends LexicalUnit { | ||||
static final short SCSS_VARIABLE = 100; | static final short SCSS_VARIABLE = 100; | ||||
static final short SCSS_OPERATOR_LEFT_PAREN = 101; | |||||
static final short SCSS_OPERATOR_RIGHT_PAREN = 102; | |||||
static final short SAC_LEM = 200; | static final short SAC_LEM = 200; | ||||
static final short SAC_REM = 201; | static final short SAC_REM = 201; | ||||
LexicalUnitImpl multiply(LexicalUnitImpl another); | LexicalUnitImpl multiply(LexicalUnitImpl another); | ||||
LexicalUnitImpl modulo(LexicalUnitImpl another); | |||||
} | } |
import java.util.regex.Pattern; | import java.util.regex.Pattern; | ||||
import com.vaadin.sass.internal.ScssStylesheet; | import com.vaadin.sass.internal.ScssStylesheet; | ||||
import com.vaadin.sass.internal.expression.ArithmeticExpressionEvaluator; | |||||
import com.vaadin.sass.internal.parser.LexicalUnitImpl; | import com.vaadin.sass.internal.parser.LexicalUnitImpl; | ||||
import com.vaadin.sass.internal.util.StringUtil; | import com.vaadin.sass.internal.util.StringUtil; | ||||
@Override | @Override | ||||
public void traverse() { | public void traverse() { | ||||
replaceVariables(ScssStylesheet.getVariables()); | |||||
/* | |||||
* "replaceVariables(ScssStylesheet.getVariables());" seems duplicated | |||||
* and can be extracted out of if, but it is not. | |||||
* containsArithmeticalOperator must be called before replaceVariables. | |||||
* Because for the "/" operator, it needs to see if its predecessor or | |||||
* successor is a Variable or not, to determine it is an arithmetic | |||||
* operator. | |||||
*/ | |||||
if (ArithmeticExpressionEvaluator.get().containsArithmeticalOperator( | |||||
value)) { | |||||
replaceVariables(ScssStylesheet.getVariables()); | |||||
value = ArithmeticExpressionEvaluator.get().evaluate(value); | |||||
} else { | |||||
replaceVariables(ScssStylesheet.getVariables()); | |||||
} | |||||
} | } | ||||
} | } |
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import com.vaadin.sass.internal.ScssStylesheet; | import com.vaadin.sass.internal.ScssStylesheet; | ||||
import com.vaadin.sass.internal.expression.ArithmeticExpressionEvaluator; | |||||
import com.vaadin.sass.internal.parser.LexicalUnitImpl; | import com.vaadin.sass.internal.parser.LexicalUnitImpl; | ||||
import com.vaadin.sass.internal.util.StringUtil; | import com.vaadin.sass.internal.util.StringUtil; | ||||
import com.vaadin.sass.internal.visitor.VariableNodeHandler; | import com.vaadin.sass.internal.visitor.VariableNodeHandler; | ||||
@Override | @Override | ||||
public void traverse() { | public void traverse() { | ||||
replaceVariables(ScssStylesheet.getVariables()); | |||||
/* | |||||
* "replaceVariables(ScssStylesheet.getVariables());" seems duplicated | |||||
* and can be extracted out of if, but it is not. | |||||
* containsArithmeticalOperator must be called before replaceVariables. | |||||
* Because for the "/" operator, it needs to see if its predecessor or | |||||
* successor is a Variable or not, to determine it is an arithmetic | |||||
* operator. | |||||
*/ | |||||
if (ArithmeticExpressionEvaluator.get().containsArithmeticalOperator( | |||||
expr)) { | |||||
replaceVariables(ScssStylesheet.getVariables()); | |||||
expr = ArithmeticExpressionEvaluator.get().evaluate(expr); | |||||
} else { | |||||
replaceVariables(ScssStylesheet.getVariables()); | |||||
} | |||||
VariableNodeHandler.traverse(this); | VariableNodeHandler.traverse(this); | ||||
} | } | ||||
} | } |
.foo { | |||||
font: 10px / 8px; | |||||
font: 5px; | |||||
margin-left: 9px; | |||||
} | |||||
.foo { | |||||
size: 1; | |||||
} | |||||
.foo { | |||||
bar: 8; | |||||
bar: 8; | |||||
bar: 12; | |||||
} | |||||
.foo { | |||||
bar: 2 3; | |||||
bar: 5; | |||||
bar: 5; | |||||
} | |||||
.foo { | |||||
bar: 2 -3; | |||||
bar: -1; | |||||
bar: -1; | |||||
} | |||||
.foo { | |||||
bar: 14; | |||||
} |
/* | |||||
*supports: | |||||
* 1. standard arithmetic operations (+, -, *, /, %) | |||||
* 2. / is treated as css operator, unless one of its operands is variable or there is another binary arithmetic operator | |||||
*limits: | |||||
* 1. cannot mix arithmetic and css operations, e.g. "margin: 1px + 3px 2px" will fail | |||||
* 2. space between add and minus operator and their following operand is mandatory. e.g. "1 + 2" is valid, "1+2" is not | |||||
* 3. parenthesis is not supported now. | |||||
*/ | |||||
$div: 10px; | |||||
.foo { | |||||
font: 10px/8px; // Plain CSS, no division | |||||
font: $div/2; // Uses a variable, does division | |||||
margin-left: 5px + 8px/2px; //Uses +, does division | |||||
} | |||||
.foo{ | |||||
size: 5 % 2; // modular | |||||
} | |||||
$mul: 2*4; //valid multiply in variable | |||||
$mul1: 2 * 4; //valid multiply in variable | |||||
.foo{ | |||||
bar: $mul; | |||||
bar: $mul1; | |||||
bar: 3*4; //valid multiply in declaration | |||||
} | |||||
.foo { | |||||
bar: 2 +3; //'+' is regarded as an unary operator, because no space between '+' and '3' | |||||
bar: 2+ 3; //valid add expression | |||||
bar: 2 + 3; //beautiful valid add expression | |||||
} | |||||
.foo { | |||||
bar: 2 -3; //'-' is regarded as an unary operator, because no space between '-' and '3' | |||||
bar: 2 - 3; //beautiful valid minus expression | |||||
bar: 2- 3; //valid minus expression | |||||
} | |||||
.foo { | |||||
bar: 2 + 3 * 4; // combinations | |||||
} |
/* | |||||
* Copyright 2000-2013 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.sass.internal.expression; | |||||
import org.junit.Assert; | |||||
import org.junit.Test; | |||||
import org.w3c.css.sac.LexicalUnit; | |||||
import com.vaadin.sass.internal.expression.exception.IncompatibleUnitsException; | |||||
import com.vaadin.sass.internal.parser.LexicalUnitImpl; | |||||
public class ArithmeticExpressionEvaluatorTest { | |||||
private ArithmeticExpressionEvaluator evaluator = new ArithmeticExpressionEvaluator(); | |||||
@Test | |||||
public void testPrecedenceSameAsAppearOrder() { | |||||
// 2 * 3 - 4 = 2 | |||||
LexicalUnitImpl operand2 = LexicalUnitImpl.createInteger(0, 0, null, 2); | |||||
LexicalUnitImpl operatorMultiply = LexicalUnitImpl.createMultiply(0, 0, | |||||
operand2); | |||||
LexicalUnitImpl operand3 = LexicalUnitImpl.createInteger(0, 0, | |||||
operatorMultiply, 3); | |||||
LexicalUnitImpl operatorMinus = LexicalUnitImpl.createMinus(0, 0, | |||||
operand3); | |||||
LexicalUnitImpl operand4 = LexicalUnitImpl.createInteger(0, 0, | |||||
operatorMinus, 4); | |||||
LexicalUnitImpl result = evaluator.evaluate(operand2); | |||||
Assert.assertEquals(2, result.getIntegerValue()); | |||||
} | |||||
@Test | |||||
public void testPrecedenceDifferFromAppearOrder() { | |||||
// 2 - 3 * 4 = -10 | |||||
LexicalUnitImpl operand2 = LexicalUnitImpl.createInteger(0, 0, null, 2); | |||||
LexicalUnitImpl operatorMinus = LexicalUnitImpl.createMinus(0, 0, | |||||
operand2); | |||||
LexicalUnitImpl operand3 = LexicalUnitImpl.createInteger(0, 0, | |||||
operatorMinus, 3); | |||||
LexicalUnitImpl operatorMultiply = LexicalUnitImpl.createMultiply(0, 0, | |||||
operand3); | |||||
LexicalUnitImpl operand4 = LexicalUnitImpl.createInteger(0, 0, | |||||
operatorMultiply, 4); | |||||
LexicalUnitImpl result = evaluator.evaluate(operand2); | |||||
Assert.assertEquals(-10, result.getIntegerValue()); | |||||
} | |||||
@Test(expected = IncompatibleUnitsException.class) | |||||
public void testIncompatibleUnit() { | |||||
// 2cm - 3px | |||||
LexicalUnitImpl operand2 = LexicalUnitImpl.createCM(0, 0, null, 2); | |||||
LexicalUnitImpl operatorMinus = LexicalUnitImpl.createMinus(0, 0, | |||||
operand2); | |||||
LexicalUnitImpl operand3 = LexicalUnitImpl.createPX(0, 0, | |||||
operatorMinus, 3); | |||||
evaluator.evaluate(operand2); | |||||
} | |||||
@Test | |||||
public void testMultiplyWithUnitInfirstOperand() { | |||||
// 2cm * 3 = 6cm | |||||
LexicalUnitImpl operand2cm = LexicalUnitImpl.createCM(0, 0, null, 2); | |||||
LexicalUnitImpl operatorMultiply = LexicalUnitImpl.createMultiply(0, 0, | |||||
operand2cm); | |||||
LexicalUnitImpl operand3 = LexicalUnitImpl.createInteger(0, 0, | |||||
operatorMultiply, 3); | |||||
LexicalUnitImpl result = evaluator.evaluate(operand2cm); | |||||
Assert.assertEquals(6, result.getIntegerValue()); | |||||
Assert.assertEquals(LexicalUnit.SAC_CENTIMETER, | |||||
result.getLexicalUnitType()); | |||||
} | |||||
@Test | |||||
public void testMultiplyWithUnitInSecondOperand() { | |||||
// 2 * 3cm = 6cm | |||||
LexicalUnitImpl operand2 = LexicalUnitImpl.createInteger(0, 0, null, 2); | |||||
LexicalUnitImpl operatorMultiply = LexicalUnitImpl.createMultiply(0, 0, | |||||
operand2); | |||||
LexicalUnitImpl operand3cm = LexicalUnitImpl.createCM(0, 0, | |||||
operatorMultiply, 3); | |||||
LexicalUnitImpl result = evaluator.evaluate(operand2); | |||||
Assert.assertEquals(6, result.getIntegerValue()); | |||||
Assert.assertEquals(LexicalUnit.SAC_CENTIMETER, | |||||
result.getLexicalUnitType()); | |||||
} | |||||
@Test | |||||
public void testDivideWithSameUnit() { | |||||
// 4cm / 2cm = 2 | |||||
LexicalUnitImpl operand4cm = LexicalUnitImpl.createCM(0, 0, null, 4); | |||||
LexicalUnitImpl operatorDivide = LexicalUnitImpl.createSlash(0, 0, | |||||
operand4cm); | |||||
LexicalUnitImpl operand2cm = LexicalUnitImpl.createCM(0, 0, | |||||
operatorDivide, 2); | |||||
LexicalUnitImpl result = evaluator.evaluate(operand4cm); | |||||
Assert.assertEquals(2, result.getIntegerValue()); | |||||
Assert.assertEquals(LexicalUnit.SAC_REAL, result.getLexicalUnitType()); | |||||
} | |||||
@Test | |||||
public void testDivideDenominatorWithoutUnit() { | |||||
// 4cm / 2 = 2cm | |||||
LexicalUnitImpl operand4cm = LexicalUnitImpl.createCM(0, 0, null, 4); | |||||
LexicalUnitImpl operatorDivide = LexicalUnitImpl.createSlash(0, 0, | |||||
operand4cm); | |||||
LexicalUnitImpl operand2 = LexicalUnitImpl.createInteger(0, 0, | |||||
operatorDivide, 2); | |||||
LexicalUnitImpl result = evaluator.evaluate(operand4cm); | |||||
Assert.assertEquals(2, result.getIntegerValue()); | |||||
Assert.assertEquals(LexicalUnit.SAC_CENTIMETER, | |||||
result.getLexicalUnitType()); | |||||
} | |||||
} |