package org.develnext.jphp.core.syntax; import org.develnext.jphp.core.tokenizer.token.Token; import org.develnext.jphp.core.tokenizer.token.expr.value.VariableExprToken; import org.develnext.jphp.core.tokenizer.token.stmt.LabelStmtToken; import java.util.*; public class Scope { protected boolean staticExists = false; protected Set<VariableExprToken> variables; protected Map<Token, ExpressionInfo> typeInfo; protected Map<String, LabelStmtToken> labels; protected final Scope parent; protected boolean levelForGoto = false; protected int cachedGotoLevel = -1; public Scope(Scope parent) { this.parent = parent; variables = new HashSet<>(); labels = new HashMap<>(); typeInfo = new LinkedHashMap<>(); } public void appendScope(Scope scope) { variables.addAll(scope.getVariables()); labels.putAll(scope.getLabels()); staticExists = staticExists || scope.staticExists; } public Map<Token, ExpressionInfo> getTypeInfo() { return typeInfo; } synchronized public ExpressionInfo typeInfoOf(Token token) { ExpressionInfo info = typeInfo.get(token); if (info == null) { typeInfo.put(token, info = new ExpressionInfo()); } return info; } public Set<VariableExprToken> getVariables() { return variables; } public void addVariable(VariableExprToken var) { variables.add(var); } public void addVariables(Collection<VariableExprToken> vars){ variables.addAll(vars); } public void addLabel(LabelStmtToken labelStmtToken) { labelStmtToken.setLevel(getGotoLevel()); labels.put(labelStmtToken.getName().toLowerCase(), labelStmtToken); } public Map<String, LabelStmtToken> getLabels() { return labels; } public boolean isStaticExists() { return staticExists; } public void setStaticExists(boolean staticExists) { this.staticExists = staticExists; } public boolean isLevelForGoto() { return levelForGoto; } public Scope setLevelForGoto(boolean applyGoto) { this.levelForGoto = applyGoto; this.cachedGotoLevel = -1; return this; } public int getGotoLevel() { if (cachedGotoLevel > -1) return cachedGotoLevel; int level = isLevelForGoto() ? 1 : 0; Scope pr = parent; while (pr != null) { level += pr.isLevelForGoto() ? 1 : 0; pr = pr.parent; } return cachedGotoLevel = level; } }