package com.github.sommeri.less4j.core.compiler.expressions; import java.util.ArrayList; import java.util.List; import com.github.sommeri.less4j.core.ast.ASTCssNode; import com.github.sommeri.less4j.core.ast.ASTCssNodeType; import com.github.sommeri.less4j.core.ast.Expression; import com.github.sommeri.less4j.core.ast.KeywordExpression; import com.github.sommeri.less4j.core.ast.ListExpression; import com.github.sommeri.less4j.core.ast.ListExpressionOperator; import com.github.sommeri.less4j.utils.ArraysUtils; public class ExpressionManipulator { public Expression findRightmostListedExpression(Expression expression) { Expression result = expression; while (result!=null && result.getType() == ASTCssNodeType.LIST_EXPRESSION) { ListExpression parentList = (ListExpression) result; result = ArraysUtils.last(parentList.getExpressions()); } return result; } public ListExpression findRightmostSpaceSeparatedList(Expression expression) { if (expression==null) return null; ListExpression result = null; Expression rightmost = expression; while (rightmost.getType() == ASTCssNodeType.LIST_EXPRESSION) { ListExpression rightmostList = (ListExpression) rightmost; if (isSpaceSeparated(rightmostList)) result = rightmostList; rightmost = ArraysUtils.last(rightmostList.getExpressions()); } return result; } public boolean isSpaceSeparatedList(Expression expression) { if (expression.getType()!=ASTCssNodeType.LIST_EXPRESSION) { return false; } return isSpaceSeparated((ListExpression)expression); } public boolean isSpaceSeparated(ListExpression list) { return list.getOperator().getOperator()==ListExpressionOperator.Operator.EMPTY_OPERATOR; } public boolean isImportant(Expression expression) { if (expression==null) return false; Expression rightmost = findRightmostListedExpression(expression); if (rightmost==null || rightmost.getType() != ASTCssNodeType.IDENTIFIER_EXPRESSION) return false; if (!(rightmost instanceof KeywordExpression)) { return false; } KeywordExpression identifier = (KeywordExpression) rightmost; return identifier.isImportant(); } public Expression cutRightmostListedExpression(Expression expression) { Expression rightmost = findRightmostListedExpression(expression); ListExpression parent = (ListExpression) rightmost.getParent(); parent.removeExpression(rightmost); rightmost.setParent(null); return rightmost; } public void squashLists(Expression expression) { if (expression.getType()!=ASTCssNodeType.LIST_EXPRESSION) return ; ListExpression list = (ListExpression) expression; List<Expression> members = list.getExpressions(); for (Expression element : members) { squashLists(element); } ArrayList<Expression> membersCopy = new ArrayList<Expression>(members); for (Expression element : membersCopy) if (element.getType()==ASTCssNodeType.LIST_EXPRESSION) { ListExpression sublist = (ListExpression) element; if (sameListOperator(list, sublist)) { replaceInList(list, members, sublist, sublist.getExpressions()); } } } private void replaceInList(Expression parent, List<Expression> list, Expression oldChild, List<Expression> newChilds) { int childsIndex = list.indexOf(oldChild); list.remove(oldChild); list.addAll(childsIndex, newChilds); oldChild.setParent(null); for (Expression newKid : newChilds) { newKid.setParent(parent); } } private boolean sameListOperator(ListExpression list, ListExpression sublist) { return list.getOperator().getOperator()==sublist.getOperator().getOperator(); } //FIXME: should probably deep clone allArguments and setup parent child relationships public Expression joinAll(List<Expression> allArguments, ASTCssNode parent) { return new ListExpression(parent.getUnderlyingStructure(), allArguments, new ListExpressionOperator(parent.getUnderlyingStructure(), ListExpressionOperator.Operator.EMPTY_OPERATOR)); } }