Initial implementation of symbols and scopes with symbol table.
authorAaron Becker <abecker3@illinois.edu>
Thu, 12 Jun 2008 06:29:38 +0000 (06:29 +0000)
committerAaron Becker <abecker3@illinois.edu>
Thu, 12 Jun 2008 06:29:38 +0000 (06:29 +0000)
Based on Terrence Parr's Mantra implementation.

12 files changed:
src/langs/charj/src/charj/translator/ClassSymbol.java [new file with mode: 0644]
src/langs/charj/src/charj/translator/InterfaceSymbol.java [new file with mode: 0644]
src/langs/charj/src/charj/translator/LocalScope.java [new file with mode: 0644]
src/langs/charj/src/charj/translator/MethodSymbol.java [new file with mode: 0644]
src/langs/charj/src/charj/translator/OutputMode.java
src/langs/charj/src/charj/translator/PackageScope.java [new file with mode: 0644]
src/langs/charj/src/charj/translator/Scope.java [new file with mode: 0644]
src/langs/charj/src/charj/translator/Symbol.java [new file with mode: 0644]
src/langs/charj/src/charj/translator/SymbolTable.java [new file with mode: 0644]
src/langs/charj/src/charj/translator/SymbolWithScope.java [new file with mode: 0644]
src/langs/charj/src/charj/translator/Translator.java
src/langs/charj/src/charj/translator/VariableSymbol.java [new file with mode: 0644]

