<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>src/xpl/semantic/HashMultiMap.java</filename>
    </added>
    <added>
      <filename>src/xpl/semantic/Selector.java</filename>
    </added>
    <added>
      <filename>src/xpl/semantic/VisibleMethodSelector.java</filename>
    </added>
    <added>
      <filename>src/xpl/semantic/VisibleSymbolSelector.java</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -170,6 +170,7 @@
 
     &lt;delete&gt;
       &lt;fileset dir=&quot;${classes}&quot; includes=&quot;**/*.class&quot;/&gt;
+      &lt;fileset dir=&quot;${tests-integration}&quot; includes=&quot;**/*.class&quot;/&gt;
     &lt;/delete&gt;
 
     &lt;delete file=&quot;${src-xpl}/XplLexer.java&quot;/&gt;</diff>
      <filename>build.xml</filename>
    </modified>
    <modified>
      <diff>@@ -30,6 +30,22 @@ options {
         errors.add(&quot;Line &quot; + line + &quot;: &quot; + message);
         throw new RecognitionException(input);
     }
+
+    public Method findMatchingMethod(String name, Type[] callSignature) {
+        List&lt;Symbol&gt; methods  = symbolTable.findMethods(name, callSignature.length);
+
+        lookup:
+        for(Symbol sym : methods) {
+            Method tried = (Method) sym;
+            Type[] desiredTypes = tried.getArgumentTypes();
+            for(int i = 0; i &lt; desiredTypes.length; i++)
+                if(!desiredTypes[i].equals(callSignature[i]))
+                    continue lookup;
+            return tried;
+        }
+
+        return null;
+    }
 }
 
 program
@@ -43,7 +59,7 @@ atomic_operation
     :  (conditional | loop | variable_definition | assignment | expression | return_expression);
 
 method_definition
-@after { symbolTable.exitFrame(); }
+@after { symbolTable.exitScope(); }
     :  ^(METHOD method_header ^(PROGN (atomic_operation | method_definition)+)) {
             ((MethodNode)$start).setMethod($method_header.method);
         };
@@ -59,13 +75,13 @@ method_header returns [Method method]
                 TypeNode typeNode = (TypeNode) $types.get(i);
 
                 Type type = typeNode.getRepresentedType();
-                arguments.add(new Argument(type, idNode.getText(), i+1));
+                arguments.add(new Argument(symbolTable.getCurrentScopeId(), type, idNode.getText(), i+1));
                 argumentTypes[i] = type;
             }
 
-            Method method = new Method(returnTypeNode.getRepresentedType(), $name.text, argumentTypes);
+            Method method = new Method(symbolTable.getCurrentScopeId(), returnTypeNode.getRepresentedType(), $name.text, argumentTypes);
             symbolTable.put(method);
-            symbolTable.enterNewFrame();
+            symbolTable.enterScope();
             for(Argument arg : arguments)
                 symbolTable.put(arg);
             $method = method;
@@ -91,7 +107,7 @@ variable_definition
             if(!lType.equals(rType))
               error(input, $name.line, &quot;the declared type isn't the same as the r-value type&quot;);
 
-            Variable variable = new Variable(lType, $name.text, variableId++);
+            Variable variable = new Variable(symbolTable.getCurrentScopeId(), lType, $name.text, variableId++);
             symbolTable.put(variable);
             ((VariableNode)$name).setVariable(variable);
         };
@@ -111,50 +127,38 @@ expression
             };
 
 boolean_expression
-    :  ^(('&amp;&amp;' | '||') a=boolean_expression b=boolean_expression)
+    :  ^(('&amp;&amp;' | '||') a=boolean_expression b=boolean_expression) {
+            TypeChecker.infer($start, $a.start, $b.start);
+        }
     |  comparision_expression {
-                $start.setNodeType($comparision_expression.start.getNodeType());
-            }
+            $start.setNodeType($comparision_expression.start.getNodeType());
+        }
     ;
 
 comparision_expression
