package org.smoothbuild.lang.function.def; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Strings.padEnd; import java.util.Collection; import org.smoothbuild.lang.expr.Expression; import org.smoothbuild.lang.message.CodeLocation; import org.smoothbuild.lang.type.Type; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Ordering; public class Argument { private final int number; private final String name; private final Expression expression; private final CodeLocation codeLocation; public static Argument namedArgument(int number, String name, Expression expression, CodeLocation codeLocation) { checkArgument(0 < number); return new Argument(number, checkNotNull(name), expression, codeLocation); } public static Argument namelessArgument(int number, Expression expression, CodeLocation codeLocation) { checkArgument(0 < number); return new Argument(number, null, expression, codeLocation); } public static Argument pipedArgument(Expression expression, CodeLocation codeLocation) { return new Argument(0, null, expression, codeLocation); } private Argument(int number, String name, Expression expression, CodeLocation codeLocation) { checkArgument(0 <= number); this.number = number; this.name = name; this.expression = checkNotNull(expression); this.codeLocation = checkNotNull(codeLocation); } /** * Number of position of this argument in function call's argument list. Value * zero denotes piped argument. Value one denotes first argument on the list. */ public int number() { return number; } public String name() { if (name == null) { throw new UnsupportedOperationException("Nameless argument does not have name."); } return name; } public String nameSanitized() { return name == null ? "<nameless>" : name; } public Type type() { return expression.type(); } public Expression expression() { return expression; } public CodeLocation codeLocation() { return codeLocation; } public boolean hasName() { return name != null; } public String toPaddedString(int minTypeLength, int minNameLength, int minNumberLength) { String type = padEnd(type().name(), minTypeLength, ' ') + ": "; String name = padEnd(nameSanitized(), minNameLength, ' '); String number = padEnd(numberString(), minNumberLength, ' '); String location = codeLocation.toString(); return type + name + " #" + number + " " + location; } private String numberString() { return number == 0 ? "|" : Integer.toString(number); } public String toString() { return type().name() + ":" + nameSanitized(); } public static ImmutableList<Argument> filterNamed(Collection<Argument> arguments) { ImmutableList.Builder<Argument> builder = ImmutableList.builder(); for (Argument argument : arguments) { if (argument.hasName()) { builder.add(argument); } } return builder.build(); } public static ImmutableMultimap<Type, Argument> filterNameless(Collection<Argument> arguments) { ImmutableMultimap.Builder<Type, Argument> builder = ImmutableMultimap.builder(); for (Argument argument : arguments) { if (!argument.hasName()) { Type type = argument.expression().type(); builder.put(type, argument); } } return builder.build(); } public static final Ordering<Argument> NUMBER_ORDERING = new Ordering<Argument>() { public int compare(Argument argument1, Argument argument2) { int number1 = argument1.number(); int number2 = argument2.number(); if (number1 == number2) { return 0; } if (number1 < number2) { return -1; } else { return 1; } } }; }