diff --git a/src/langs/charj/src/charj/translator/ClassSymbol.java b/src/langs/charj/src/charj/translator/ClassSymbol.java
new file mode 100644 (file)
index 0000000..7911c04
--- /dev/null
@@ -0,0 +1,271 @@
+
+package charj.translator;
+
+import java.util.*;
+
+public class ClassSymbol extends SymbolWithScope implements Scope {
+
+    public ClassSymbol superClass;
+    public List<String> interfaceImpls;
+
+    Map<String, PackageScope> imports = 
+        new LinkedHashMap<String, PackageScope>();
+
+    /** List of all fields and methods */
+    public Map<String, Symbol> members = new LinkedHashMap<String, Symbol>();
+    public Map<String, String> aliases = new LinkedHashMap<String, String>();
+
+    /** The set of method names (without signatures) for this class.  Maps
+     *  to a list of methods with same name but different args
+     protected Map<String, List<MethodSymbol>> methods =
+     new HashMap<String, List<MethodSymbol>>();
+     */
+
+    /** List of unmangled methods for this class. Used to distinguish
+     *  var from method name in expressions.  x = f; // what is f?
+     */
+    protected Set<String> methodNames = new HashSet<String>();
+
+    public boolean hasCopyCtor = false;
+
+    public ClassSymbol(
+            SymbolTable symtab, 
+            String name) 
+    {
+        super(symtab, name);
+        type = this;;
+        for (String pkg : SymbolTable.AUTO_IMPORTS) {
+            importPackage(pkg);
+        }
+    }
+
+    public ClassSymbol(
+            SymbolTable symtab, 
+            String name,
+            ClassSymbol
+            superClass,
+            Scope scope)
+    {
+        this(symtab, name);
+        this.superClass = superClass;
+        this.scope = scope;
+
+        // manually add automatic class methods and symbols here
+    }
+
+    public Scope getEnclosingScope() 
+    {
+        // at root?  Then use enclosing scope
+        if ( superClass==null ) { 
+            return scope;
+        }
+        return superClass;
+    }
+
+    public Map<String, Symbol> getMembers() {
+        return members;
+    }
+
+    /** Importing a package means adding the package to list of "filters"
+     *  used by resolvePackage.  The resolve operation can only see classes
+     *  defined in the imported packages.  This method asks the sym tab if
+     *  it is known before looking at corresponding dir on disk to see if it 
+     *  exists.
+     *
+     *  Return null if this class is not in sym tab and was not found in path.
+     */
+    public PackageScope importPackage(String packageName) 
+    {
+        if (debug()) System.out.println(
+                "ClassSymbol.importPackage(" + packageName +
+                "): add to " + toString());
+        
+        PackageScope p = symtab.resolvePackage(packageName);
+        if ( p!=null ) {
+            imports.put(packageName, p);
+            if (debug()) System.out.println(
+                    "ClassSymbol.importPackage(" + packageName + "): known");
+            return p;
+        }
+
+        if ( symtab.translator.findPackage(packageName)!=null ) {
+            p = symtab.definePkg(packageName);
+            imports.put(packageName, p);
+        }
+
+        if ( p==null && debug() ) System.out.println(
+                "ClassSymbol.importPackage(" + packageName + 
+                "): dir not found");
+        return p;
+    }
+
+    public void alias(
+            CharjAST aliasAST, 
+            CharjAST methodNameAST) 
+    {
+        String op = aliasAST.getToken().getText();
+        op = op.substring(1,op.length()-1);
+        String method = methodNameAST.getToken().getText();
+        method = method.substring(1,method.length()-1);
+        alias(op, method);
+    }
+
+    public void alias(
+            String alias, 
+            String methodName) 
+    {
+        aliases.put(alias, methodName);
+    }
+
+    public String getMethodNameForOperator(String op) 
+    {
+        String name = aliases.get(op);
+        if ( name==null ) {
+            symtab.translator.error(
+                    "no such operator for " + this.name + ": " + op);
+        }
+        return name;
+    }
+
+    /** Using the list of imports, resolve a package name like charj::lang.
+     *  There may be many packages defined and visible to the symbol table
+     *  but this class can only see those packages in the implicit or explicit
+     *  import list.
+     */
+    public PackageScope resolvePackage(String packageName) {
+        return imports.get(packageName);
+    }
+
+    /** To resolve a type in a class, look it up in each imported package 
+     *  including the current package. Classes cannot be defined in the 
+     *  superclass so don't look upwards for types.
+     *
+     *  First check to see if we are resolving enclosing class then
+     *  look for type in each imported package.  If not found in existing
+     *  packges, walk through imported packages again, trying to load from 
+     *  disk.
+     */
+    public ClassSymbol resolveType(String type) 
+    {
+        if ( debug() ) System.out.println(
+                "ClassSymbol.resolveType(" + type + "): context is " + name +
+                ":" + members.keySet());
+        if ( type==null ) {
+            return null;
+        }
+
+        if ( name.equals(type) ) {
+            if ( debug() ) System.out.println(
+                    "ClassSymbol.resolveType(" + type + 
+                    "): surrounding class " + name + ":" + members.keySet());
+            return this;
+        }
+
+        // look for type in classes already defined in imported packages
+        for (String packageName : imports.keySet()) {
+            PackageScope pkg = resolvePackage(packageName);
+            ClassSymbol cs = pkg.resolveType(type);
+            if ( cs != null) { // stop looking, found it
+                if ( debug() ) System.out.println(
+                        "ClassSymbol.resolveType(" + type + 
+                        "): found in context " + name + ":" + 
+                        members.keySet());
+                return cs;
+            }
+        }
+
+        // not already seen in one of the imported packages, look on disk
+        for (String packageName : imports.keySet()) {
+            PackageScope pkg = resolvePackage(packageName);
+            ClassSymbol cs = symtab.translator.loadType(
+                    pkg.getFullyQualifiedName(), type);
+            if ( cs!=null ) {
+                pkg.define(type, cs); // add to symbol table
+                if ( debug() ) System.out.println(
+                        "ClassSymbol.resolveType(" + type +
+                        "): found after loading in context " + name +
+                        ":" + members.keySet());
+                return cs;
+            }
+        }
+
+        if ( debug() ) System.out.println(
+                "ClassSymbol.resolveType(" + type + 
+                "): not in context " + name + ":" + members.keySet());
+        return null;
+    }
+
+    public MethodSymbol resolveMethodLocally(
+            String name, 
+            int numargs) 
+    {
+        if ( numargs>0 ) {
+            name += numargs;
+        }
+     
+        Symbol s = members.get(name);
+        if ( s!=null && s.getClass() == MethodSymbol.class ) {
+            return (MethodSymbol)s;
+        }
+
+        return null;
+    }
+
+    public boolean isMethod(String name) 
+    {
+        if ( methodNames.contains(name) ) {
+            return true;
+        }
+        if ( getEnclosingScope()!=null ) {
+            return getEnclosingScope().isMethod(name);
+        }
+        return false;
+    }
+
+    public Symbol define(
+            String name, 
+            Symbol sym) 
+    {
+        if ( sym instanceof MethodSymbol ) {
+            methodNames.add(sym.name);
+        }
+        return super.define(name, sym);
+    }
+
+    public String toString() {
+        return "ClassSymbol[" + name + "]: " + members;
+    }
+
+    public String getFullyQualifiedName() 
+    {
+        String parent = null;
+        if ( scope!=null ) { // in a package?
+            parent = scope.getFullyQualifiedName();
+        }
+        if ( parent!=null ) {
+            return parent+"::"+name;
+        }
+        return name;
+    }
+
+    public String getFullyQualifiedJavaName() 
+    {
+        String parent = null;
+        if ( scope!=null ) { // in a package?
+            parent = scope.getFullyQualifiedJavaName();
+        }
+        if ( parent!=null ) {
+            return parent+"."+getMangledName();
+        }
+        return name;
+    }
+
+    public String getMangledName() 
+    {
+        if ( SymbolTable.TYPE_NAMES_TO_MANGLE.contains(name) ) {
+            return "m"+name;
+        }
+        return name;
+    }
+
+}
diff --git a/src/langs/charj/src/charj/translator/InterfaceSymbol.java b/src/langs/charj/src/charj/translator/InterfaceSymbol.java
new file mode 100644 (file)
index 0000000..abe9b1c
--- /dev/null
@@ -0,0 +1,17 @@
+
+package charj.translator;
+
+import java.util.*;
+
+public class InterfaceSymbol extends ClassSymbol {
+    public List<String> superClasses = new ArrayList<String>();
+
+    public InterfaceSymbol(
+            SymbolTable symtab, 
+            String name, 
+            ClassSymbol superClass, 
+            Scope scope) 
+    {
+        super(symtab, name, superClass, scope);
+    }
+}
diff --git a/src/langs/charj/src/charj/translator/LocalScope.java b/src/langs/charj/src/charj/translator/LocalScope.java
new file mode 100644 (file)
index 0000000..d88a0d7
--- /dev/null
@@ -0,0 +1,38 @@
+package charj.translator;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class LocalScope extends SymbolWithScope implements Scope {
+    Scope parent;
+    Map members = new LinkedHashMap();
+
+    public LocalScope(
+            SymbolTable symtab, 
+            Scope parent) 
+    {
+        super(symtab);
+        this.parent = parent;
+    }
+
+    public Scope getEnclosingScope() 
+    {
+        return parent;
+    }
+
+    public Map getMembers() 
+    {
+        return members;
+    }
+
+    /** A local scope's name is the parent method's scope */
+    public String getScopeName() 
+    {
+        return parent.getScopeName();
+    }
+
+    public String toString() 
+    {
+        return members.toString();
+    }
+}
diff --git a/src/langs/charj/src/charj/translator/MethodSymbol.java b/src/langs/charj/src/charj/translator/MethodSymbol.java
new file mode 100644 (file)
index 0000000..9f7a0b9
--- /dev/null
@@ -0,0 +1,133 @@
+
+package charj.translator;
+
+import org.antlr.stringtemplate.StringTemplate;
+import org.antlr.stringtemplate.language.AngleBracketTemplateLexer;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class MethodSymbol 
+    extends SymbolWithScope 
+    implements Scope {
+    /** The enclosing class */
+    Scope enclosingScope;
+
+    /** The formal argument list scope */
+    LinkedHashMap<String, VariableSymbol> orderedArgs = new LinkedHashMap();
+
+    /** The list of local variables defined anywhere in the method */
+    LocalScope locals;
+
+    public boolean isStatic = false;
+    public boolean isCtor = false;
+
+    public MethodSymbol(SymbolTable symtab) 
+    { 
+        super(symtab); 
+    }
+
+    public MethodSymbol(
+            SymbolTable symtab, 
+            String name,
+            Scope enclosingScope,
+            ClassSymbol retType)
+    {
+        super(symtab, name);
+        this.enclosingScope = enclosingScope;
+        this.type = retType;
+    }
+
+    public VariableSymbol defineArg(
+            String name, 
+            ClassSymbol type) 
+    {
+        if ( orderedArgs.get(name)!=null ) {
+            return null;
+        }
+        VariableSymbol vs = new VariableSymbol(symtab,name,type);
+        define(name, vs);
+        return vs;
+    }
+
+    public Scope getEnclosingScope() 
+    {
+        return enclosingScope;
+    }
+
+    public LocalScope getLocalScope() 
+    {
+        return locals;
+    }
+
+    public void setLocalScope(LocalScope s)
+    {
+        locals = s;
+    }
+
+    public String getScopeName() 
+    {
+        return SymbolTable.mangle(name);
+    }
+
+    public Map createMembers() 
+    {
+        if ( orderedArgs==null ) {
+            orderedArgs = new LinkedHashMap();
+        }
+        return orderedArgs;
+    }
+
+    public Map getMembers() 
+    {
+        return orderedArgs;
+    }
+
+    public String signature() 
+    {
+        return null;
+    }
+
+    public String toString() 
+    {
+        StringTemplate st = new StringTemplate(
+                "<if(parent)><parent>::<endif><name>(<args; separator=\",\">)" +
+                "<if(locals)>{<locals; separator=\",\">}<endif>",
+                AngleBracketTemplateLexer.class);
+        st.setAttribute("parent", enclosingScope.getScopeName());
+        st.setAttribute("name", name);
+        st.setAttribute("args", orderedArgs);
+        st.setAttribute("locals", locals!=null?locals.getMembers():null);
+        return st.toString();
+    }
+
+    public int hashCode() 
+    {
+        return name.hashCode() + orderedArgs.size() + enclosingScope.hashCode();
+    }
+
+    /** Two methods are equals() when they have the same name and
+     *  the same number of arguments in the same scope.
+     */
+    public boolean equals(Object object) 
+    {
+        return name.equals(((MethodSymbol)object).name) &&
+            orderedArgs.size()==((MethodSymbol)object).orderedArgs.size() &&
+            enclosingScope == ((MethodSymbol)object).enclosingScope;
+    }
+
+    public String getMangledName() 
+    {
+        String mangled = name;
+        boolean isCtor = name.equals(enclosingScope.getScopeName());
+        if ( SymbolTable.METHOD_NAMES_TO_MANGLE.contains(name) ||
+                (isCtor && SymbolTable.TYPE_NAMES_TO_MANGLE.contains(name)) ) {
+            mangled = "cj" + mangled;
+        }
+        int numargs = getMembers().size();
+        if ( numargs > 0 && !isCtor ) {
+            mangled += numargs;
+        }
+        return mangled;
+    }
+}
index b3c0310db9c2c4b9f7fdb13245f46a37aa997232..ba06f70d0b9bd70f5d4cbb2a0d2cfc9446f3d0e2 100644 (file)
@@ -3,7 +3,7 @@ package charj.translator;
 /**
  * Indicates whether we are working on .ci or .cc output.
  */
