/**
* Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de>
*
* 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 de.codesourcery.jasm16.ast;
import org.apache.commons.lang.ObjectUtils;
import de.codesourcery.jasm16.compiler.Equation;
import de.codesourcery.jasm16.compiler.ICompilationContext;
import de.codesourcery.jasm16.compiler.ISymbol;
import de.codesourcery.jasm16.compiler.ISymbolTable;
import de.codesourcery.jasm16.compiler.IValueSymbol;
import de.codesourcery.jasm16.compiler.Label;
import de.codesourcery.jasm16.compiler.SymbolTable;
import de.codesourcery.jasm16.exceptions.ParseException;
import de.codesourcery.jasm16.parser.IParseContext;
import de.codesourcery.jasm16.parser.IParser.ParserOption;
import de.codesourcery.jasm16.parser.Identifier;
import de.codesourcery.jasm16.utils.TextRegion;
/**
* An AST node that represents a references to a symbol.
*
* @author tobias.gierke@code-sourcery.de
* @see Label
* @see ISymbol
* @see Equation
*/
public class SymbolReferenceNode extends ConstantValueNode
{
private Identifier identifier;
public Identifier getIdentifier()
{
return identifier;
}
@Override
protected SymbolReferenceNode parseInternal(IParseContext context) throws ParseException
{
final int startOffset = context.currentParseIndex();
this.identifier = context.parseIdentifier( null , context.hasParserOption(ParserOption.LOCAL_LABELS_SUPPORTED ) );
mergeWithAllTokensTextRegion( new TextRegion( startOffset , identifier.getRawValue().length() ) );
return this;
}
public void setIdentifier(Identifier identifier) {
this.identifier = identifier;
}
@Override
public boolean equals(Object obj)
{
if ( obj == this ) {
return true;
}
if ( obj instanceof SymbolReferenceNode) {
return ObjectUtils.equals( this.identifier , ((SymbolReferenceNode) obj).identifier );
}
return false;
}
@Override
public SymbolReferenceNode reduce(ICompilationContext context) {
return (SymbolReferenceNode) createCopy(false);
}
@Override
protected SymbolReferenceNode copySingleNode()
{
final SymbolReferenceNode result = new SymbolReferenceNode();
result.identifier = identifier;
return result;
}
@Override
public Long getNumericValue(ISymbolTable table)
{
ISymbol symbol = resolve(table);
if ( symbol == null ) {
return null;
}
if ( !( symbol instanceof IValueSymbol ) ) {
throw new RuntimeException("Internal error, symbol reference does not refer to a value symbol but to "+symbol);
}
return ((IValueSymbol) symbol).getValue( table );
}
public ISymbol resolve(ISymbolTable table) {
return resolve(table,false);
}
public ISymbol resolve(ISymbolTable table,boolean searchParentTables)
{
ISymbolTable currentTable = table;
do {
ISymbol symbol = internalResolve(currentTable);
if ( symbol != null ) {
if ( SymbolTable.DEBUG_SYMBOLS ) {
System.out.println("RESOLVED => Symbol '"+getIdentifier()+"' => "+symbol.getFullyQualifiedName());
}
return symbol;
}
if ( SymbolTable.DEBUG_SYMBOLS ) {
System.out.println("!!! Symbol '"+getIdentifier()+"' not found in "+currentTable);
}
currentTable = currentTable.getParent();
} while( currentTable != null && searchParentTables );
if ( SymbolTable.DEBUG_SYMBOLS ) {
System.out.println("Failed to resolve symbol '"+getIdentifier()+"'");
}
return null;
}
private ISymbol internalResolve(ISymbolTable table) {
ISymbol symbol = null;
// try to resolve as local reference first
LabelNode labelNode = getPreviousGlobalLabel();
if ( labelNode != null )
{
symbol = table.getSymbol(identifier, labelNode.getLabel() );
}
if ( symbol == null ) { // try to resolve as global label
symbol = table.getSymbol( this.identifier , null );
}
return symbol;
}
@Override
public String toString()
{
return identifier != null ? identifier.toString() : "<null identifier?>";
}
@Override
public boolean supportsChildNodes() {
return false;
}
@Override
public Long calculate(ISymbolTable symbolTable)
{
return getNumericValue( symbolTable );
}
}