package com.github.sommeri.less4j.core.compiler.stages;
import java.util.ArrayList;
import java.util.Iterator;
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.ArgumentDeclaration;
import com.github.sommeri.less4j.core.ast.Expression;
import com.github.sommeri.less4j.core.ast.MixinReference;
import com.github.sommeri.less4j.core.ast.ReusableStructure;
import com.github.sommeri.less4j.core.compiler.expressions.ExpressionManipulator;
import com.github.sommeri.less4j.core.compiler.scopes.IScope;
import com.github.sommeri.less4j.core.compiler.scopes.ScopeFactory;
import com.github.sommeri.less4j.core.problems.ProblemsHandler;
import com.github.sommeri.less4j.utils.ArraysUtils;
class ArgumentsBuilder {
// utils
private final ProblemsHandler problemsHandler;
private final ExpressionManipulator expressionManipulator = new ExpressionManipulator();
private final String ALL_ARGUMENTS = ReferencesSolver.ALL_ARGUMENTS;
// input
private Iterator<Expression> positionalParameters;
private ReusableStructure mixin;
private EvaluatedMixinReferenceCall evaluatedReference;
private MixinReference reference;
// results
private List<Expression> allValues = new ArrayList<Expression>();
private IScope argumentsScope;
public ArgumentsBuilder(EvaluatedMixinReferenceCall evaluatedReference, ReusableStructure pureMixin, ProblemsHandler problemsHandler) {
super();
this.problemsHandler = problemsHandler;
this.positionalParameters = evaluatedReference.getPositionalParameters().iterator();
this.evaluatedReference = evaluatedReference;
this.reference = evaluatedReference.getReference();
this.argumentsScope = ScopeFactory.createDummyScope(reference, "#arguments-" + reference + "#");
this.mixin = pureMixin;
}
public IScope build() {
int length = mixin.getParameters().size();
for (int i = 0; i < length; i++) {
ASTCssNode parameter = mixin.getParameters().get(i);
if (parameter.getType() == ASTCssNodeType.ARGUMENT_DECLARATION) {
add((ArgumentDeclaration) parameter);
} else {
skipPositionalParameter();
}
}
Expression allArgumentsValue = expressionManipulator.joinAll(allValues, reference);
argumentsScope.registerVariableIfNotPresent(ALL_ARGUMENTS, allArgumentsValue);
return argumentsScope;
}
private void skipPositionalParameter() {
positionalParameters.next();
}
private void add(ArgumentDeclaration declaration) {
if (canFillFromNamed(declaration)) {
fillFromNamed(declaration);
} else if (declaration.isCollector()) {
addAsCollector(declaration);
} else if (canFillFromPositional()) {
fillFromPositional(declaration);
} else if (hasDefault(declaration)) {
fillFromDefault(declaration);
} else {
if (declaration.getValue() == null)
problemsHandler.undefinedMixinParameterValue(mixin, declaration, reference);
}
}
private void fillFromNamed(ArgumentDeclaration declaration) {
Expression value = evaluatedReference.getNamedParameter(declaration.getVariable());
allValues.add(value);
argumentsScope.registerVariable(declaration, value);
}
private boolean canFillFromNamed(ArgumentDeclaration declaration) {
return evaluatedReference.hasNamedParameter(declaration.getVariable());
}
private void fillFromDefault(ArgumentDeclaration declaration) {
allValues.add(declaration.getValue());
argumentsScope.registerVariable(declaration);
}
private boolean hasDefault(ArgumentDeclaration declaration) {
return declaration.getValue() != null;
}
private void fillFromPositional(ArgumentDeclaration declaration) {
Expression value = positionalParameters.next();
allValues.add(value);
argumentsScope.registerVariable(declaration, value);
}
private boolean canFillFromPositional() {
return positionalParameters.hasNext();
}
private void addAsCollector(ArgumentDeclaration declaration) {
List<Expression> allArgumentsFrom = ArraysUtils.remaining(positionalParameters);
allValues.addAll(allArgumentsFrom);
Expression value = expressionManipulator.joinAll(allArgumentsFrom, reference);
argumentsScope.registerVariable(declaration, value);
}
}