package com.github.sommeri.less4j.core.compiler.scopes.local; import java.util.List; import java.util.Stack; import com.github.sommeri.less4j.core.ast.ASTCssNode; import com.github.sommeri.less4j.core.ast.AbstractVariableDeclaration; import com.github.sommeri.less4j.core.ast.Expression; import com.github.sommeri.less4j.core.ast.ReusableStructure; import com.github.sommeri.less4j.core.ast.ReusableStructureName; import com.github.sommeri.less4j.core.ast.Variable; import com.github.sommeri.less4j.core.compiler.expressions.ExpressionFilter; import com.github.sommeri.less4j.core.compiler.scopes.FullMixinDefinition; import com.github.sommeri.less4j.core.compiler.scopes.ILocalScope; import com.github.sommeri.less4j.core.compiler.scopes.IScope; import com.github.sommeri.less4j.core.compiler.scopes.InScopeSnapshotRunner; import com.github.sommeri.less4j.core.compiler.scopes.ScopeFactory; import com.github.sommeri.less4j.core.compiler.scopes.local.MixinsDefinitionsStorage.MixinsPlaceholder; import com.github.sommeri.less4j.core.compiler.scopes.local.VariablesDeclarationsStorage.VariablesPlaceholder; public class LocalScope implements ILocalScope { // following is used only during debugging - to generate human readable // toString private String type; private final ASTCssNode owner; private boolean presentInAst = true; private LocalScopeData localData = new LocalScopeData(); private Stack<LocalScopeData> localDataSnapshots = new Stack<LocalScopeData>(); private boolean cloneOnWrite = false; private boolean cloned; private List<String> names; public LocalScope(ASTCssNode owner, List<String> names, String type) { this.owner = owner; this.names = names; this.type = type; } public LocalScope(ASTCssNode owner, LocalScopeData initialLocalData, List<String> names, String type) { this(owner, names, type); localData = initialLocalData; } public LocalScope(ASTCssNode owner, LocalScopeData initialLocalData, List<String> names, String type, boolean cloneOnWrite, boolean cloned) { this(owner, names, type); localData = initialLocalData; this.cloneOnWrite = cloneOnWrite; this.cloned = cloned; } @Override public ASTCssNode getOwner() { return owner; } public String getType() { return type; } public boolean isBodyOwnerScope() { return ScopeFactory.BODY_OWNER.equals(getType()); } public void removedFromAst() { presentInAst = false; } public boolean isPresentInAst() { return presentInAst; } public void addNames(List<String> names) { this.names.addAll(names); } public List<String> getNames() { return names; } public void registerVariable(AbstractVariableDeclaration declaration) { getLocalVariables().store(declaration); } public void registerVariable(AbstractVariableDeclaration node, Expression replacementValue) { getLocalVariables().store(node, replacementValue); } public void registerVariableIfNotPresent(String name, Expression replacementValue) { getLocalVariables().storeIfNotPresent(name, replacementValue); } public void registerVariable(String name, Expression replacementValue) { getLocalVariables().store(name, replacementValue); } public void addFilteredVariables(ExpressionFilter filter, IScope source) { getLocalVariables().addFilteredVariables(filter, source.getLocalVariables()); } public Expression getValue(Variable variable) { return getLocalVariables().getValue(variable.getName()); } public Expression getValue(String name) { return getLocalVariables().getValue(name); } @Override public void addAllMixins(List<FullMixinDefinition> mixins) { getLocalMixins().storeAll(mixins); } public void registerMixin(ReusableStructure mixin, IScope mixinsBodyScope) { getLocalMixins().store(new FullMixinDefinition(mixin, mixinsBodyScope)); } public DataPlaceholder createDataPlaceholder() { VariablesPlaceholder variablesPlaceholder = getLocalVariables().createPlaceholder(); MixinsPlaceholder mixinsPlaceholder = getLocalMixins().createPlaceholder(); return new DataPlaceholder(variablesPlaceholder, mixinsPlaceholder); } public void addToDataPlaceholder(IScope otherScope) { getLocalVariables().addToFirstPlaceholderIfNotPresent(otherScope.getLocalVariables()); getLocalMixins().addToPlaceholder(otherScope.getLocalMixins()); } public void replacePlaceholder(DataPlaceholder placeholder, IScope otherScope) { getLocalVariables().replacePlaceholder(placeholder.getVariablesPlaceholder(), otherScope.getLocalVariables()); getLocalMixins().replacePlaceholder(placeholder.getMixinsPlaceholder(), otherScope.getLocalMixins()); } public void closeDataPlaceholder() { getLocalVariables().closePlaceholder(); getLocalMixins().closePlaceholder(); } public void add(IScope otherSope) { getLocalMixins().storeAll(otherSope.getLocalMixins()); getLocalVariables().storeAll(otherSope.getLocalVariables()); } public LocalScopeData getLocalData() { return localData; } public ILocalScope cloneCurrentDataSnapshot() { return new LocalScope(owner, localData, names, type, true, false); } public boolean hasTheSameLocalData(ILocalScope otherScope) { return otherScope.getLocalData() == localData; } /** * Do not call this method directly. Use {@link InScopeSnapshotRunner} * instead. */ public void createCurrentDataSnapshot() { localDataSnapshots.push(localData); cloneOnWrite = true; cloned = false; } /** * Do not call this method directly. Use {@link InScopeSnapshotRunner} * instead. */ public void createOriginalDataSnapshot() { localDataSnapshots.push(localData); localData = localDataSnapshots.firstElement(); cloneOnWrite = true; cloned = false; } /** * Do not call this method directly. Use {@link InScopeSnapshotRunner} * instead. */ public void discardLastDataSnapshot() { localData = localDataSnapshots.pop(); cloneOnWrite = false; cloned = false; } public MixinsDefinitionsStorage getLocalMixins() { cloneIfNeeded(); return localData.getMixins(); } public VariablesDeclarationsStorage getLocalVariables() { cloneIfNeeded(); return localData.getVariables(); } public List<FullMixinDefinition> getAllMixins() { return getLocalMixins().getAllMixins(); } public List<FullMixinDefinition> getMixinsByName(List<String> nameChain, ReusableStructureName name) { return getLocalMixins().getMixins(nameChain, name); } public List<FullMixinDefinition> getMixinsByName(ReusableStructureName name) { return getLocalMixins().getMixins(name); } public List<FullMixinDefinition> getMixinsByName(String name) { return getLocalMixins().getMixins(name); } private void cloneIfNeeded() { if (cloneOnWrite && !cloned) { localData = localData.clone(); cloned = true; } } @Override public String toString() { return localData.toString(); } }