/**
* 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.compiler;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import de.codesourcery.jasm16.exceptions.DuplicateSymbolException;
import de.codesourcery.jasm16.parser.Identifier;
public class ParentSymbolTable implements IParentSymbolTable
{
private final IdentityHashMap<String,ISymbolTable> tablesByUnitIdentifier = new IdentityHashMap<String,ISymbolTable>();
private final String debugIdentifier;
public ParentSymbolTable(String debugIdentifier)
{
this.debugIdentifier = debugIdentifier;
}
@Override
public String dumpToString()
{
String result = "ParentSymbolTable ("+debugIdentifier+")\n";
for ( Entry<String, ISymbolTable> t : tablesByUnitIdentifier.entrySet() ) {
result += "\n "+t.getKey()+" => "+t.getValue().dumpToString();
}
return result;
}
@Override
public String toString()
{
return "ParentSymbolTable( "+debugIdentifier+" ) { "+org.apache.commons.lang.StringUtils.join( tablesByUnitIdentifier.values() , " , " )+"}";
}
@Override
public IParentSymbolTable createCopy()
{
final ParentSymbolTable result = new ParentSymbolTable(this.debugIdentifier);
for ( Map.Entry<String,ISymbolTable> entry : tablesByUnitIdentifier.entrySet() ) {
result.tablesByUnitIdentifier.put( entry.getKey() , entry.getValue().createCopy() );
}
return result;
}
private ISymbolTable findSymbolTable(Identifier identifier,ISymbol scope)
{
for ( ISymbolTable table : tablesByUnitIdentifier.values() )
{
final ISymbol result = table.getSymbol( identifier , scope );
if ( result != null ) {
return table;
}
}
return null;
}
@Override
public ISymbol renameSymbol(ISymbol symbol, Identifier newIdentifier) throws DuplicateSymbolException
{
final ISymbol scope = symbol.isLocalSymbol() ? null : symbol.getScope();
final ISymbolTable existingTable= findSymbolTable( symbol.getName() , scope );
final ISymbol existing = existingTable == null ? null : existingTable.getSymbol( symbol.getName() , scope );
if ( existing == null ) {
throw new IllegalArgumentException("Symbol "+symbol+" is not part of this symbol table?");
}
return existingTable.renameSymbol( existing , newIdentifier );
}
@Override
public List<ISymbol> getSymbols()
{
final List<ISymbol> result = new ArrayList<ISymbol>();
for ( ISymbolTable table : tablesByUnitIdentifier.values() ) {
result.addAll( table.getSymbols() );
}
return result;
}
@Override
public void defineSymbol(ISymbol symbol) throws DuplicateSymbolException
{
final ICompilationUnit unit = symbol.getCompilationUnit();
ISymbolTable table = findSymbolTable( unit );
if ( table == null ) {
table = unit.getSymbolTable();
table.setParent( this );
tablesByUnitIdentifier.put( unit.getIdentifier() , table );
}
for ( ISymbolTable tmp : tablesByUnitIdentifier.values() )
{
if ( tmp.containsSymbol( symbol.getName() , symbol.getScope() ) )
{
final ISymbol existing = tmp.getSymbol( symbol.getName() , symbol.getScope() );
throw new DuplicateSymbolException( existing , symbol );
}
}
if ( DEBUG_SYMBOLS ) {
System.out.println("+++ Defining symbol "+symbol+" in "+this);
}
table.defineSymbol( symbol );
}
@Override
public ISymbol getSymbol(Identifier identifier, ISymbol scope)
{
final ISymbolTable table = findSymbolTable( identifier , scope );
return table == null ? null : table.getSymbol( identifier , scope );
}
@Override
public boolean containsSymbol(Identifier identifier, ISymbol scope) {
return getSymbol(identifier,scope ) != null;
}
@Override
public void clear()
{
for ( ISymbolTable table : tablesByUnitIdentifier.values() )
{
table.clear();
}
}
@Override
public IParentSymbolTable getParent()
{
return null;
}
@Override
public void setParent(IParentSymbolTable table)
{
throw new UnsupportedOperationException("Parent symbol tables cannot have other parents");
}
@Override
public int getSize()
{
int result = 0;
for ( ISymbolTable table : tablesByUnitIdentifier.values() )
{
result += table.getSize();
}
return result;
}
private ISymbolTable findSymbolTable(ICompilationUnit unit)
{
final ISymbolTable symbolTable = tablesByUnitIdentifier.get( unit.getIdentifier() );
if ( symbolTable != null )
{
return symbolTable;
}
for ( Iterator<Entry<String, ISymbolTable>> it = tablesByUnitIdentifier.entrySet().iterator() ; it.hasNext() ; )
{
final Entry<String, ISymbolTable> entry = it.next();
if ( entry.getKey().equals( unit.getResource().getIdentifier() ) ) {
return entry.getValue();
}
}
return null;
}
@Override
public void clear(ICompilationUnit unit)
{
final ISymbolTable symbolTable = findSymbolTable( unit );
if ( symbolTable != null ) {
symbolTable.clear();
}
}
}