-    :  ^(('==' | '&lt;=' | '&gt;=' | '&lt;' | '&gt;') a=binary_expression b=binary_expression)
+    :  ^(('==' | '&lt;=' | '&gt;=' | '&lt;' | '&gt;') a=binary_expression b=binary_expression) {
+            TypeChecker.infer($start, $a.start, $b.start);
+        }
     |  binary_expression {
-                $start.setNodeType($binary_expression.start.getNodeType());
-            }
-    |  addition {
-                $start.setNodeType($addition.start.getNodeType());
-            }
+            $start.setNodeType($binary_expression.start.getNodeType());
+        }
     ;
 
 binary_expression
-    :  ^(('-' | '*' | '/' | '%') a=binary_expression b=binary_expression) {
+    :  addition {
+            $start.setNodeType($addition.start.getNodeType());
+        }
+    |  ^(('-' | '*' | '/' | '%') a=binary_expression b=binary_expression) {
             TypeChecker.infer($start, $a.start, $b.start);
         }
-    | '(' expr=binary_expression ')' {
+    |  '(' expr=binary_expression ')' {
             $start.setNodeType($expr.start.getNodeType());
         }
-    | atom {
+    |  atom {
             $start.setNodeType($atom.start.getNodeType());
         }
     ;
 
-atom
-    :  NUMBER {
-            $NUMBER.setNodeType(Types.Integer);
-        }
-    |  STRING {
-            $STRING.setNodeType(Types.String);
-        }
-    |  IDENTIFIER {
-            Identifier identifier = symbolTable.findIdentifier($IDENTIFIER.text);
-            if(identifier != null)
-                $IDENTIFIER.setNodeType(identifier.getType());
-            ((IdentifierNode)$IDENTIFIER).setIdentifier(identifier);
-        }
-    |  call
-    ;
-
 addition
     :  ^('+' a=addition_flatten b=addition_flatten) {
             TypeChecker.infer($start, $a.start, $b.start);
@@ -172,15 +176,43 @@ addition_flatten
     |  binary_expression -&gt; binary_expression
     ;
 
+atom
+    :  NUMBER {
+            $NUMBER.setNodeType(Types.Integer);
+        }
+    |  STRING {
+            $STRING.setNodeType(Types.String);
+        }
+    |  IDENTIFIER {
+            Identifier identifier = symbolTable.findIdentifier($IDENTIFIER.text);
+            if(identifier != null)
+                $IDENTIFIER.setNodeType(identifier.getType());
+            ((IdentifierNode)$IDENTIFIER).setIdentifier(identifier);
+        }
+    |  call
+    ;
+
 return_expression
     :  ^(RETURN expression)
     ;
 
 call
-    :  ^(CALL IDENTIFIER ^(CALL_ARGUMENTS expression+)) {
-            Method method  = symbolTable.findMethod($IDENTIFIER.text);
-            MethodNode node = ((MethodNode)$start);
-            node.setMethod(method);
-            node.setNodeType(method.getReturnType());
+    :  ^(CALL IDENTIFIER ^(CALL_ARGUMENTS (args+=expression)+)) {
+          Type[] callSignature = new Type[$args.size()];
+          for(int i = 0; i &lt; $args.size(); i++) {
+            ASTNode node = (ASTNode)$args.get(i);
+            callSignature[i] = node.getNodeType();
+          }
+
+          Method method = findMatchingMethod($IDENTIFIER.text, callSignature);
+
+          if(method == null) {
+            error(input, $IDENTIFIER.line, &quot;no method &quot; + $IDENTIFIER.text + &quot; with this signature&quot;);
+            return null;
+          }
+
+          MethodNode node = ((MethodNode)$start);
+          node.setMethod(method);
+          node.setNodeType(method.getReturnType());
         }
     ;</diff>
      <filename>src/xpl/semantic/SemanticAnalysis.g</filename>
    </modified>
    <modified>
      <diff>@@ -1,100 +1,112 @@
 package xpl.semantic;
 
-import xpl.semantic.symbols.*;
-
 import java.util.*;
 
+import xpl.semantic.symbols.*;
+
 /**
  * The symbol table is used during semantic analysis to store
- * informations about encountered symbols, and provide you with those
- * informations later on when you're encountering the symbols defined
- * previously. Currently it uses a linked list of Frames for storing
- * symbols, through another approach will be needed for implementing
- * method overloading.
+ * informations about encountered symbols, and provide you with them
+ * later on when you're encountering the symbols that were defined
+ * previously. The current implemenation is loosely based on the
+ * seminal paper by LeBlanc and Cook - &quot;A Symbol Table Abstraction to
+ * Implement Languages with Explicit Scope Control&quot;
  *
  * @author Jaros&#322;aw Rzesz&#243;tko
  */
-
 public class SymbolTable {
   /**
-   * Creates a new symbol table populated with the globally available
-   * methods from the Runtime class
+   * Constructs an empty symbol table and populates it with the
+   * globally available runtime methods
    */
   public SymbolTable() {
-    enterNewFrame();
+    enterScope();
 
-    current.put(&quot;puts&quot;,  new Method(Types.Void,    &quot;puts&quot;,  new Type[] { Types.String  }, true));
-    current.put(&quot;print&quot;, new Method(Types.Void,    &quot;print&quot;, new Type[] { Types.Integer }, true));
-    current.put(&quot;power&quot;, new Method(Types.Integer, &quot;power&quot;, new Type[] { Types.Integer, Types.Integer }, true));
+    put(new Method(0, Types.Void,    &quot;puts&quot;,  new Type[] { Types.String  }, true));
+    put(new Method(0, Types.Void,    &quot;print&quot;, new Type[] { Types.Integer }, true));
+    put(new Method(0, Types.Integer, &quot;power&quot;, new Type[] { Types.Integer, Types.Integer }, true));
   }
 
-  private ArrayList&lt;Frame&gt; frames = new ArrayList&lt;Frame&gt;();
-
-  private Frame current = null;
+  /**
+   * Creates a new scope and enters it
+   * @param scopeId The id to give to the newly created scope
+   */
+  public void enterScope() {
+    scopes.push(new Integer(++currentScopeId));
+  }
 
   /**
-   * Find an Identifier symbol, meaning either a (method) Argument or a
-   * Variable, in the current scope
-   *
-   * @param name The name of the identifier
+   * Exits from the current scope, returning its id
    */
-  public Identifier findIdentifier(String name) {
-    return current.find(name, Identifier.class);
+  public int exitScope() {
+    return scopes.pop();
   }
 
   /**
-   * Find an Argument symbol
-   *
-   * @param name The name of the argument
+   * Returns the id of the current scope, needed for symbol creation.
    */
-  public Argument findArgument(String name) {
-    return current.find(name, Argument.class);
+  public int getCurrentScopeId() {
+    return currentScopeId;
   }
 
   /**
-   * Find a Variable symbol
+   * Add a symbol to the current scope
    *
-   * @param name The name of the variable
+   * @param symbol The symbol to add
    */
-  public Variable findVariable(String name) {
-    return current.find(name, Variable.class);
+  public void put(Symbol symbol) {
+    symbols.put(symbol.getName(), symbol);
   }
 
   /**
-   * Find a Method symbol
+   * Finds the symbol represting the innermost definition of the given
+   * identifier (representing an argument or local variable)
    *
-   * @param name The name of the variable
+   * @param name The name of the sought identifier
    */
-  public Method findMethod(String name) {
-    return current.find(name, Method.class);
+  public Identifier findIdentifier(String name) {
+    return (Identifier) symbols.get(name, symbolSelector.withType(Identifier.class));
   }
 
   /**
-   * Put a new symbol in the current frame
+   * Finds the symbol represting the innermost definition of the given
+   * method argument
    *
-   * @param sym The new symbol
+   * @param name The name of the argument
    */
-  public void put(Symbol sym) {
-    current.put(sym.getName(), sym);
+  public Argument findArgument(String name) {
+    return (Argument) symbols.get(name, symbolSelector.withType(Argument.class));
   }
 
   /**
-   * Creates a new frame with the current frame as it parent and makes
-   * it the new current frame.
+   * Finds the symbol represting the innermost definition of the given
+   * variable
+   *
+   * @param name The name of the variable
    */
-  public void enterNewFrame() {
-    current = new Frame(current);
-    frames.add(current);
+  public Variable findVariable(String name) {
+    return (Variable) symbols.get(name, symbolSelector.withType(Variable.class));
   }
 
   /**
-   * Makes the parent of the current frame the new current frame
+   * Finds all methods with a given name and arity (the number of
+   * parameters) returning them in a list, with the innermost
+   * definition first
+   *
+   * @param name The name of the variable
+   * @param arity The number of arguments of the looked up method
    */
-  public void exitFrame()  {
-    current = current.getParent();
+  public List&lt;Symbol&gt; findMethods(String name, int arity) {
+    return symbols.getAll(name, methodSelector.withArity(arity));
   }
 
-  public String toString() {
-    return current.toString();
-  }
+  private Stack&lt;Integer&gt; scopes = new Stack&lt;Integer&gt;();
+
+  private HashMultiMap&lt;String, Symbol&gt; symbols = new HashMultiMap&lt;String, Symbol&gt;();
+
+  private VisibleSymbolSelector symbolSelector = new VisibleSymbolSelector(scopes);
+
+  private VisibleMethodSelector methodSelector = new VisibleMethodSelector(scopes);
+
+  private int currentScopeId = -1;
 }</diff>
      <filename>src/xpl/semantic/SymbolTable.java</filename>
    </modified>
    <modified>
      <diff>@@ -3,8 +3,8 @@ package xpl.semantic.symbols;
 import xpl.semantic.Type;
 
 public class Argument extends Identifier {
-  public Argument(Type type, String name, int id) {
-    super(type, name);
+  public Argument(int scopeId, Type type, String name, int id) {
+    super(scopeId, type, name);
     this.id = id;
   }
 </diff>
      <filename>src/xpl/semantic/symbols/Argument.java</filename>
    </modified>
    <modified>
      <diff>@@ -3,8 +3,8 @@ package xpl.semantic.symbols;
 import xpl.semantic.Type;
 
 public abstract class Identifier extends Symbol {
-  public Identifier(Type type, String name) {
-    super(name);
+  public Identifier(int scopeId, Type type, String name) {
+    super(scopeId, name);
     this.type = type;
   }
 </diff>
      <filename>src/xpl/semantic/symbols/Identifier.java</filename>
    </modified>
    <modified>
      <diff>@@ -3,14 +3,14 @@ package xpl.semantic.symbols;
 import xpl.semantic.Type;
 
 public class Method extends Symbol {
-  public Method(Type returnType, String name, Type[] argumentTypes) {
-    super(name);
+  public Method(int scopeId, Type returnType, String name, Type[] argumentTypes) {
+    super(scopeId, name);
     this.returnType    = returnType;
     this.argumentTypes = argumentTypes;
   }
 
-  public Method(Type returnType, String name, Type[] argumentTypes, boolean builtin) {
-    this(returnType, name, argumentTypes);
+  public Method(int scopeId, Type returnType, String name, Type[] argumentTypes, boolean builtin) {
+    this(scopeId, returnType, name, argumentTypes);
     this.builtin = builtin;
   }
 
@@ -21,6 +21,7 @@ public class Method extends Symbol {
   public  Type   getReturnType() { return returnType; }
 
   private Type[] argumentTypes;
+  public  Type[] getArgumentTypes() { return argumentTypes; }
   public  int    getArity() { return argumentTypes.length; }
 
   public String getArgumentsSignature() {</diff>
      <filename>src/xpl/semantic/symbols/Method.java</filename>
    </modified>
    <modified>
      <diff>@@ -5,10 +5,14 @@ import xpl.semantic.Type;
 public abstract class Symbol {
   public Symbol() {}
 
-  public Symbol(String name) {
-    this.name = name;
+  public Symbol(int scopeId, String name) {
+    this.scopeId = scopeId;
+    this.name    = name;
   }
 
   protected String name;
-  public String getName() { return name; }
+  public    String getName() { return name; }
+
+  protected int scopeId;
+  public    int getScopeId() { return scopeId; }
 }</diff>
      <filename>src/xpl/semantic/symbols/Symbol.java</filename>
    </modified>
    <modified>
      <diff>@@ -3,8 +3,8 @@ package xpl.semantic.symbols;
 import xpl.semantic.Type;
 
 public class Variable extends Identifier {
-  public Variable(Type type, String name, int id) {
-    super(type, name);
+  public Variable(int scopeId, Type type, String name, int id) {
+    super(scopeId, type, name);
     this.variableId = &quot;variable&quot; + id;
   }
 </diff>
      <filename>src/xpl/semantic/symbols/Variable.java</filename>
    </modified>
    <modified>
      <diff>@@ -4,12 +4,14 @@ import static org.junit.Assert.*;
 import xpl.semantic.*;
 import xpl.semantic.symbols.*;
 
+import java.util.*;
+
 public class SymbolTableTest {
   @Test
   public void storesArguments() {
     SymbolTable table = new SymbolTable();
 
-    Argument argument = new Argument(Types.Integer, &quot;foobar&quot;, 1);
+    Argument argument = new Argument(table.getCurrentScopeId(), Types.Integer, &quot;foobar&quot;, 1);
     table.put(argument);
 
     Argument found = table.findArgument(&quot;foobar&quot;);
@@ -20,7 +22,7 @@ public class SymbolTableTest {
   public void storesLocalVariables() {
     SymbolTable table = new SymbolTable();
 
-    Variable variable = new Variable(Types.Integer, &quot;foobar&quot;, 0);
+    Variable variable = new Variable(table.getCurrentScopeId(), Types.Integer, &quot;foobar&quot;, 0);
     table.put(variable);
 
     Variable found = table.findVariable(&quot;foobar&quot;);
@@ -31,24 +33,28 @@ public class SymbolTableTest {
   public void storesMethods() {
     SymbolTable table = new SymbolTable();
 
-    Method method = new Method(Types.Integer, &quot;foobar&quot;, new Type[] { Types.Integer, Types.Integer, Types.Integer });
+    Method method = new Method(table.getCurrentScopeId(), Types.Integer, &quot;foobar&quot;, new Type[] { Types.Integer, Types.Integer, Types.Integer });
     table.put(method);
 
-    Method found = table.findMethod(&quot;foobar&quot;);
-    assertEquals(method, found);
+    List&lt;Symbol&gt; found = table.findMethods(&quot;foobar&quot;, 3);
+    assertEquals(1, found.size());
+    assertEquals(method, (Method) found.get(0));
   }
 
   @Test
   public void ignoresItemsOfDifferentTypeWhenLookingUpSymbols() {
-    SymbolTable   table    = new SymbolTable();
-    Method        method   = new Method(Types.Integer, &quot;foobar&quot;, new Type[] { Types.Integer, Types.Integer, Types.Integer });
-    Variable      variable = new Variable(Types.Integer, &quot;foobar&quot;, 0);
+    SymbolTable table = new SymbolTable();
 
+    Method method = new Method(table.getCurrentScopeId(), Types.Integer, &quot;foobar&quot;, new Type[] { Types.Integer, Types.Integer, Types.Integer });
     table.put(method);
-    table.enterNewFrame();
+
+    table.enterScope();
+
+    Variable variable = new Variable(table.getCurrentScopeId(), Types.Integer, &quot;foobar&quot;, 0);
     table.put(variable);
 
-    Method found = table.findMethod(&quot;foobar&quot;);
-    assertEquals(method, found);
+    List&lt;Symbol&gt; found = table.findMethods(&quot;foobar&quot;, 3);
+    assertEquals(method, (Method)found.get(0));
+    assertEquals(1, found.size());
   }
 }</diff>
      <filename>tests/unit/SymbolTableTest.java</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>src/xpl/semantic/Frame.java</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>92fb74a3f630d36454b330f2709adbd7b546000d</id>
    </parent>
  </parents>
  <author>
    <name>sztywny</name>
    <email>sztywny@gmail.com</email>
  </author>
  <url>http://github.com/sztywny/xpl/commit/3d5caf424976755cc950b536ca3e6f1b66733b6b</url>
  <id>3d5caf424976755cc950b536ca3e6f1b66733b6b</id>
  <committed-date>2008-11-17T00:16:48-08:00</committed-date>
  <authored-date>2008-11-17T00:16:48-08:00</authored-date>
  <message>Rewriting the symbol table from scratch with a new design, the semantic analysis is now more exact and decorates more expressions with types - all in preparation for method overloading. Breaks the tests.</message>
  <tree>053c1c6a58f5055d03c5cf552c49bc7f58b6caf6</tree>
  <committer>
    <name>sztywny</name>
    <email>sztywny@gmail.com</email>
  </committer>
</commit>
