package org.elixir_lang.lexer;
import com.intellij.psi.tree.IElementType;
import org.elixir_lang.lexer.group.Base;
import org.elixir_lang.lexer.group.Quote;
import org.elixir_lang.lexer.group.Sigil;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
/**
* Created by luke.imhoff on 8/19/14.
*/
public class StackFrame {
/*
* Static
*/
public static final Map<String, String> TERMINATOR_BY_PROMOTER = new HashMap<String, String>();
static {
TERMINATOR_BY_PROMOTER.put("'", "'");
TERMINATOR_BY_PROMOTER.put("'''", "'''");
TERMINATOR_BY_PROMOTER.put("(", ")");
TERMINATOR_BY_PROMOTER.put("/", "/");
TERMINATOR_BY_PROMOTER.put("<", ">");
TERMINATOR_BY_PROMOTER.put("[", "]");
TERMINATOR_BY_PROMOTER.put("\"", "\"");
TERMINATOR_BY_PROMOTER.put("\"\"\"", "\"\"\"");
TERMINATOR_BY_PROMOTER.put("{", "}");
TERMINATOR_BY_PROMOTER.put("|", "|");
}
/*
* Instance
*/
private Base group = null;
private Boolean interpolation = null;
private Integer lastLexicalState = null;
private String promoter = null;
private Character sigilName = null;
public StackFrame(int lastLexicalState) {
this.lastLexicalState = lastLexicalState;
}
public StackFrame(Quote group, String promoter, int lastLexicalState) {
this.group = group;
this.interpolation = true;
this.lastLexicalState = lastLexicalState;
this.promoter = promoter;
}
private Base getGroup() {
if (this.group == null) {
throw new IllegalStateException("Group not set.");
}
return this.group;
}
// private because Quote groups should be set from constructors and Sigil groups should be set from nameSigil
private void setGroup(Base group) {
if (this.group != null) {
throw new IllegalStateException(
"Group already set to " + this.group + ". " +
"It is illegal to set group more than once in any StackFrame."
);
}
this.group = group;
}
public void nameSigil(char sigilName) {
Sigil group = Sigil.fetch(sigilName);
setGroup(group);
setSigilName(sigilName);
setInterpolation(SigilName.isInterpolating(sigilName));
}
public void setQuotePromoter(String quotePromoter) {
setInterpolation(true);
this.group = Quote.fetch(quotePromoter);
}
private char getSigilName() {
if (sigilName == null) {
throw new IllegalStateException("SigilName is not set.");
}
return sigilName;
}
// setSigilName is private because public API is nameSigil, which in addition to setting interpolation and sigilName
// with setSigilName, also sets the group with setGroup.
private void setSigilName(char sigilName) {
if (this.sigilName != null) {
throw new IllegalStateException(
"SigilName already set to " + this.sigilName + ". " +
"It is illegal to set sigilName more than once in any StackFrame."
);
}
this.sigilName = sigilName;
}
private void setInterpolation(boolean interpolation) {
if (this.interpolation != null) {
throw new IllegalStateException(
"Parent already set to " + this.interpolation + ". " +
"It is illegal to set interpolation more than once in any StackFrame."
);
}
this.interpolation = interpolation;
}
public boolean isInterpolating() {
if (this.interpolation == null) {
throw new IllegalStateException("Parent not set.");
}
return this.interpolation.booleanValue();
}
public int getLastLexicalState() {
if (lastLexicalState == null) {
throw new IllegalStateException("LastLexicalState not set");
}
return lastLexicalState.intValue();
}
public void setLastLexicalState(int lastLexicalState) {
if (this.lastLexicalState != null) {
throw new IllegalStateException("LastLexicalState already set");
}
this.lastLexicalState = lastLexicalState;
}
public String getPromoter() {
if (promoter == null) {
throw new IllegalStateException("Promoter not set.");
}
return promoter;
}
public void setPromoter(@NotNull String promoter) {
if (this.promoter != null) {
throw new IllegalStateException(
"Promoter already set to " + this.promoter + ". " +
"It is illegal to set promoter more than once in any StackFrame."
);
}
this.promoter = promoter;
}
public IElementType promoterType() {
String promoter = getPromoter();
Base group = getGroup();
IElementType promoterType;
if (Base.isHeredocPromoter(promoter)) {
promoterType = group.heredocPromoterType;
} else {
promoterType = group.promoterType;
}
return promoterType;
}
public IElementType fragmentType() {
return getGroup().fragmentType;
}
public boolean isSigil() {
return getGroup() instanceof Sigil;
}
public IElementType sigilNameType() {
return SigilName.elementType(getSigilName());
}
public IElementType terminatorType() {
String promoter = getPromoter();
Base group = getGroup();
IElementType terminatorType;
if (Base.isHeredocPromoter(promoter)) {
terminatorType = group.heredocTerminatorType;
} else {
terminatorType = group.terminatorType;
}
return terminatorType;
}
public String getTerminator() {
String promoter = getPromoter();
String terminator = TERMINATOR_BY_PROMOTER.get(promoter);
// unregistered promoters are their own terminators
if (terminator == null) {
TERMINATOR_BY_PROMOTER.put(promoter, promoter);
terminator = promoter;
}
return terminator;
}
}