-enum OutputMode {
+public enum OutputMode {
     cc(".cc"), 
     ci(".ci"),
     h(".h");
diff --git a/src/langs/charj/src/charj/translator/PackageScope.java b/src/langs/charj/src/charj/translator/PackageScope.java
new file mode 100644 (file)
index 0000000..468b79b
--- /dev/null
@@ -0,0 +1,77 @@
+
+package charj.translator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class PackageScope extends SymbolWithScope {
+
+    /** List of packages and classes in this package */
+    Map<String, Symbol> members = new HashMap();
+    Scope enclosingScope;
+
+    public PackageScope(
+            SymbolTable symtab, 
+            String name, 
+            Scope enclosingScope) 
+    {
+        super(symtab, name);
+        this.enclosingScope = enclosingScope;
+    }
+
+    public Scope getEnclosingScope() 
+    {
+        return enclosingScope;
+    }
+
+    /** See if type is already defined in this package.  If not, look
+     *  for type on the disk in same package.  For example, first time
+     *  mantra::io::File fails to resolve.  Load from disk and put File
+     *  in package io which is in package mantra.  Next time, File will
+     *  be found.
+     */
+    public ClassSymbol resolveType(String type) 
+    {
+        if (debug()) System.out.println(
+                "PackageScope.resolveType(" + type + 
+                "): examine " + toString());
+
+        // look for type in this package's members (other packages, classes)
+        if ( getMembers()!=null ) {
+            Symbol s = getMembers().get(type);
+            if ( s!=null && s instanceof ClassSymbol ) {
+                if (debug()) System.out.println(
+                        "PackageScope.resolveType(" + type + "): found in " + 
+                        toString());
+                return (ClassSymbol)s;
+            }
+        }
+        return null;
+    }
+
+    public Map<String, Symbol> getMembers() 
+    {
+        return members;
+    }
+
+    public String getFullyQualifiedName() 
+    {
+        if ( name.equals(SymbolTable.DEFAULT_PACKAGE_NAME) ) {
+            return null;
+        }
+        return super.getFullyQualifiedName();
+    }
+
+    public String getFullyQualifiedJavaName() 
+    {
+        if ( name.equals(SymbolTable.DEFAULT_PACKAGE_NAME) ) {
+            return null;
+        }
+        return super.getFullyQualifiedJavaName();
+    }
+
+    public String toString() 
+    {
+        return "PackageScope[" + name + "]: " + members.keySet();
+    }
+}
diff --git a/src/langs/charj/src/charj/translator/Scope.java b/src/langs/charj/src/charj/translator/Scope.java
new file mode 100644 (file)
index 0000000..d214ec9
--- /dev/null
@@ -0,0 +1,58 @@
+
+package charj.translator;
+
+import java.util.Map;
+
+public interface Scope {
+    
+    /** Does this scope have a name?  Call it getScopeName not getName so
+     *  things are not confusing in SymbolWithScope subclasses that have a
+     *  symbol name and a scope name.
+     */
+    public String getScopeName();
+
+    public Scope getEnclosingScope();
+
+    public String getFullyQualifiedName();
+
+    public String getFullyQualifiedJavaName();    
+
+    /** Return a Map of all contained members */
+    public Map<String, Symbol> getMembers();
+
+    /** Look up name in this scope or in enclosing scope if not here;
+     *  don't look on disk for classes.
+     */
+    public Symbol resolve(String name);
+
+    public VariableSymbol resolveVariable(String name);
+
+    /** Look up a typename in this scope or in enclosing scope if not here.
+     *  Load from disk if necessary.
+     */
+    public ClassSymbol resolveType(String name);
+
+    /** To look up a method, we need to know number of arguments for overloading
+     *  so we need separate method to distinguish from resolve().
+     *  Don't return variables or classes.
+     */
+    public MethodSymbol resolveMethod(
+            String name, 
+            int numargs);
+
+    /** Sometimes we need to test if a name is a method, but we don't know
+     *  the full signature (or can't compute easily).  This identifies the
+     *  kind of thing 'name' is.
+     */
+    public boolean isMethod(String name);
+
+    /** Remove a name from this scope */
+    public Symbol remove(String name);
+
+    /** Define a symbol in the current scope */
+    public Symbol define(
+            String name, 
+            Symbol sym);
+}
+
+
diff --git a/src/langs/charj/src/charj/translator/Symbol.java b/src/langs/charj/src/charj/translator/Symbol.java
new file mode 100644 (file)
index 0000000..0ce4c6e
--- /dev/null
@@ -0,0 +1,53 @@
+
+package charj.translator;
+
+import charj.translator.CharjAST;
+import org.antlr.runtime.TokenStream;
+
+public class Symbol {
+    /** All symbols at least have a name */
+    public String name;
+
+    /** Classes, methods, variables, and closures have types */
+    public ClassSymbol type;
+
+    /** All symbols know what scope contains them. */
+    public Scope scope;
+
+    /** All symbols know which symbol table they are apart of */
+    public SymbolTable symtab;
+
+    /** Often we want to know where in tree this symbol was defined. */
+    public CharjAST defintion;
+
+    /** To print definition, we need to know where tokens live */
+    public TokenStream definitionTokenStream;
+
+    public Symbol(SymbolTable _symtab) 
+    {
+        symtab = _symtab;
+    }
+
+    public Symbol(
+            SymbolTable _symtab, 
+            String _name, 
+            ClassSymbol _type) 
+    {
+        this(_symtab);
+        name = _name;
+        type = _type;
+    }
+
+    /** Some mantra types and methods must be mangled before
+     *  emitting to Java like int.
+     */
+    public String getMangledName() 
+    {
+        return name;
+    }
+
+    public boolean debug()
+    {
+        return symtab.translator.debug();
+    }
+}
diff --git a/src/langs/charj/src/charj/translator/SymbolTable.java b/src/langs/charj/src/charj/translator/SymbolTable.java
new file mode 100644 (file)
index 0000000..bd88616
--- /dev/null
@@ -0,0 +1,186 @@
+
+package charj.translator;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+public class SymbolTable {
+    public static final String DEFAULT_PACKAGE_NAME = "default";
+    public static final List<String> AUTO_IMPORTS = 
+        new ArrayList<String>() {
+            {
+                add("charj::lang");
+                add(DEFAULT_PACKAGE_NAME);
+            }
+        };
+
+    public static final Set<String> TYPE_NAMES_TO_MANGLE = 
+        new HashSet<String>() { {} };
+
+    public static final Set<String> METHOD_NAMES_TO_MANGLE = 
+        new HashSet<String>() { {} };
+
+    /** Provides runtime variables and loads classes */
+    public Translator translator;
+
+    /** The scope for the "default" package */
+    PackageScope defaultPkg;
+
+    public Map<String,PackageScope> topLevelPackageScopes = new HashMap();
+
+    /** This is the list of all scopes created during symbol table building. */
+    public List scopes = new ArrayList();
+
+    /** Root of the object hierarchy, Charj::Object */
+    ClassSymbol objectRoot;
+
+    public SymbolTable(Translator _translator) 
+    {
+        translator = _translator;
+        // define default package
+        defaultPkg = new PackageScope(this, DEFAULT_PACKAGE_NAME, null);
+        topLevelPackageScopes.put(DEFAULT_PACKAGE_NAME, defaultPkg);
+        // define mantra::lang
+        PackageScope lang = definePkg("charj::lang");
+        addScope(defaultPkg);
+    }
+
+    public boolean debug() {
+        return translator.debug();
+    }
+
+    protected void initObjectHierarchy() 
+    {
+        PackageScope lang = resolvePackage("charj::lang");
+        objectRoot = new ClassSymbol(this, "Object", null, lang);
+        objectRoot.define("EOF", new VariableSymbol(this,"EOF",null));
+        lang.define("Object", objectRoot);
+    }
+
+    public ClassSymbol resolveBuiltInType(String type) {
+        return objectRoot.resolveType(type);
+    }
+
+    /** Given a package like foo or charj::io, define it by breaking it up and
+     *  looking up the packages to left of last id.  Add last id to that 
+     *  package.
+     */
+    public PackageScope definePkg(String packageName) 
+    {
+        String[] packageNames = packageName.split("::");
+        String outerPackageName = packageNames[0];
+        PackageScope outerPackage = (PackageScope)defaultPkg.resolve(
+                outerPackageName);
+        if ( outerPackage == null ) {
+            if ( debug() ) {
+                System.out.println(
+                        "definePkg(" + packageName + 
+                        "): defining outer pkg: " + outerPackageName);
+            }
+            outerPackage = new PackageScope(this,outerPackageName,defaultPkg);
+            defaultPkg.define(outerPackageName, outerPackage);
+            topLevelPackageScopes.put(outerPackageName, outerPackage);
+        }
+
+        PackageScope enclosingPackage = defaultPkg;
+        for (String pname : packageNames) {
+            PackageScope p = (PackageScope)enclosingPackage.resolve(pname);
+            if ( p==null ) {
+                if ( debug() ) System.out.println(
+                        "definePkg(" + packageName + 
+                        "): defining inner pkg: " + pname +
+                        " in "+enclosingPackage.toString());
+                
+                p = new PackageScope(this,pname,enclosingPackage);
+                enclosingPackage.define(pname, p);
+            }
+            enclosingPackage = p;
+        }
+        return enclosingPackage;
+    }
+
+    public PackageScope getDefaultPkg() {
+        return defaultPkg;
+    }
+
+    /** Find package starting with it's outermost package name.  If
+     *  not in sym tab, return null.
+     */
+    public PackageScope resolvePackage(String packageName) 
+    {
+        if ( debug() ) System.out.println(
+                "SymbolTable.resolvePackage(" + packageName + 
+                "): examine: " + topLevelPackageScopes.keySet());
+        String[] packageNames = packageName.split("::");
+        String outerPackageName = packageNames[0];
+        PackageScope enclosingPackage = topLevelPackageScopes.get(
+                outerPackageName);
+
+        if ( enclosingPackage==null ) {
+            if ( debug() ) System.out.println(
+                    "resolvePackage(" + packageName + "): outer package " +
+                    outerPackageName + " not found in top level " +
+                    topLevelPackageScopes.keySet());
+            return null;
+        }
+
+        if ( packageNames.length==1 ) {
+            return enclosingPackage; // top-level package
+        }
+
+        PackageScope p = null;
+        for (int i=1; i<packageNames.length; i++) {
+            String pname = packageNames[i];
+            p = (PackageScope)enclosingPackage.resolve(pname);
+            if ( p==null ) {
+                if ( debug() ) System.out.println(
+                        "SymbolTable.resolvePackage(" + packageName +
+                        "): not found in " + topLevelPackageScopes.keySet());
+                return null;
+            }
+            enclosingPackage = p;
+        }
+
+        if ( p!=null && debug() ) System.out.println(
+                "SymbolTable.resolvePackage(" + packageName + "): found in " +
+                topLevelPackageScopes.keySet());
+        return p;
+    }
+
+    public ClassSymbol getObjectRoot() {
+        return objectRoot;
+    }
+
+    public void addScope(Scope s) {
+        scopes.add(s);
+    }
+
+    // TODO:  shouldn't we include the arguments and do all mangling here?
+    public static String mangle(String methodName) {
+        if ( METHOD_NAMES_TO_MANGLE.contains(methodName) ) {
+            return "cj" + methodName;
+        }
+        return methodName;
+    }
+
+    public static String unmangle(String methodName) {
+        // this is not perfect because perhaps someone makes a method called
+        // mtoString() etc.
+        String unmangled = methodName.substring(2, methodName.length());
+        if ( METHOD_NAMES_TO_MANGLE.contains(unmangled) ) {
+            return unmangled;
+        }
+        return methodName;
+    }
+
+    public static String getCharjTypeName(String className) {
+        if ( SymbolTable.TYPE_NAMES_TO_MANGLE.contains(className) ) {
+            return "cj"+className;
+        }
+        return className;
+    }
+
+    public String toString() {
+        return scopes.toString();
+    }
+}
diff --git a/src/langs/charj/src/charj/translator/SymbolWithScope.java b/src/langs/charj/src/charj/translator/SymbolWithScope.java
new file mode 100644 (file)
index 0000000..b42967d
--- /dev/null
@@ -0,0 +1,190 @@
+
+package charj.translator;
+
+import java.util.Map;
+
+public abstract class SymbolWithScope 
+    extends Symbol 
+    implements Scope {
+
+    public SymbolWithScope(SymbolTable symtab) 
+    {
+        super(symtab);
+    }
+
+    public SymbolWithScope(
+            SymbolTable symtab, 
+            String name) 
+    {
+        super(symtab, name, null);
+    }
+
+    /** Find any symbol matching name; won't look on disk for classes though */
+    public Symbol resolve(String name) 
+    {
+        Symbol s = null;
+        
+        // in this scope?
+        if ( getMembers()!=null ) {
+            s = (Symbol)getMembers().get(name);
+        }
+
+        // if not, check any enclosing scope
+        if ( s==null && getEnclosingScope() != null ) 
+        {
+            return getEnclosingScope().resolve(name);
+        }
+
+        return s;
+    }
+
+    /** Scopes other other package and class don't know how to resolve types
+     *  (e.g., MethodSymbol).  Look to enclosing scope.
+     */
+    public ClassSymbol resolveType(String type) 
+    {
+        if ( getEnclosingScope()!=null ) {
+            return getEnclosingScope().resolveType(type);
+        }
+        return null;
+    }
+
+    public VariableSymbol resolveVariable(String name) 
+    {
+        Symbol s = getMembers().get(name);
+        if (debug()) System.out.println(
+                "SymbolWithScope.resolveVariable(" + name + 
+                "): examine " + this.getClass().getName() + "=" + toString());
+        
+        // found it
+        if (s != null && s.getClass() == VariableSymbol.class) {
+            if (debug()) System.out.println(
+                    "SymbolWithScope.resolveVariable(" + name + ") found in " +
+                    this.getClass().getName() + "=" + toString());
+            return (VariableSymbol)s;
+        }
+
+        // not here, check enclosing scope
+        if ( s==null && getEnclosingScope() != null ) {
+            return getEnclosingScope().resolveVariable(name);
+        }
+
+        // not a variable
+        if (debug()) System.out.println(
+                "SymbolWithScope.resolveVariable(" + name + 
+                "): not a variable in " + this.getClass().getName() + 
+                "=" + toString());
+        return null;
+    }
+
+    public MethodSymbol resolveMethod(
+            String name, 
+            int numargs) 
+    {
+        if (debug()) System.out.println(
+                "SymbolWithScope.resolveMethod(" + name + "," + numargs +
+                "): examine " + this.getClass().getName() + "=" + toString());
+        
+        Symbol s = null;
+        if ( numargs == 0 ) {
+            s = resolve(name);
+        } else {
+            s = resolve(name+numargs);
+        }
+
+        if ( s!=null && debug() ) System.out.println(
+                "SymbolWithScope.resolveMethod(" + name + "," + numargs +
+                "): found in context " + this.getClass().getName() +
+                "=" + toString());
+        else if ( s==null && debug() ) System.out.println(
+                "SymbolWithScope.resolveMethod(" + name + "," + numargs +
+                "): not found in context " + this.getClass().getName() + 
+                "="+toString());
+        
+        if ( s==null || (s!=null && s.getClass() != MethodSymbol.class) ) {
+            // not a method
+            if ( s!=null && debug() ) System.out.println(
+                    "SymbolWithScope.resolveMethod(" + name + "," + numargs +
+                    "): not a method");
+            return null;         
+        }
+        return (MethodSymbol)s;
+    }
+
+    /** By default, pass up responsibility in scope hierarchy until we
+     *  find a class.
+     */
+    public boolean isMethod(String name) 
+    {
+        if ( getEnclosingScope()!=null ) {
+            return getEnclosingScope().isMethod(name);
+        }
+        return false;
+    }
+
+    public Symbol remove(String name) 
+    {
+        Symbol s = (Symbol)getMembers().get(name);
+        if ( s==null && getEnclosingScope() != null) {
+            return getEnclosingScope().remove(name);
+        }
+        if ( s != null) {
+            getMembers().remove(name);
+        }
+        return s;
+    }
+
+    public Symbol define(
+            String name, 
+            Symbol sym) 
+    {
+        // check for error
+        Map members = getMembers();
+        if ( members == null ) {
+            members = createMembers();
+        }
+        members.put(name, sym);
+        sym.scope = this; // track the scope in each symbol
+        
+        if (debug()) System.out.println("define " + name + " as " + sym);
+        return sym;
+    }
+
+    /** create the member list; we're about to add stuff */
+    protected Map<String, Symbol> createMembers() 
+    {
+        return getMembers();
+    }
+
+    /** Scope defaults to just the symbol name; method f's scope is f by 
+     *  default. 
+     */
+    public String getScopeName() 
+    {
+        return name;
+    }
+
+    public String getFullyQualifiedName() 
+    {
+        String parent = null;
+        if ( getEnclosingScope()!=null ) {
+            parent = getEnclosingScope().getFullyQualifiedName();
+        }
+        if ( parent!=null ) {
+            return parent + "::" + name;
+        }
+        return name;
+    }
+
+    public String getFullyQualifiedJavaName() 
+    {
+        String parent = null;
+        if ( getEnclosingScope()!=null ) {
+            parent = getEnclosingScope().getFullyQualifiedJavaName();
+        }
+        if ( parent!=null ) {
+            return parent + "." + name;
+        }
+        return name;
+    }
+}
index b7c2a8051662667ced52ba8b1c503d4699b56e6b..09ffa812c7368656513cdb47b63ebe8534cebf2e 100644 (file)
@@ -22,10 +22,10 @@ public class Translator {
     public static final String templateFile = "charj/translator/Charj.stg";
 
     // variables controlled by command-line arguments
-    public String m_charmc;
-    public boolean m_debug;
-    public boolean m_verbose;
-    public boolean m_errorCondition;
+    private String m_charmc;
+    private boolean m_debug;
+    private boolean m_verbose;
+    private boolean m_errorCondition;
 
     public Translator(
             String _charmc,
@@ -38,6 +38,9 @@ public class Translator {
         m_errorCondition = false;
     }
 
+    public boolean debug()      { return m_debug; }
+    public boolean verbose()    { return m_verbose; }
+
     public static TreeAdaptor adaptor = new CommonTreeAdaptor() {
         public Object create(Token token) {
             return new CharjAST(token);
@@ -228,6 +231,23 @@ public class Translator {
         }
         return templates;
     }
+
+    public File findPackage(String packageName)
+    {
+        // TODO: implement me
+        // turn package name into a file path
+        // look in: current directory, stdlib, user specified directory
+        return null;
+    }
+
+    /** Load a class from disk looking in lib/package
+     *  Side-effect: add class to symtab.
+     */
+    public ClassSymbol loadType(String packageName, String typeName)
+    {
+        // TODO: implement me
+        return null;
+    }
     
     private void error(
             String sourceName, 
diff --git a/src/langs/charj/src/charj/translator/VariableSymbol.java b/src/langs/charj/src/charj/translator/VariableSymbol.java
new file mode 100644 (file)
index 0000000..3be712f
--- /dev/null
@@ -0,0 +1,29 @@
+
+package charj.translator;
+
+/** Represents a variable definition (name,type) in symbol table (a scope 
+ *  thereof)
+ */
+public class VariableSymbol extends Symbol {
+    public boolean isStatic = false;
+    public boolean isConst = false;
+
+    public VariableSymbol(
+            SymbolTable symtab,
+            String name,
+            ClassSymbol type) 
+    {
+        super(symtab, name, type);
+    }
+
+    public String toString() 
+    {
+        StringBuffer buf = new StringBuffer();
+        if ( scope!=null ) {
+            buf.append(scope.getScopeName());
+            buf.append("::");
+        }
+        buf.append(name);
+        return buf.toString();
+    }
+}