/* Copyright (c) 2009-2013 Olivier Chafik, All Rights Reserved This file is part of JNAerator (http://jnaerator.googlecode.com/). JNAerator is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. JNAerator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with JNAerator. If not, see <http://www.gnu.org/licenses/>. */ package com.ochafik.lang.jnaerator; import java.util.Map; import java.util.LinkedHashMap; import com.ochafik.lang.jnaerator.parser.*; import static com.ochafik.lang.jnaerator.parser.Statement.*; import com.ochafik.lang.jnaerator.parser.StoredDeclarations.*; import com.ochafik.lang.jnaerator.parser.TypeRef.*; import com.ochafik.lang.jnaerator.parser.Expression.*; import com.ochafik.lang.jnaerator.parser.Declarator.*; import static com.ochafik.lang.jnaerator.parser.ElementsHelper.*; public class Symbols { public final Map<Integer, Element> resolvedVariables = new LinkedHashMap<Integer, Element>(); public final Map<Integer, Element> resolvedTypes = new LinkedHashMap<Integer, Element>(); public final Map<Element, SymbolTable> elementTables = new LinkedHashMap<Element, SymbolTable>(); public Element getType(Identifier ident) { return resolvedTypes.get(ident.getId()); } public Element getVariable(Identifier ident) { return resolvedVariables.get(ident.getId()); } public SymbolTable getEnclosingSymbolTable(Element element) { while (element != null) { SymbolTable st = elementTables.get(element); if (st != null) { return st; } element = element.getParentElement(); } return null; } public boolean isClassType(TypeRef tr) { if (tr instanceof SimpleTypeRef) { return getType(((SimpleTypeRef) tr).getName()) instanceof Struct; } return false; } public boolean isEnumType(TypeRef tr) { if (tr instanceof SimpleTypeRef) { return getType(((SimpleTypeRef) tr).getName()) instanceof com.ochafik.lang.jnaerator.parser.Enum; } return false; } public boolean isEnumItem(Identifier ident) { Element v = getVariable(ident); if (v instanceof Declarator) { v = ((Declarator) v).getParentElement(); } if (v instanceof Declaration) { v = ((Declaration) v).getValueType(); } Element type; if (v instanceof SimpleTypeRef) { return getType(((SimpleTypeRef) v).getName()) instanceof com.ochafik.lang.jnaerator.parser.Enum; } return false; // TODO ? } public static class SymbolTable { public final SymbolTable parent; public final Symbols symbols; public final Map<Identifier, Element> variableDefinitions = new LinkedHashMap<Identifier, Element>(); public final Map<Identifier, Element> typeDefinitions = new LinkedHashMap<Identifier, Element>(); public final Identifier subNamespace; public final Element owner; public SymbolTable(Symbols symbols) { this.parent = null; this.symbols = symbols; this.owner = null; this.subNamespace = null; } public SymbolTable(SymbolTable parent, Identifier subNamespace, Element owner) { this.parent = parent; this.symbols = parent.symbols; this.subNamespace = subNamespace; this.owner = owner; if (owner != null) { symbols.elementTables.put(owner, this); } } public void defineVariable(String name, Element element) { defineVariable(ident(name), element); } public void defineVariable(Identifier name, Element element) { variableDefinitions.put(name, element); } public void defineType(Identifier name, Element element) { typeDefinitions.put(name, element); } public Element resolveVariable(Identifier ident) { return resolve(ident, true); } public Element resolveType(Identifier ident) { return resolve(ident, false); } private Element resolve(Identifier ident, boolean varOrType) { if (ident == null) { return null; } // TODO handle new namespace Identifier lastIdent = ident.resolveLastSimpleIdentifier(); Element resolved = (varOrType ? variableDefinitions : typeDefinitions).get(lastIdent); if (resolved == null) { if (parent != null) { return parent.resolve(ident, varOrType); } //if (ident.getParentElement() instanceof TypeRef && ident.getParentElement().getParentElement() instanceof VariablesDeclaration) // System.out.println("hehehe"); return null; } //System.out.println("Resolved " + ident + " as " + resolved); //System.err.println("Resolved " + ident + " as " + resolved); (varOrType ? symbols.resolvedVariables : symbols.resolvedTypes).put(ident.getId(), resolved); return resolved; } } static Symbols resolveSymbols(Element root) { Symbols symbols = new Symbols(); final SymbolTable rootTable = new SymbolTable(symbols); root.accept(new Scanner() { SymbolTable currentTable = rootTable; /*public void visitTypeRef(TypeRef element) { super.visitTypeRef(element); }*/ public void visitSimpleTypeRef(SimpleTypeRef element) { super.visitSimpleTypeRef(element); currentTable.resolveType(element.getName()); } public void visitVariableRef(VariableRef element) { super.visitVariableRef(element); currentTable.resolveVariable(element.getName()); } @Override public void visitArg(final Arg element) { super.visitArg(element); currentTable.defineVariable(element.getName(), element); } @Override public void visitDirectDeclarator(final DirectDeclarator element) { super.visitDirectDeclarator(element); currentTable.defineVariable(element.getName(), element); } @Override public void visitBlock(final Block element) { currentTable = new SymbolTable(currentTable, null, element); try { super.visitBlock(element); } finally { currentTable = currentTable.parent; } } @Override public void visitFunction(final Function element) { currentTable.defineVariable(element.getName(), element); currentTable = new SymbolTable(currentTable, null, element); try { super.visitFunction(element); } finally { currentTable = currentTable.parent; } } @Override public void visitStruct(final Struct element) { currentTable.defineType(element.getTag(), element); currentTable = new SymbolTable(currentTable, element.getTag(), element); try { super.visitStruct(element); } finally { currentTable = currentTable.parent; } } @Override public void visitNamespace(final Namespace element) { currentTable = new SymbolTable(currentTable, element.getName(), element); try { super.visitNamespace(element); } finally { currentTable = currentTable.parent; } } @Override public void visitFor(final For element) { currentTable = new SymbolTable(currentTable, null, element); try { super.visitFor(element); } finally { currentTable = currentTable.parent; } } @Override public void visitIf(final If element) { currentTable = new SymbolTable(currentTable, null, element); try { super.visitIf(element); } finally { currentTable = currentTable.parent; } } @Override public void visitTry(final Try element) { currentTable = new SymbolTable(currentTable, null, element); try { super.visitTry(element); } finally { currentTable = currentTable.parent; } } @Override public void visitCatch(final Catch element) { currentTable = new SymbolTable(currentTable, null, element); try { super.visitCatch(element); } finally { currentTable = currentTable.parent; } } @Override public void visitWhile(final While element) { currentTable = new SymbolTable(currentTable, null, element); try { super.visitWhile(element); } finally { currentTable = currentTable.parent; } } @Override public void visitDoWhile(final DoWhile element) { currentTable = new SymbolTable(currentTable, null, element); try { super.visitDoWhile(element); } finally { currentTable = currentTable.parent; } } }); return symbols; } }