
com.inet.sass.Scope Maven / Gradle / Ivy
/*
* Copyright 2023 i-net software
* Copyright 2000-2014 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.inet.sass;
import java.util.HashMap;
import com.inet.sass.parser.Variable;
import com.inet.sass.tree.FunctionDefNode;
import com.inet.sass.tree.MixinDefNode;
/**
* Nestable scope for variables, functions and mixins.
*/
public class Scope {
private static final Definition MISSING = new Variable( null, null );
private static class DefinitionScope {
private DefinitionScope parent;
// optimization: create map only when needed
private HashMap definitions;
public DefinitionScope( DefinitionScope parent ) {
this.parent = parent;
}
/**
* Sets a definition value in the largest scope where it is already defined. If the variable isn't defined, set it in the current scope.
* @param node definition to set
*/
public void set( T node ) {
if( parent == null || !parent.setIfPresent( node ) ) {
add( node );
}
}
/**
* Sets a definition in the current scope without checking parent scopes.
* @param node definition to set
*/
public void add( T node ) {
HashMap definitions = this.definitions;
if( definitions == null ) {
definitions = this.definitions = new HashMap();
}
definitions.put( node.getName(), node );
}
/**
* Sets a definition and returns true if it is already defined in the scope or its parents. Otherwise returns false.
* @param node definition to set
* @return true if the definition was set
*/
private boolean setIfPresent( T node ) {
if( parent != null && parent.setIfPresent( node ) ) {
return true;
}
HashMap definitions = this.definitions;
if( definitions != null ) {
return definitions.replace( node.getName(), node ) != null;
}
return false;
}
public T get( String name ) {
HashMap definitions = this.definitions;
if( definitions != null ) {
T value = definitions.getOrDefault( name, (T)MISSING );
if( value != MISSING ) {
return value;
}
}
DefinitionScope parent = this.parent;
if( parent != null ) {
return parent.get( name );
} else {
return null;
}
}
@Override
public String toString() {
if( definitions != null ) {
return definitions.keySet().toString() + ", parent = " + parent;
} else {
return "{}, parent = " + parent;
}
}
}
private Scope parent;
private final DefinitionScope variables;
private final DefinitionScope functions;
private final DefinitionScope mixins;
public Scope() {
variables = new DefinitionScope( null );
functions = new DefinitionScope( null );
mixins = new DefinitionScope( null );
}
public Scope( Scope parent ) {
this.parent = parent;
variables = new DefinitionScope( parent.variables );
functions = new DefinitionScope( parent.functions );
mixins = new DefinitionScope( parent.mixins );
}
public Scope getParent() {
return parent;
}
/**
* Sets a variable value in the largest scope where it is already defined. If the variable isn't defined, set it in the current scope.
* @param node variable to set
*/
public void setVariable( Variable node ) {
variables.set( node );
}
/**
* Sets a variable in the current scope without checking parent scopes.
* @param node variable to set
*/
public void addVariable( Variable node ) {
variables.add( node );
}
public Variable getVariable( String name ) {
return variables.get( name );
}
public void defineFunction( FunctionDefNode function ) {
functions.add( function );
}
public void defineMixin( MixinDefNode mixin ) {
mixins.add( mixin );
}
public FunctionDefNode getFunctionDefinition( String name ) {
return functions.get( name );
}
public MixinDefNode getMixinDefinition( String name ) {
return mixins.get( name );
}
@Override
public String toString() {
return "Variables: " + variables.toString() + "\nFunctions: " + functions.toString() + "\nMixins: " + mixins.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy