GSOC | Extending Common Lisp support

Charles Turner chturne@gmail.com
Sun Jun 17 19:46:00 GMT 2012


On 17 June 2012 19:35, Helmut Eller <eller.helmut@gmail.com> wrote:
> * Charles Turner [2012-06-17 15:06] writes:
>> So then what
>> would export's first parameter be?
>
> The result of (intern "A" "TEST")

Thanks Per & Helmut. I've wasted quite a bit of time having confused
external representations with internal ones, which given last years
project, is rather weird... Ignoring the egregious printer problems, I
have the behaviour I want now:

#|kawa:1|# (make-package 'temp :use nil)
#,(namespace "TEMP")
#|kawa:2|# (use-package 'temp)
t
#|kawa:3|# (intern "TEMP-SYM" 'temp)
{TEMP}:TEMP-SYM ()
#|kawa:4|# (find-symbol "TEMP-SYM")
() ()
#|kawa:5|# (find-symbol "TEMP-SYM" 'temp)
{TEMP}:TEMP-SYM :internal
#|kawa:6|# (multiple-value-bind (s w) (find-symbol "TEMP-SYM" 'temp)
(export s 'temp))
t
#|kawa:7|# (find-symbol "TEMP-SYM")
TEMP-SYM :inherited

I've attached the relevant bits involved in the above example. EXPORT
is currently a bit of monster and may be wrong (but passes test
cases!), I tried to account for the various exceptional situations
mentioned in the hyper spec as well as I could understand them.

>> The symbol 'a whose hashCode would
>> match 'a in test, but not say in an 'a in cl-user?
>
> The hashcode of a symbol should be independent of the package it belongs
> to.  Interning/uninterning symbols or renaming/deleting packages should
> not have any effect on the symbols hashcode.

Of course. Apologies for the confusion!

Charles.
-------------- next part --------------
//This file contains the methods INTERN, FIND-SYMBOL and EXPORT of
//LispPackage

  public static Values intern(String name, LispPackage pkg)
  {
    Values v = pkg.findSymbol(name);
    if (v.get(1) != CommonLisp.FALSE)
    {
      return v;
    }
    else
    {
      Symbol s = Symbol.make(pkg, name);
      s.setNamespace(pkg);
      if (pkg == KeywordNamespace)
      {
        Environment.getCurrent().put(s, s);
        pkg.exported.add(s);
      }
      else
      {
        pkg.add(s);
      }
      return new Values(new Object[] {s, CommonLisp.FALSE});
    }
  }

  public Values findSymbol (Object name)
  {
    String sname;
    
    if (name instanceof Symbol)
      // reader hack. FIXME
      sname = ((Symbol) name).getName().toUpperCase();
    else
      sname = (String) name;
    
    Symbol sym = exported.lookup(sname);
    if (sym != null)
    {
      return new Values(new Object[]
          {
            sym, Keyword.make("external")
          });
    }
    
    sym = lookupInternal(sname, sname.hashCode());
    if (sym != null)
    {
      return new Values(new Object[]
          {
            sym, Keyword.make("internal")
          });
    }    
    
    NamespaceUse U = imported;
    while (U != null)
    {      
      sym = U.imported.exported.lookup(sname);
      
      if (sym != null)
      {
        return new Values(new Object[]
            {
              sym, Keyword.make("inherited")
            });
      }
      
      U = U.nextImported;
    }
    
    return new Values(new Object[]
        {
          CommonLisp.FALSE, CommonLisp.FALSE
        });
  }

  /**
   * Export a list of symbols from a package, checking for conflicts.
   * @param syms the list of symbols to export.
   * @param pkg the package to export the symbols from.
   */
  public static void exportPkg (LList syms, LispPackage pkg)
  {
    Stack<Symbol> validSyms = new Stack<Symbol>();
    Iterator symiter = syms.getIterator();
    Symbol s;
    Values v;

    while (symiter.hasNext())
    {
      s = (Symbol) symiter.next();
      v = pkg.findSymbol(s.getName());
      if (v.get(1) != CommonLisp.FALSE
          && !validSyms.contains(s))
      {
        validSyms.push(s);
      }
    }

    NamespaceUse usedBy = pkg.imported;
    symiter = syms.getIterator();

    while (symiter.hasNext())
    {
      s = (Symbol) symiter.next();
      String sname = s.getName();
      while (usedBy != null)
      {
        v = usedBy.imported.findSymbol(sname);
        if (v.get(1) != CommonLisp.FALSE
            && v.get(0) != s
            && !usedBy.imported.shadowingSymbols.contains(v.get(0)))
        {
          // name conflict in usedBy.imported! Correctable, ask user
          // which name to nuke.
          signal("Name conflict from package " + usedBy.imported + "on symbol" +
                 s);
        }
        usedBy = usedBy.nextImported;
      }
    }

    // Check that all symbols are accessible. If not, ask to import them.
    Stack<Symbol> missing = new Stack<Symbol>();
    // syms accessible in the inheritance chain, but not in this package
    Stack<Symbol> imports = new Stack<Symbol>(); 

    symiter = syms.getIterator();
    while (symiter.hasNext())
    {
      s = (Symbol) symiter.next();
      v = pkg.findSymbol(s.getName());
      if ((v.get(1) == CommonLisp.FALSE) &&
          (!(v.get(0).hashCode() == s.hashCode())))
      {
        missing.push(s);
      }
      else if (v.get(1) == KeywordNamespace.valueOf("inherited"))
      {
        imports.push(s);
      }
    }
    
    if (!missing.isEmpty())
    {
      // correctable error, ask user if they want ot import these
      // missing symbols into the package
      signal("The following symbols are missing: " + missing.toString());
    }
    
    while (!imports.isEmpty())
    {
      pkg.exported.add(imports.pop());
    }
    
    //!! There's a problem here. For a start we should be going thru the
    // list of valid symbols... Second, we should probably be removing the
    // namespace prefix.
    
    while (!validSyms.isEmpty())
    {
      s = validSyms.pop();
      pkg.remove(s); // remove internal
      pkg.exported.add(s); // add to external
    }
  }


More information about the Kawa mailing list