package org.elixir_lang.beam;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static org.elixir_lang.psi.call.name.Function.DEF;
import static org.elixir_lang.psi.call.name.Function.DEFMACRO;
/**
* The macro ({@code def} or {@code defmacro}), name of the call definition and arity to define an export
*/
public class MacroNameArity implements Comparable<MacroNameArity> {
/*
* CONSTANTS
*/
private static final String MACRO_EXPORT_PREFIX = "MACRO-";
/*
* Fields
*/
/**
* {@code defmacro} if exportArity is prefixed with {@code MACRO-}; otherwise, {@code def}.
*/
@NotNull
public final String macro;
/**
* Elixir macros are defined as Erlang functions with names prefixed by {@code MACRO-}. That prefix is stripped
* from this name as it is the call definition name passed to {@code def} or {@code defmacro}.
*/
@NotNull
public final String name;
/**
* Elixir macros are defined as Erlang functions that take an extra Caller argument, so the exportArity is +1 for
* macros compared to this arity, which is the number of parameters to the call definition head passed to
* {@code defmacro}.
*/
@NotNull
public final Integer arity;
/*
* Constructors
*/
public MacroNameArity(@NotNull String exportName, int exportArity) {
if (exportName.startsWith(MACRO_EXPORT_PREFIX)) {
macro = DEFMACRO;
name = exportName.substring(MACRO_EXPORT_PREFIX.length());
arity = exportArity - 1;
} else {
macro = DEF;
name = exportName;
arity = exportArity;
}
}
/*
* Instance Methods
*/
@Override
public int compareTo(@NotNull MacroNameArity other) {
int comparison = compareMacroTo(other.macro);
if (comparison == 0) {
comparison = compareNameTo(other.name);
if (comparison == 0) {
comparison = compareArityTo(other.arity);
}
}
return comparison;
}
@Contract(pure = true)
private int compareArityTo(int otherArity) {
return Double.compare(arity, otherArity);
}
@Contract(pure = true)
private int compareMacroTo(@NotNull String otherMacro) {
int comparison;
if (macro.equals(DEFMACRO)) {
if (otherMacro.equals(DEFMACRO)) {
comparison = 0;
} else if (otherMacro.equals(DEF)) {
comparison = - 1;
} else {
throw new IllegalArgumentException("otherMacro must be \"" + DEFMACRO + "\" or \"" + DEF + "\"");
}
} else if (macro.equals(DEF)) {
if (otherMacro.equals(DEFMACRO)) {
comparison = 1;
} else if (otherMacro.equals(DEF)) {
comparison = 0;
} else {
throw new IllegalArgumentException("otherMacro must be \"" + DEFMACRO + "\" or \"" + DEF + "\"");
}
} else {
throw new IllegalArgumentException("macro must be \"" + DEFMACRO + "\" or \"" + DEF + "\"");
}
return comparison;
}
@Contract(pure = true)
private int compareNameTo(@NotNull String otherName) {
return name.compareTo(otherName);
}
}