| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| \* */ | ||
|
|
||
| // $Id$ | ||
|
|
||
| package scalac.ast.printer; | ||
|
|
||
| import java.io.OutputStream; | ||
|
|
||
| import scalac.Unit; | ||
| import scalac.ast.Tree; | ||
|
|
||
| /** | ||
| * Interface for all abstract tree printers. | ||
| * | ||
| * @author Michel Schinz | ||
| * @version 1.0 | ||
| */ | ||
| public interface TreePrinter { | ||
| public void begin(); | ||
| public void end(); | ||
| public void flush(); | ||
|
|
||
| public void beginSection(int level, String title); | ||
|
|
||
| public void print(Unit unit); | ||
|
|
||
| public TreePrinter print(Tree tree); | ||
| public TreePrinter print(String str); | ||
| public TreePrinter println(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| \* */ | ||
|
|
||
| // $Id$ | ||
|
|
||
| package scalac.checkers; | ||
|
|
||
| import scalac.util.*; | ||
| import scalac.ast.*; | ||
| import scalac.symtab.*; | ||
| import scalac.Global; | ||
| import scalac.util.Debug; | ||
| import Tree.*; | ||
|
|
||
| /** | ||
| * Check that the owner of symbols is set correctly. | ||
| * | ||
| * @author Michel Schinz | ||
| * @version 1.0 | ||
| */ | ||
|
|
||
| public class CheckOwners extends Checker { | ||
| protected Symbol currentOwner; | ||
|
|
||
| public CheckOwners(Global global) { | ||
| super(global); | ||
| currentOwner = global.definitions.ROOT_CLASS; | ||
| } | ||
|
|
||
| protected void traverse(Tree tree, Symbol owner) { | ||
| Symbol prevOwner = currentOwner; | ||
| currentOwner = owner; | ||
| traverse(tree); | ||
| currentOwner = prevOwner; | ||
| } | ||
|
|
||
| protected void traverse(Tree[] array, Symbol owner) { | ||
| Symbol prevOwner = currentOwner; | ||
| currentOwner = owner; | ||
| traverse(array); | ||
| currentOwner = prevOwner; | ||
| } | ||
|
|
||
| protected void traverse(Tree[][] array, Symbol owner) { | ||
| Symbol prevOwner = currentOwner; | ||
| currentOwner = owner; | ||
| traverse(array); | ||
| currentOwner = prevOwner; | ||
| } | ||
|
|
||
| protected void traverse(Template templ, Symbol owner) { | ||
| Symbol prevOwner = currentOwner; | ||
| if (owner.kind == Kinds.CLASS) | ||
| currentOwner = owner.constructor(); | ||
| traverse(templ.parents); | ||
| currentOwner = owner; | ||
|
|
||
| Symbol templSymbol = templ.symbol(); | ||
| Tree[] body = templ.body; | ||
| for (int i = 0; i < body.length; ++i) { | ||
| switch (body[i]) { | ||
| case PackageDef(_,_): | ||
| case ClassDef(_,_,_,_,_,_): | ||
| case ModuleDef(_,_,_,_): | ||
| case DefDef(_,_,_,_,_,_): | ||
| case ValDef(_,_,_,_): | ||
| case TypeDef(_,_,_,_): | ||
| traverse(body[i], owner); | ||
| break; | ||
| default: | ||
| traverse(body[i], templSymbol); | ||
| } | ||
| } | ||
|
|
||
| currentOwner = prevOwner; | ||
| } | ||
|
|
||
| protected void checkOwner(Tree tree, Symbol sym) { | ||
| Symbol owner = sym.owner(); | ||
| verify(tree, | ||
| owner == currentOwner, | ||
| "owner", | ||
| "incorrect owner for " + Debug.toString(sym) + ":\n" | ||
| + " found: " + Debug.toString(owner) + "\n" | ||
| + " required: " + Debug.toString(currentOwner)); | ||
| } | ||
|
|
||
| public void traverse(Tree tree) { | ||
| switch(tree) { | ||
| case PackageDef(Tree packaged, Template impl): | ||
| check(tree); | ||
| traverse(packaged); | ||
| traverse(impl, packaged.symbol()); | ||
| break; | ||
|
|
||
| case ClassDef(int mods, | ||
| Name name, | ||
| TypeDef[] tparams, | ||
| ValDef[][] vparams, | ||
| Tree tpe, | ||
| Template impl): { | ||
| check(tree); | ||
| traverse(tparams, tree.symbol()); | ||
| traverse(vparams, tree.symbol()); | ||
| traverse(tpe); | ||
| traverse(impl, tree.symbol()); | ||
| } break; | ||
|
|
||
| case ModuleDef(int mods, Name name, Tree tpe, Template impl): { | ||
| check(tree); | ||
| traverse(tpe); | ||
| traverse(impl, tree.symbol()); | ||
| } break; | ||
|
|
||
| case DefDef(int mods, | ||
| Name name, | ||
| TypeDef[] tparams, | ||
| ValDef[][] vparams, | ||
| Tree tpe, | ||
| Tree rhs): { | ||
| check(tree); | ||
| traverse(tparams, tree.symbol()); | ||
| traverse(vparams, tree.symbol()); | ||
| traverse(tpe, tree.symbol()); | ||
| traverse(rhs, tree.symbol()); | ||
| } break; | ||
|
|
||
| case ValDef(int mods, Name name, Tree tpe, Tree rhs): { | ||
| check(tree); | ||
| traverse(tpe); | ||
| traverse(rhs, tree.symbol()); | ||
| } break; | ||
|
|
||
| case TypeDef(int mods, Name name, TypeDef[] tparams, Tree rhs): { | ||
| check(tree); | ||
| traverse(tparams, tree.symbol()); | ||
| traverse(rhs, tree.symbol()); | ||
| } break; | ||
|
|
||
| default: | ||
| super.traverse(tree); | ||
| } | ||
| } | ||
|
|
||
| public void check(Tree tree) { | ||
| switch (tree) { | ||
| case PackageDef(_,_): | ||
| case ClassDef(_,_,_,_,_,_): | ||
| case ModuleDef(_,_,_,_): | ||
| case DefDef(_,_,_,_,_,_): | ||
| case ValDef(_,_,_,_): | ||
| case TypeDef(_,_,_,_): { | ||
| Symbol sym = tree.symbol(); | ||
| if (sym != null && sym != Symbol.NONE) { | ||
| checkOwner(tree, sym); | ||
| if (sym.kind == Kinds.CLASS) | ||
| checkOwner(tree, sym.constructor()); | ||
| } | ||
| } break; | ||
|
|
||
| default: | ||
| ; // nothing to do | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| \* */ | ||
|
|
||
| // $Id$ | ||
|
|
||
| package scalac.checkers; | ||
|
|
||
| import scalac.ast.Tree; | ||
| import scalac.symtab.Symbol; | ||
| import scalac.Global; | ||
|
|
||
| /** | ||
| * Verify that all tree nodes for which hasSymbol() is true have a | ||
| * non-null symbol. | ||
| * | ||
| * @author Michel Schinz | ||
| * @version 1.0 | ||
| */ | ||
|
|
||
| public class CheckSymbols extends Checker { | ||
| public CheckSymbols(Global global) { super(global); } | ||
|
|
||
| public void check(Tree tree) { | ||
| verify(tree, | ||
| implies(tree.hasSymbol(), tree.symbol() != null), | ||
| "symbol not null", | ||
| "hasSymbol => symbol not null"); | ||
| verify(tree, | ||
| implies(tree.hasSymbol(), tree.symbol() != Symbol.NONE), | ||
| "symbol not NONE", | ||
| "hasSymbol => symbol not NONE"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| \* */ | ||
|
|
||
| // $Id$ | ||
|
|
||
| package scalac.checkers; | ||
|
|
||
| import scalac.ast.Tree; | ||
| import scalac.util.Name; | ||
| import scalac.symtab.Type; | ||
| import scalac.Global; | ||
| import scalac.util.Debug; | ||
|
|
||
| /** | ||
| * Check that all tree nodes have a type. | ||
| * | ||
| * @author Michel Schinz | ||
| * @version 1.0 | ||
| */ | ||
|
|
||
| public class CheckTypes extends Checker { | ||
| public CheckTypes(Global global) { super(global); } | ||
|
|
||
| public void check(Tree tree) { | ||
| verify(tree, tree.type != null, "non-null type", "type of tree is not null"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| \* */ | ||
|
|
||
| // $Id$ | ||
|
|
||
| package scalac.checkers; | ||
|
|
||
| import scalac.ast.*; | ||
| import scalac.Global; | ||
|
|
||
| public abstract class Checker extends Traverser { | ||
| protected final Global global; | ||
|
|
||
| public Checker(Global global) { | ||
| this.global = global; | ||
| } | ||
|
|
||
| public boolean implies(boolean b1, boolean b2) { | ||
| return (!b1) | b2; | ||
| } | ||
|
|
||
| public void verify(Tree tree, boolean b, String name, String message) { | ||
| if (! b) { | ||
| System.err.println("ERROR: Condition '" + name + "' violated (after " | ||
| + global.currentPhase + ")!"); | ||
| System.err.println(message); | ||
| global.debugPrinter.print(tree); | ||
| System.err.println(); | ||
| } | ||
| } | ||
|
|
||
| abstract public void check(Tree tree); | ||
|
|
||
| public void traverse(Tree tree) { | ||
| check(tree); | ||
| super.traverse(tree); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab; | ||
|
|
||
|
|
||
| public interface Kinds { | ||
|
|
||
| /** kind of error symbol | ||
| */ | ||
| int ERROR = 0; | ||
|
|
||
| /** kind of non-existent symbol | ||
| */ | ||
| int NONE = 1; | ||
|
|
||
| /** definition kinds | ||
| */ | ||
| int ALIAS = 2; | ||
| int CLASS = 3; | ||
| int TYPE = 4; | ||
| int VAL = 5; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab; | ||
|
|
||
| public interface Modifiers { | ||
|
|
||
| // modifiers | ||
| int ABSTRACT = 0x00000001; | ||
| int FINAL = 0x00000002; | ||
| int PRIVATE = 0x00000004; | ||
| int PROTECTED = 0x00000008; | ||
|
|
||
| int QUALIFIED = 0x00000010; | ||
| int OVERRIDE = 0x00000020; | ||
| int CASE = 0x00000040; | ||
| int ABSTRACTCLASS = 0x00000080; // abstract class | ||
|
|
||
| int DEF = 0x00000100; // a def parameter | ||
| int SYNTHETIC = 0x00000200; | ||
| int DEPRECATED = 0x00000400; | ||
| int JAVA = 0x00000800; // symbol was defined by a Java class | ||
|
|
||
| int MODUL = 0x00001000; // symbol is module or class implementing a module | ||
| int MUTABLE = 0x00002000; // symbol is a mutable variable. | ||
| int PARAM = 0x00004000; // symbol is a (type) parameter to a method | ||
|
|
||
| int INITIALIZED = 0x00010000; // symbol's definition is complete | ||
| int LOCKED = 0x00020000; // temporary flag to catch cyclic dependencies | ||
| int ACCESSED = 0x00040000; // symbol was accessed at least once | ||
| int SELECTOR = 0x00080000; // symbol was used as selector in Select | ||
|
|
||
| int PACKAGE = 0x00100000; // symbol is a java packages. | ||
| int LABEL = 0x00200000; // symbol is a label symbol | ||
| int STATIC = 0x00400000; // "static" inner classes (i.e. after class norm.) | ||
| int STABLE = 0x00800000; // functions that are assumed to be stable | ||
| // (typically, access methods for valdefs) | ||
|
|
||
| int CAPTURED = 0x01000000; // variables is accessed from nested function. | ||
|
|
||
| int ACCESSOR = 0x04000000; // function is an access function for a | ||
| // value or variable | ||
| int BRIDGE = 0x0800000; // function is a bridge method. | ||
|
|
||
| int INTERFACE = 0x10000000; // symbol is a Java interface | ||
| int TRAIT = 0x20000000; // symbol is a Trait | ||
|
|
||
| int SNDTIME = 0x40000000; //debug | ||
|
|
||
| // masks | ||
| int SOURCEFLAGS = 0x00000077 | PARAM | TRAIT; // these modifiers can be set in source programs. | ||
| int ACCESSFLAGS = PRIVATE | PROTECTED; | ||
|
|
||
| public static class Helper { | ||
|
|
||
| public static boolean isAbstract(int flags) { | ||
| return (flags & (ABSTRACT | ABSTRACTCLASS)) != 0; | ||
| } | ||
|
|
||
| public static boolean isFinal(int flags) { | ||
| return (flags & FINAL) != 0; | ||
| } | ||
|
|
||
| public static boolean isPrivate(int flags) { | ||
| return (flags & PRIVATE) != 0; | ||
| } | ||
|
|
||
| public static boolean isProtected(int flags) { | ||
| return (flags & PROTECTED) != 0; | ||
| } | ||
|
|
||
| public static boolean isQualified(int flags) { | ||
| return (flags & QUALIFIED) != 0; | ||
| } | ||
|
|
||
| public static boolean isOverride(int flags) { | ||
| return (flags & OVERRIDE) != 0; | ||
| } | ||
|
|
||
| public static boolean isCase(int flags) { | ||
| return (flags & CASE) != 0; | ||
| } | ||
|
|
||
| public static boolean isInterface(int flags) { | ||
| return (flags & INTERFACE) != 0; | ||
| } | ||
|
|
||
| public static boolean isDef(int flags) { | ||
| return (flags & DEF) != 0; | ||
| } | ||
|
|
||
| public static boolean isModClass(int flags) { | ||
| return (flags & MODUL) != 0; | ||
| } | ||
|
|
||
| public static boolean isStatic(int flags) { | ||
| return (flags & STATIC) != 0; | ||
| } | ||
|
|
||
| public static boolean isJava(int flags) { | ||
| return (flags & JAVA) != 0; | ||
| } | ||
|
|
||
| public static boolean isNoVal(int flags) { | ||
| return (flags & PACKAGE) != 0; | ||
| } | ||
|
|
||
| public static String toString(int flags) { | ||
| StringBuffer buffer = new StringBuffer(); | ||
| toString(buffer, flags); | ||
| return buffer.toString(); | ||
| } | ||
|
|
||
| public static void toString(StringBuffer buffer, int flags) { | ||
| //buffer.append(flags).append(": ");//debug | ||
| int marker = buffer.length(); | ||
| if (isPrivate(flags)) buffer.append("private "); | ||
| if (isProtected(flags)) buffer.append("protected "); | ||
| if (isAbstract(flags)) buffer.append("abstract "); | ||
| if (isFinal(flags)) buffer.append("final "); | ||
| if (isQualified(flags)) buffer.append("qualified "); | ||
| if (isInterface(flags)) buffer.append("interface "); | ||
| if (isCase(flags)) buffer.append("case "); | ||
| if (isDef(flags)) buffer.append("def "); | ||
| if (isOverride(flags)) buffer.append("override "); | ||
| int length = buffer.length(); | ||
| buffer.setLength(length - (length == marker ? 0 : 1)); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab; | ||
|
|
||
| import scalac.util.Name; | ||
| import java.util.HashMap; | ||
|
|
||
| public class NameMangler { | ||
|
|
||
| private HashMap/*<Symbol,HashMap<Symbol,int[]>>*/ mangleMap = new HashMap(); | ||
|
|
||
| public void setMangledName(Symbol innerclazz) { | ||
| Symbol topclazz = innerclazz.enclToplevelClass(); | ||
| HashMap map = (HashMap) mangleMap.get(topclazz); | ||
| if (map == null) { | ||
| map = new HashMap(); | ||
| mangleMap.put(topclazz, map); | ||
| } | ||
| int[] ctr = (int[]) map.get(innerclazz); | ||
| if (ctr == null) { | ||
| ctr = new int[1]; | ||
| map.put(innerclazz, ctr); | ||
| } | ||
| innerclazz.setMangledName( | ||
| Name.fromString(topclazz.name + "$" + (ctr[0]++) + innerclazz.name)); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,306 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab; | ||
|
|
||
| import scalac.util.*; | ||
| import scalac.ApplicationError; | ||
|
|
||
| public class Scope { | ||
|
|
||
| public static abstract class SymbolIterator { | ||
| public abstract boolean hasNext(); | ||
| public abstract Symbol next(); | ||
| } | ||
|
|
||
| /** A symbol iterator that returns all alternatives of an overloaded symbol | ||
| * instead of the overloaded symbol itself. | ||
| */ | ||
| public static class UnloadIterator extends SymbolIterator { | ||
| private SymbolIterator iterator; | ||
| private Symbol[] alternatives; | ||
| private int index; | ||
|
|
||
| public UnloadIterator(SymbolIterator iterator) { | ||
| this.iterator = iterator; | ||
| this.alternatives = null; | ||
| this.index = -1; | ||
| } | ||
|
|
||
| public boolean hasNext() { | ||
| return index >= 0 || iterator.hasNext(); | ||
| } | ||
| public Symbol next() { | ||
| if (index >= 0) { | ||
| Symbol symbol = alternatives[index++]; | ||
| if (index == alternatives.length) { | ||
| alternatives = null; | ||
| index = -1; | ||
| } | ||
| return symbol; | ||
| } else { | ||
| Symbol symbol = iterator.next(); | ||
| switch (symbol.type()) { | ||
| case OverloadedType(Symbol[] alts, _): | ||
| alternatives = alts; | ||
| index = 0; | ||
| return next(); | ||
| default: | ||
| return symbol; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static class Entry { | ||
|
|
||
| /** the absent entry | ||
| */ | ||
| public static final Entry NONE = new Entry(); | ||
|
|
||
| /** the symbol of the entry (this is the symbol containing the name) | ||
| */ | ||
| public Symbol sym; | ||
|
|
||
| /** the next entry in the hash bucket | ||
| */ | ||
| Entry tail; | ||
|
|
||
| /** the next entry in this scope | ||
| */ | ||
| public Entry next; | ||
|
|
||
| /** The owner of the entry; | ||
| */ | ||
| public Scope owner; | ||
|
|
||
| Entry(Symbol sym, Scope owner) { | ||
| if (sym == null) throw new ApplicationError(); | ||
| this.sym = sym; | ||
| this.owner = owner; | ||
| this.next = owner.elems; | ||
| owner.elems = this; | ||
| } | ||
|
|
||
| private Entry() { | ||
| this.sym = Symbol.NONE; | ||
| } | ||
|
|
||
| public Entry setSymbol(Symbol sym) { | ||
| this.sym = sym; | ||
| owner.elemsCache = null; | ||
| return this; | ||
| } | ||
|
|
||
| public int hashCode() { | ||
| return sym.name.index; | ||
| } | ||
|
|
||
| public String toString() { | ||
| return sym.toString(); | ||
| } | ||
| } | ||
|
|
||
| /** all elements of this scope | ||
| */ | ||
| public Entry elems; | ||
|
|
||
| /** the hash table | ||
| */ | ||
| private Entry[] hashtable; | ||
|
|
||
| /** a cache for all elements, to be used by symbol iterator. | ||
| */ | ||
| private Symbol[] elemsCache = null; | ||
|
|
||
| /** size and mask of hash tables | ||
| * todo: make hashtables grow? | ||
| */ | ||
| private final int HASHSIZE = 0x80; | ||
| private final int HASHMASK = 0x7f; | ||
|
|
||
| /** the threshold number of entries from which a hashtable is constructed. | ||
| */ | ||
| private final int MIN_HASH = 6; | ||
|
|
||
| /** construct a new name space | ||
| */ | ||
| public Scope() { | ||
| this.elems = Entry.NONE; | ||
| } | ||
|
|
||
| public Scope(Entry elems) { | ||
| this.elems = elems; | ||
| if (size() >= MIN_HASH) createHash(); | ||
| } | ||
|
|
||
| public Scope(Scope base) { | ||
| this.elems = base.elems; | ||
| if (base.hashtable != null) { | ||
| this.hashtable = new Entry[HASHSIZE]; | ||
| for (int i = 0; i < HASHSIZE; i++) | ||
| hashtable[i] = base.hashtable[i]; | ||
| } | ||
| } | ||
|
|
||
| public Scope(Symbol[] members) { | ||
| this(); | ||
| for (int i = 0; i < members.length; i++) | ||
| enter(members[i]); | ||
| } | ||
|
|
||
| /** the number of entries in this scope | ||
| */ | ||
| int size() { | ||
| int s = 0; | ||
| for (Entry e = elems; e != Entry.NONE; e = e.next) s++; | ||
| return s; | ||
| } | ||
|
|
||
| private Scope enter(Entry e) { | ||
| elems = e; | ||
| elemsCache = null; | ||
| if (hashtable != null) { | ||
| int i = e.sym.name.index & HASHMASK; | ||
| elems.tail = hashtable[i]; | ||
| hashtable[i] = elems; | ||
| } else if (size() >= MIN_HASH) { | ||
| createHash(); | ||
| } | ||
| return this; | ||
| } | ||
|
|
||
| /** enter a symbol | ||
| */ | ||
| public Scope enter(Symbol sym) { | ||
| return enter(new Entry(sym, this)); | ||
| } | ||
|
|
||
| public Scope enterOrOverload(Symbol sym) { | ||
| Entry e = lookupEntry(sym.name); | ||
| if (e.owner == this && (sym.flags & Modifiers.PRIVATE) == 0) { | ||
| e.setSymbol(e.sym.overloadWith(sym)); | ||
| return this; | ||
| } else { | ||
| return enter(sym); | ||
| } | ||
| } | ||
|
|
||
| private void createHash() { | ||
| hashtable = new Entry[HASHSIZE]; | ||
| for (int i = 0; i < HASHSIZE; i++) | ||
| hashtable[i] = Entry.NONE; | ||
| enterInHash(elems); | ||
| } | ||
|
|
||
| private void enterInHash(Entry e) { | ||
| if (e != Entry.NONE) { | ||
| enterInHash(e.next); | ||
| int i = e.sym.name.index & HASHMASK; | ||
| e.tail = hashtable[i]; | ||
| hashtable[i] = e; | ||
| } | ||
| } | ||
|
|
||
| /** remove entry | ||
| */ | ||
| public void unlink(Entry e) { | ||
| Entry e1 = hashtable[e.sym.name.index & HASHMASK]; | ||
| if (e1 == e) { | ||
| hashtable[e.sym.name.index & HASHMASK] = e.tail; | ||
| } else { | ||
| while (e1.tail != e) e1 = e1.tail; | ||
| } | ||
| if (elems == e) { | ||
| elems = e.next; | ||
| } else { | ||
| e1 = elems; | ||
| while (e1.next != e) e1 = e1.next; | ||
| e1.next = e.next; | ||
| } | ||
| elemsCache = null; | ||
| } | ||
|
|
||
| /** lookup a symbol | ||
| */ | ||
| public Symbol lookup(Name name) { | ||
| return lookupEntry(name).sym; | ||
| } | ||
|
|
||
| /** lookup a symbol entry. | ||
| */ | ||
| public Entry lookupEntry(Name name) { | ||
| Entry e; | ||
| if (hashtable != null) { | ||
| e = hashtable[name.index & HASHMASK]; | ||
| while (e != Entry.NONE && e.sym.name != name) e = e.tail; | ||
| } else { | ||
| e = elems; | ||
| while (e != Entry.NONE && e.sym.name != name) e = e.next; | ||
| } | ||
| return e; | ||
| } | ||
|
|
||
| /** return all symbols as an array, | ||
| * in the order they were entered in this scope. | ||
| */ | ||
| public Symbol[] elements() { | ||
| if (elemsCache == null) { | ||
| int s = size(); | ||
| elemsCache = new Symbol[s]; | ||
| for (Entry e = elems; e != Entry.NONE; e = e.next) | ||
| elemsCache[--s] = e.sym; | ||
| } | ||
| return elemsCache; | ||
| } | ||
|
|
||
| /** return all symbols as an iterator, | ||
| * in the order they were entered in this scope. | ||
| */ | ||
| public SymbolIterator iterator() { return new MySymbols(); } | ||
|
|
||
| class MySymbols extends SymbolIterator { | ||
|
|
||
| private int index; | ||
| MySymbols() { | ||
| elements(); | ||
| index = 0; | ||
| } | ||
|
|
||
| public boolean hasNext() { | ||
| return index < elemsCache.length; | ||
| } | ||
|
|
||
| public Symbol next() { | ||
| return elemsCache[index++]; | ||
| } | ||
| } | ||
|
|
||
| public String toString() { | ||
| StringBuffer str = new StringBuffer("{"); | ||
| SymbolIterator it = iterator(); | ||
| while (it.hasNext()) { | ||
| str.append("\n " + it.next().defString()); | ||
| } | ||
| str.append("}"); | ||
| return str.toString(); | ||
| } | ||
|
|
||
| public String simpleToString() { | ||
| StringBuffer str = new StringBuffer("{"); | ||
| SymbolIterator it = iterator(); | ||
| while (it.hasNext()) { | ||
| str.append("\n " + it.next().name); | ||
| } | ||
| str.append("}"); | ||
| return str.toString(); | ||
| } | ||
|
|
||
| public static Scope EMPTY = new Scope(); | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab; | ||
|
|
||
| import scalac.*; | ||
| import scalac.ast.parser.*; | ||
| import scalac.typechecker.Analyzer; | ||
| import java.io.*; | ||
|
|
||
|
|
||
| public class SourceCompleter extends Type.LazyType { | ||
|
|
||
| /** the global compilation environment | ||
| */ | ||
| protected Global global; | ||
| protected String filename; | ||
| private boolean completed = false; | ||
|
|
||
| public SourceCompleter(Global global, String filename) { | ||
| this.global = global; | ||
| this.filename = filename; | ||
| } | ||
|
|
||
| /** complete class symbol c by loading the class | ||
| */ | ||
| public void complete(Symbol c) { | ||
| if (completed) { | ||
| c.setInfo(Type.ErrorType); | ||
| } else if (filename != null) { | ||
| try { | ||
| String fname = filename; | ||
| long msec = System.currentTimeMillis(); | ||
| Unit unit = new Unit(global, new Sourcefile(filename, false)); | ||
| filename = null; | ||
| global.PHASE.PARSER.createPhase(global).apply(unit); | ||
| ((Analyzer)global.PHASE.ANALYZER.createPhase(global)).lateEnter(unit, c); | ||
| global.operation("added " + fname + " in " + | ||
| (System.currentTimeMillis() - msec) + "ms"); | ||
| } catch (IOException e) { | ||
| e.printStackTrace(); | ||
| global.error("i/o error while loading " + c); | ||
| c.setInfo(Type.ErrorType); | ||
| } | ||
| completed = true; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| \* */ | ||
|
|
||
| // $Id$ | ||
|
|
||
| package scalac.symtab; | ||
|
|
||
| /** Sets of symbols, implemented as binary trees. | ||
| */ | ||
| public class SymSet { | ||
| private SymSet l, r; | ||
| private Symbol sym; | ||
|
|
||
| public SymSet() {} | ||
|
|
||
| private SymSet(Symbol sym, SymSet l, SymSet r) { | ||
| this.sym = sym; this.l = l; this.r = r; | ||
| } | ||
|
|
||
| /** Union of this set and `{sym}'. | ||
| */ | ||
| public SymSet incl(Symbol sym) { | ||
| if (this == EMPTY) { | ||
| return new SymSet(sym, EMPTY, EMPTY); | ||
| } else if (sym == this.sym) { | ||
| return this; | ||
| } else if (sym.isLess(this.sym)) { | ||
| return new SymSet(this.sym, l.incl(sym), r); | ||
| } else { | ||
| assert this.sym.isLess(sym); | ||
| return new SymSet(this.sym, l, r.incl(sym)); | ||
| } | ||
| } | ||
|
|
||
| /** Is `sym' an element of this set? | ||
| */ | ||
| public boolean contains(Symbol sym) { | ||
| if (this == EMPTY) { | ||
| return false; | ||
| } else if (sym == this.sym) { | ||
| return true; | ||
| } else if (sym.isLess(this.sym)) { | ||
| return l.contains(sym); | ||
| } else { | ||
| assert this.sym.isLess(sym); | ||
| return r.contains(sym); | ||
| } | ||
| } | ||
|
|
||
| /** The number of elements in ths set. | ||
| */ | ||
| public int size() { | ||
| if (this == EMPTY) { | ||
| return 0; | ||
| } else { | ||
| return 1 + l.size() + r.size(); | ||
| } | ||
| } | ||
|
|
||
| /** Copy elements of this set into `ss', starting at index `from'. | ||
| * Return index one past last element copied. | ||
| */ | ||
| public int copyToArray(Symbol[] ss, int from) { | ||
| if (this == EMPTY) { | ||
| return from; | ||
| } else { | ||
| from = l.copyToArray(ss, from); | ||
| ss[from] = sym; | ||
| return r.copyToArray(ss, from + 1); | ||
| } | ||
| } | ||
|
|
||
| /** Return all elements of this set as an array. | ||
| */ | ||
| public Symbol[] toArray() { | ||
| int s = size(); | ||
| if (s == 0) return Symbol.EMPTY_ARRAY; | ||
| Symbol[] ss = new Symbol[s]; | ||
| copyToArray(ss, 0); | ||
| return ss; | ||
| } | ||
|
|
||
| /** The empty set. | ||
| */ | ||
| public final static SymSet EMPTY = new SymSet(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab; | ||
|
|
||
| public interface TypeTags { | ||
|
|
||
| /** unboxed type tags | ||
| */ | ||
| int BYTE = 10; | ||
| int CHAR = 11; | ||
| int SHORT = 12; | ||
| int INT = 13; | ||
| int LONG = 14; | ||
| int FLOAT = 15; | ||
| int DOUBLE = 16; | ||
| int BOOLEAN = 17; | ||
| int UNIT = 18; | ||
| int STRING = 19; | ||
|
|
||
| int FirstUnboxedTag = BYTE; | ||
| int LastUnboxedTag = UNIT; | ||
|
|
||
| /** other type tags (used for hashcodes and Pickling) | ||
| */ | ||
| int ERRORtpe = 20; | ||
| int NOtpe = 21; | ||
| int THIStpe = 22; | ||
| int NAMEDtpe = 23; | ||
| int SINGLEtpe = 24; | ||
| int COMPOUNDtpe = 25; | ||
| int METHODtpe = 26; | ||
| int POLYtpe = 27; | ||
| int CONSTRUCTORtpe = 28; | ||
| int COVARtpe = 29; | ||
| int OVERLOADEDtpe = 30; | ||
| int UNBOXEDtpe = 31; | ||
| int UNBOXEDARRAYtpe = 32; | ||
|
|
||
| int firstTypeTag = ERRORtpe; | ||
| int lastTypeTag = UNBOXEDARRAYtpe; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab.classfile; | ||
|
|
||
| import scalac.*; | ||
| import scalac.symtab.*; | ||
| import scalac.util.*; | ||
| import java.io.*; | ||
|
|
||
|
|
||
| public class ClassParser extends Type.LazyType { | ||
|
|
||
| /** the global compilation environment | ||
| */ | ||
| protected Global global; | ||
|
|
||
| public ClassParser(Global global) { | ||
| this.global = global; | ||
| } | ||
|
|
||
| /** complete class symbol c by loading the class | ||
| */ | ||
| public void complete(Symbol c) { | ||
| //System.out.println("loading " + c);//DEBUG | ||
| try { | ||
| long msec = System.currentTimeMillis(); | ||
| String filename = externalizeFileName(c.fullName()) + ".class"; | ||
| AbstractFile f = global.classPath.openFile(filename); | ||
| if (f == null) | ||
| global.error("could not read class " + c); | ||
| else { | ||
| new ClassfileParser(global, new AbstractFileReader(f), c).parse(); | ||
| global.operation("loaded " + f.getPath() + " in " + | ||
| (System.currentTimeMillis() - msec) + "ms"); | ||
| //for (Definition e = c.locals().elems; e != null; e = e.sibling) | ||
| // if (e.def.kind == TYP) | ||
| // e.def.complete(); | ||
| } | ||
| } catch (IOException e) { | ||
| e.printStackTrace(); | ||
| global.error("i/o error while loading " + c); | ||
| c.setInfo(Type.ErrorType); | ||
| } | ||
| } | ||
|
|
||
| /** return external representation of file name s, | ||
| * converting '.' to File.separatorChar | ||
| */ | ||
| public String externalizeFileName(Name n) { | ||
| if ((n == null) || (n.length() == 0)) | ||
| return "."; | ||
| byte[] ascii = n.toAscii(); | ||
| String s = SourceRepresentation.ascii2string( | ||
| ascii, 0, ascii.length); | ||
| return s.replace('.', File.separatorChar); | ||
| } | ||
|
|
||
| public Type.LazyType staticsParser(Symbol clazz) { | ||
| return new StaticsParser(clazz); | ||
| } | ||
|
|
||
| public Type.LazyType aliasParser(Symbol alias) { | ||
| return new AliasParser(alias); | ||
| } | ||
|
|
||
| class StaticsParser extends Type.LazyType { | ||
| Symbol clazz; | ||
|
|
||
| StaticsParser(Symbol clazz) { | ||
| this.clazz = clazz; | ||
| } | ||
|
|
||
| public void complete(Symbol statics) { | ||
| ClassParser.this.complete(clazz); | ||
| } | ||
| } | ||
|
|
||
| class AliasParser extends Type.LazyType { | ||
| Symbol alias; | ||
|
|
||
| AliasParser(Symbol alias) { | ||
| this.alias = alias; | ||
| } | ||
|
|
||
| public void complete(Symbol c) { | ||
| try { | ||
| long msec = System.currentTimeMillis(); | ||
| String filename = externalizeFileName(alias.fullName()) + ".class"; | ||
| AbstractFile f = global.classPath.openFile(filename); | ||
| if (f == null) | ||
| global.error("could not read class " + c); | ||
| else { | ||
| new ClassfileParser(global, new AbstractFileReader(f), c).parse(); | ||
| global.operation("loaded " + f.getPath() + " in " + | ||
| (System.currentTimeMillis() - msec) + "ms"); | ||
| } | ||
| } catch (IOException e) { | ||
| e.printStackTrace(); | ||
| global.error("i/o error while loading " + c); | ||
| c.setInfo(Type.ErrorType); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab.classfile; | ||
|
|
||
| import scalac.util.Name; | ||
|
|
||
| public interface ClassfileConstants { | ||
|
|
||
| int JAVA_MAGIC = 0xCAFEBABE; | ||
| int JAVA_MAJOR_VERSION = 45; | ||
| int JAVA_MINOR_VERSION = 3; | ||
|
|
||
| int CONSTANT_UTF8 = 1; | ||
| int CONSTANT_UNICODE = 2; | ||
| int CONSTANT_INTEGER = 3; | ||
| int CONSTANT_FLOAT = 4; | ||
| int CONSTANT_LONG = 5; | ||
| int CONSTANT_DOUBLE = 6; | ||
| int CONSTANT_CLASS = 7; | ||
| int CONSTANT_STRING = 8; | ||
| int CONSTANT_FIELDREF = 9; | ||
| int CONSTANT_METHODREF = 10; | ||
| int CONSTANT_INTFMETHODREF = 11; | ||
| int CONSTANT_NAMEANDTYPE = 12; | ||
|
|
||
| int BAD_ATTR = 0x00000; | ||
| int SOURCEFILE_ATTR = 0x00001; | ||
| int SYNTHETIC_ATTR = 0x00002; | ||
| int DEPRECATED_ATTR = 0x00004; | ||
| int CODE_ATTR = 0x00008; | ||
| int EXCEPTIONS_ATTR = 0x00010; | ||
| int CONSTANT_VALUE_ATTR = 0x00020; | ||
| int LINE_NUM_TABLE_ATTR = 0x00040; | ||
| int LOCAL_VAR_TABLE_ATTR = 0x00080; | ||
| int INNERCLASSES_ATTR = 0x08000; | ||
| int META_ATTR = 0x10000; | ||
| int SCALA_ATTR = 0x20000; | ||
|
|
||
| Name SOURCEFILE_N = Name.fromString("SourceFile"); | ||
| Name SYNTHETIC_N = Name.fromString("Synthetic"); | ||
| Name DEPRECATED_N = Name.fromString("Deprecated"); | ||
| Name CODE_N = Name.fromString("Code"); | ||
| Name EXCEPTIONS_N = Name.fromString("Exceptions"); | ||
| Name CONSTANT_VALUE_N = Name.fromString("ConstantValue"); | ||
| Name LINE_NUM_TABLE_N = Name.fromString("LineNumberTable"); | ||
| Name LOCAL_VAR_TABLE_N = Name.fromString("LocalVariableTable"); | ||
| Name INNERCLASSES_N = Name.fromString("InnerClasses"); | ||
| Name META_N = Name.fromString("JacoMeta"); | ||
| Name SCALA_N = Name.fromString("ScalaSignature"); | ||
| Name CONSTR_N = Name.fromString("<init>"); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,239 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab.classfile; | ||
|
|
||
| import scalac.*; | ||
| import scalac.util.*; | ||
| import scalac.symtab.*; | ||
| import java.io.*; | ||
| import java.util.*; | ||
|
|
||
| //todo: don't keep statics module in scope. | ||
|
|
||
| public class ClassfileParser implements ClassfileConstants { | ||
|
|
||
| static final int CLASS_ATTR = SOURCEFILE_ATTR | ||
| | INNERCLASSES_ATTR | ||
| | SYNTHETIC_ATTR | ||
| | DEPRECATED_ATTR | ||
| | META_ATTR | ||
| | SCALA_ATTR; | ||
| static final int METH_ATTR = CODE_ATTR | ||
| | EXCEPTIONS_ATTR | ||
| | SYNTHETIC_ATTR | ||
| | DEPRECATED_ATTR | ||
| | META_ATTR; | ||
| static final int FIELD_ATTR = CONSTANT_VALUE_ATTR | ||
| | SYNTHETIC_ATTR | ||
| | DEPRECATED_ATTR | ||
| | META_ATTR; | ||
|
|
||
| protected Global global; | ||
| protected AbstractFileReader in; | ||
| protected Symbol c; | ||
| protected Type ctype; | ||
| protected Scope locals; | ||
| protected Scope statics; | ||
| protected Scope constr; | ||
| protected JavaTypeFactory make; | ||
| protected Signatures sigs; | ||
| protected ConstantPool pool; | ||
| protected AttributeParser attrib; | ||
| protected Definitions defs; | ||
| protected int phaseId; | ||
|
|
||
|
|
||
| public ClassfileParser(Global global, AbstractFileReader in, Symbol c) { | ||
| this.global = global; | ||
| this.in = in; | ||
| this.c = c; | ||
| this.ctype = Type.TypeRef(c.owner().thisType(), c, Type.EMPTY_ARRAY); | ||
| this.make = new JavaTypeCreator(global); | ||
| this.sigs = new Signatures(global, make); | ||
| this.pool = new ConstantPool(in, sigs); | ||
| this.attrib = new AttributeParser(in, pool, this); | ||
| this.defs = global.definitions; | ||
| this.phaseId = global.POST_ANALYZER_PHASE_ID; | ||
| } | ||
|
|
||
|
|
||
| /** parse the classfile and throw IO exception if there is an | ||
| * error in the classfile structure | ||
| */ | ||
| public void parse() throws IOException { | ||
| try { | ||
| if (in.nextInt() != JAVA_MAGIC) | ||
| throw new IOException("illegal start of class file"); | ||
| int minorVersion = in.nextChar(); | ||
| int majorVersion = in.nextChar(); | ||
| if ((majorVersion < JAVA_MAJOR_VERSION) || | ||
| ((majorVersion == JAVA_MAJOR_VERSION) && | ||
| (minorVersion < JAVA_MINOR_VERSION))) | ||
| throw new IOException("class file has wrong version " + | ||
| majorVersion + "." + minorVersion + ", should be " + | ||
| JAVA_MAJOR_VERSION + "." + JAVA_MINOR_VERSION); | ||
| pool.indexPool(); | ||
| int flags = in.nextChar(); | ||
| Name name = readClassName(in.nextChar()); | ||
| if (c.fullName() != name) | ||
| throw new IOException("class file '" + c.fullName() + | ||
| "' contains wrong class " + name); | ||
| // todo: correct flag transition | ||
| c.flags = transFlags(flags); | ||
| if ((c.flags & Modifiers.ABSTRACT) != 0) | ||
| c.flags = c.flags & ~Modifiers.ABSTRACT | Modifiers.ABSTRACTCLASS; | ||
| Type supertpe = readClassType(in.nextChar()); | ||
| Type[] basetpes = new Type[in.nextChar() + 1]; | ||
| this.locals = new Scope(); | ||
| this.statics = new Scope(); | ||
| this.constr = new Scope(); | ||
| // set type of class | ||
| Type classType = Type.compoundType(basetpes, locals, c); | ||
| c.setInfo(classType, phaseId); | ||
| // set type of statics | ||
| Symbol staticsClass = c.module().moduleClass(); | ||
| Type staticsInfo = Type.compoundType(Type.EMPTY_ARRAY, statics, staticsClass); | ||
| staticsClass.setInfo(staticsInfo, phaseId); | ||
| c.module().setInfo(Type.TypeRef(staticsClass.owner().thisType(), | ||
| staticsClass, Type.EMPTY_ARRAY)); | ||
| basetpes[0] = supertpe; | ||
| for (int i = 1; i < basetpes.length; i++) | ||
| basetpes[i] = readClassType(in.nextChar()); | ||
| int fieldCount = in.nextChar(); | ||
| for (int i = 0; i < fieldCount; i++) | ||
| parseField(); | ||
| int methodCount = in.nextChar(); | ||
| for (int i = 0; i < methodCount; i++) | ||
| parseMethod(); | ||
| // set constructor type to the declared type | ||
| Symbol[] constrs = constr.elements(); | ||
| if (constrs.length != 0) { | ||
| assert constrs.length == 1; | ||
| c.constructor().setInfo(constrs[0].info(), phaseId); | ||
| } else { | ||
| Type constrtype = ((c.flags & Modifiers.INTERFACE) != 0) | ||
| ? Type.PolyType(Symbol.EMPTY_ARRAY, ctype) | ||
| : Type.MethodType(new Symbol[]{Symbol.NONE}, ctype); | ||
| c.constructor().setInfo(constrtype, phaseId); | ||
| } | ||
| attrib.readAttributes(c, classType, CLASS_ATTR); | ||
| //System.out.println("dynamic class: " + c); | ||
| //System.out.println("statics class: " + staticsClass); | ||
| //System.out.println("module: " + c.module()); | ||
| //System.out.println("modules class: " + c.module().type().symbol()); | ||
| } catch (RuntimeException e) { | ||
| e.printStackTrace(); | ||
| throw new IOException("bad class file (" + e.getMessage() + ")"); | ||
| } | ||
| } | ||
|
|
||
| /** convert Java modifiers into Scala flags | ||
| */ | ||
| public int transFlags(int flags) { | ||
| int res = 0; | ||
| if (((flags & 0x0007) == 0) || | ||
| ((flags & 0x0002) != 0)) | ||
| res |= Modifiers.PRIVATE; | ||
| else if ((flags & 0x0004) != 0) | ||
| res |= Modifiers.PROTECTED; | ||
| if ((flags & 0x0400) != 0) | ||
| res |= Modifiers.ABSTRACT; | ||
| if ((flags & 0x0010) != 0) | ||
| res |= Modifiers.FINAL; | ||
| if ((flags & 0x0200) != 0) | ||
| res |= Modifiers.INTERFACE | Modifiers.ABSTRACTCLASS; | ||
| return res | Modifiers.JAVA; | ||
| } | ||
|
|
||
| /** read a class name | ||
| */ | ||
| protected Name readClassName(int i) { | ||
| return (Name)pool.readPool(i); | ||
| } | ||
|
|
||
| /** read a class name and return the corresponding class type | ||
| */ | ||
| protected Type readClassType(int i) { | ||
| if (i == 0) | ||
| return defs.ANY_TYPE; | ||
| Type res = defs.getJavaType((Name)pool.readPool(i)); | ||
| if (res == Type.ErrorType) | ||
| global.error("unknown class reference " + pool.readPool(i)); | ||
| if (res.symbol() == defs.JAVA_OBJECT_TYPE.symbol()) | ||
| return defs.ANYREF_TYPE; | ||
| else | ||
| return res; | ||
| } | ||
|
|
||
| /** read a signature and return it as a type | ||
| */ | ||
| protected Type readType(int i) { | ||
| Name sig = pool.readExternal(i); | ||
| return sigs.sigToType(Name.names, sig.index, sig.length()); | ||
| } | ||
|
|
||
| /** read a field | ||
| */ | ||
| protected void parseField() { | ||
| int flags = in.nextChar(); | ||
| Name name = (Name)pool.readPool(in.nextChar()); | ||
| Type type = readType(in.nextChar()); | ||
| int mods = transFlags(flags); | ||
| if ((flags & 0x0010) == 0) | ||
| mods |= Modifiers.MUTABLE; | ||
| Symbol owner = c; | ||
| if ((flags & 0x0008) != 0) | ||
| owner = c.module().moduleClass(); | ||
| Symbol s = new TermSymbol(Position.NOPOS, name, owner, mods); | ||
| s.setInfo(type, phaseId); | ||
| attrib.readAttributes(s, type, FIELD_ATTR); | ||
| ((flags & 0x0008) != 0 ? statics : locals).enterOrOverload(s); | ||
| } | ||
|
|
||
| /** read a method | ||
| */ | ||
| protected void parseMethod() { | ||
| int flags = in.nextChar(); | ||
| Name name = (Name)pool.readPool(in.nextChar()); | ||
| Type type = readType(in.nextChar()); | ||
| if (CONSTR_N.equals(name)) { | ||
| Symbol s = TermSymbol.newConstructor(c, transFlags(flags)); | ||
| // kick out protected, package visible or | ||
| // private constructors | ||
| if (((flags & 0x0004) != 0) || | ||
| ((flags & 0x0002) != 0) || | ||
| ((flags & 0x0007) == 0)) { | ||
| attrib.readAttributes(s, type, METH_ATTR); | ||
| return; | ||
| } | ||
| switch (type) { | ||
| case MethodType(Symbol[] vparams, _): | ||
| if (c == defs.OBJECT_CLASS) | ||
| type = Type.PolyType(Symbol.EMPTY_ARRAY, ctype); | ||
| else | ||
| type = Type.MethodType(vparams, ctype); | ||
| break; | ||
| default: | ||
| throw new ApplicationError(); | ||
| } | ||
| s.setInfo(type, phaseId); | ||
| attrib.readAttributes(s, type, METH_ATTR); | ||
| //System.out.println("-- enter " + s); | ||
| constr.enterOrOverload(s); | ||
| } else { | ||
| Symbol s = new TermSymbol( | ||
| Position.NOPOS, name, | ||
| ((flags & 0x0008) != 0) ? c.module().moduleClass() : c, | ||
| transFlags(flags)); | ||
| s.setInfo(type, phaseId); | ||
| attrib.readAttributes(s, type, METH_ATTR); | ||
| ((flags & 0x0008) != 0 ? statics : locals).enterOrOverload(s); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab.classfile; | ||
|
|
||
| import scalac.*; | ||
| import scalac.symtab.*; | ||
| import scalac.util.*; | ||
|
|
||
| public class ConstantPool implements ClassfileConstants { | ||
|
|
||
| AbstractFileReader in; | ||
| Signatures sigparser; | ||
|
|
||
| /** the objects of the constant pool | ||
| */ | ||
| protected Object[] poolObj; | ||
|
|
||
| /** for every constant pool entry, an index into in.buf where the | ||
| * defining section of the entry is found | ||
| */ | ||
| protected int[] poolIdx; | ||
|
|
||
| /** constructor | ||
| */ | ||
| protected ConstantPool(AbstractFileReader in, Signatures sigparser) { | ||
| this.in = in; | ||
| this.sigparser = sigparser; | ||
| } | ||
|
|
||
| /** index all constant pool entries, writing their start | ||
| * addresses into poolIdx | ||
| */ | ||
| public void indexPool() { | ||
| poolIdx = new int[in.nextChar()]; | ||
| poolObj = new Object[poolIdx.length]; | ||
| int i = 1; | ||
| while (i < poolIdx.length) { | ||
| poolIdx[i++] = in.bp; | ||
| byte tag = in.nextByte(); | ||
| switch (tag) { | ||
| case CONSTANT_UTF8: | ||
| case CONSTANT_UNICODE: { | ||
| int len = in.nextChar(); | ||
| in.skip(len); | ||
| break; | ||
| } | ||
| case CONSTANT_CLASS: | ||
| case CONSTANT_STRING: | ||
| in.skip(2); | ||
| break; | ||
| case CONSTANT_FIELDREF: | ||
| case CONSTANT_METHODREF: | ||
| case CONSTANT_INTFMETHODREF: | ||
| case CONSTANT_NAMEANDTYPE: | ||
| case CONSTANT_INTEGER: | ||
| case CONSTANT_FLOAT: | ||
| in.skip(4); | ||
| break; | ||
| case CONSTANT_LONG: | ||
| case CONSTANT_DOUBLE: | ||
| in.skip(8); | ||
| i++; | ||
| break; | ||
| default: | ||
| throw new RuntimeException("bad constant pool tag: " + tag + | ||
| " at " + (in.bp - 1)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** if name is an array type or class signature, return the | ||
| * corresponding type; otherwise return a class definition with given name | ||
| */ | ||
| protected Object classOrType(Name name) { | ||
| if ((name.sub(0) == '[') || (name.sub(name.length() - 1) == ';')) { | ||
| byte[] ascii = name.toAscii(); | ||
| return sigparser.sigToType(ascii, 0, ascii.length); | ||
| } else | ||
| return name; | ||
| } | ||
|
|
||
| /** read constant pool entry at start address i, use poolObj as a cache. | ||
| */ | ||
| public Object readPool(int i) { | ||
| if (poolObj[i] != null) | ||
| return poolObj[i]; | ||
| int index = poolIdx[i]; | ||
| if (index == 0) | ||
| return null; | ||
| switch (in.byteAt(index)) { | ||
| case CONSTANT_UTF8: | ||
| poolObj[i] = Name.fromAscii(in.buf, index + 3, in.getChar(index + 1)); | ||
| break; | ||
|
|
||
| case CONSTANT_UNICODE: | ||
| throw new RuntimeException("can't read unicode strings in classfiles"); | ||
|
|
||
| case CONSTANT_CLASS: | ||
| poolObj[i] = classOrType(readExternal(in.getChar(index + 1))); | ||
| break; | ||
|
|
||
| case CONSTANT_FIELDREF: { | ||
| //Symbol owner = (Symbol)readPool(in.getChar(index + 1)); | ||
| //NameAndType nt = (NameAndType)readPool(in.getChar(index + 3)); | ||
| //poolObj[i] = new TermSymbol(Kinds.VAR, Position.NOPOS, nt.name, owner, 0) | ||
| // .type(sigparser.sigToType(Name.names, nt.sig.index, nt.sig.length())); | ||
| throw new RuntimeException("can't read constant_fieldrefs in classfiles"); | ||
| } | ||
|
|
||
| case CONSTANT_METHODREF: | ||
| case CONSTANT_INTFMETHODREF: { | ||
| //Symbol owner = (Symbol)readPool(in.getChar(index + 1)); | ||
| //NameAndType nt = (NameAndType)readPool(in.getChar(index + 3)); | ||
| //poolObj[i] = new TermSymbol(Kinds.FUN, Position.NOPOS, nt.name, owner, 0) | ||
| // .type(sigparser.sigToType(Name.names, nt.sig.index, nt.sig.length())); | ||
| throw new RuntimeException("can't read constant_methodrefs in classfiles"); | ||
| } | ||
|
|
||
| case CONSTANT_NAMEANDTYPE: | ||
| poolObj[i] = new NameAndType((Name)readPool(in.getChar(index + 1)), | ||
| readExternal(in.getChar(index + 3))); | ||
| break; | ||
|
|
||
| case CONSTANT_STRING: | ||
| case CONSTANT_INTEGER: | ||
| case CONSTANT_FLOAT: | ||
| case CONSTANT_LONG: | ||
| case CONSTANT_DOUBLE: | ||
| throw new RuntimeException("can't read constants in classfiles"); | ||
|
|
||
| default: | ||
| throw new RuntimeException("bad constant pool tag: " + in.byteAt(index)); | ||
| } | ||
| return poolObj[i]; | ||
| } | ||
|
|
||
| /** return internal representation of buf[offset..offset+len-1], | ||
| * converting '/' to '.' | ||
| */ | ||
| public byte[] internalize(byte[] buf, int offset, int len) { | ||
| byte[] translated = new byte[len]; | ||
| for (int j = 0; j < len; j++) { | ||
| byte b = buf[offset + j]; | ||
| if (b == '/') | ||
| translated[j] = '.'; | ||
| else | ||
| translated[j] = b; | ||
| } | ||
| return translated; | ||
| } | ||
|
|
||
| /** read a constant pool string and convert to internal representation. | ||
| */ | ||
| public Name readExternal(int i) { | ||
| if (poolObj[i] == null) { | ||
| int index = poolIdx[i]; | ||
| if (in.byteAt(index) == CONSTANT_UTF8) { | ||
| int len = in.getChar(index + 1); | ||
| byte[] translated = internalize(in.buf, index + 3, len); | ||
| poolObj[i] = Name.fromAscii(translated, 0, len); | ||
| } | ||
| } | ||
| return (Name)poolObj[i]; | ||
| } | ||
|
|
||
| /** the name and type signature of a method or field | ||
| */ | ||
| public static final class NameAndType { | ||
| public Name name; | ||
| public Name sig; | ||
|
|
||
| public NameAndType(Name name, Name sig) { | ||
| this.name = name; | ||
| this.sig = sig; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab.classfile; | ||
|
|
||
| import scalac.Global; | ||
| import scalac.util.*; | ||
| import scalac.symtab.*; | ||
| import Type.*; | ||
|
|
||
|
|
||
| public class JavaTypeCreator implements JavaTypeFactory { | ||
|
|
||
| protected Global global; | ||
|
|
||
| public JavaTypeCreator(Global global) { | ||
| this.global = global; | ||
| } | ||
|
|
||
| public Type byteType() { | ||
| return global.definitions.BYTE_TYPE; | ||
| } | ||
|
|
||
| public Type shortType() { | ||
| return global.definitions.SHORT_TYPE; | ||
| } | ||
|
|
||
| public Type charType() { | ||
| return global.definitions.CHAR_TYPE; | ||
| } | ||
|
|
||
| public Type intType() { | ||
| return global.definitions.INT_TYPE; | ||
| } | ||
|
|
||
| public Type longType() { | ||
| return global.definitions.LONG_TYPE; | ||
| } | ||
|
|
||
| public Type floatType() { | ||
| return global.definitions.FLOAT_TYPE; | ||
| } | ||
|
|
||
| public Type doubleType() { | ||
| return global.definitions.DOUBLE_TYPE; | ||
| } | ||
|
|
||
| public Type booleanType() { | ||
| return global.definitions.BOOLEAN_TYPE; | ||
| } | ||
|
|
||
| public Type voidType() { | ||
| return global.definitions.UNIT_TYPE; | ||
| } | ||
|
|
||
| public Type classType(Name classname) { | ||
| return global.definitions.getJavaType(classname); | ||
| } | ||
|
|
||
| public Type arrayType(Type elemtpe) { | ||
| return global.definitions.arrayType(elemtpe); | ||
| } | ||
|
|
||
| public Type methodType(Type[] argtpes, Type restpe, Type[] thrown) { | ||
| Symbol[] args = new Symbol[argtpes.length]; | ||
| for (int i = 0; i < args.length; i++) { | ||
| args[i] = new TermSymbol( | ||
| Position.NOPOS, Name.fromString("x" + i), Symbol.NONE, Modifiers.PARAM); | ||
| args[i].setInfo(argtpes[i]); | ||
| } | ||
| return new MethodType(args, restpe); | ||
| } | ||
|
|
||
| public Type packageType(Name packagename) { | ||
| return null; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab.classfile; | ||
|
|
||
| import scalac.symtab.Type; | ||
| import scalac.util.Name; | ||
|
|
||
| public interface JavaTypeFactory { | ||
| Type byteType(); | ||
| Type shortType(); | ||
| Type charType(); | ||
| Type intType(); | ||
| Type longType(); | ||
| Type floatType(); | ||
| Type doubleType(); | ||
| Type booleanType(); | ||
| Type voidType(); | ||
| Type classType(Name classname); | ||
| Type arrayType(Type elemtpe); | ||
| Type methodType(Type[] argtpes, Type restpe, Type[] thrown); | ||
| Type packageType(Name packagename); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab.classfile; | ||
|
|
||
| import scalac.*; | ||
| import scalac.symtab.*; | ||
| import scalac.util.*; | ||
| import java.io.*; | ||
|
|
||
| public class PackageParser extends Type.LazyType { | ||
|
|
||
| /** the global compilation environment | ||
| */ | ||
| protected Global global; | ||
|
|
||
| /** the class parser | ||
| */ | ||
| public ClassParser classCompletion; | ||
|
|
||
| public PackageParser(Global global) { | ||
| this.global = global; | ||
| this.classCompletion = new ClassParser(global); | ||
| } | ||
|
|
||
| /** complete package type symbol p by loading all package members | ||
| */ | ||
| public void complete(Symbol p) { | ||
| long msec = System.currentTimeMillis(); | ||
| Scope members = new Scope(); | ||
| String dirname = null; | ||
| Name name = p.fullName(); | ||
| if (name.length() == 0) { | ||
| // includeMembers(AbstractFile.open(null, "."), p, members, false); | ||
| } else { | ||
| dirname = externalizeFileName(name); | ||
| assert !dirname.startsWith("com") : p;//debug | ||
| if (!dirname.endsWith("/")) | ||
| dirname += "/"; | ||
| } | ||
| String[] base = global.classPath.components(); | ||
| for (int i = 0; i < base.length; i++) { | ||
| includeMembers( | ||
| AbstractFile.open(base[i], dirname), p, members, dirname != null); | ||
| } | ||
| p.setInfo(Type.compoundType(Type.EMPTY_ARRAY, members, p)); | ||
| if (dirname == null) | ||
| dirname = "anonymous package"; | ||
| global.operation("scanned " + dirname + " in " + | ||
| (System.currentTimeMillis() - msec) + "ms"); | ||
| } | ||
|
|
||
| /** read directory of a classpath directory and include members | ||
| * in package/module scope | ||
| */ | ||
| protected void includeMembers(AbstractFile dir, Symbol p, Scope locals, | ||
| boolean inclClasses) { | ||
| if (dir == null) | ||
| return; | ||
| String[] filenames = null; | ||
| try { | ||
| if ((filenames = dir.list()) == null) | ||
| return; | ||
| for (int j = 0; j < filenames.length; j++) { | ||
| String fname = filenames[j]; | ||
| if (inclClasses && fname.endsWith(".class")) { | ||
| Name n = Name.fromString(fname.substring(0, fname.length() - 6)) | ||
| .toTypeName(); | ||
| ClassSymbol clazz = new ClassSymbol(n, p, classCompletion); | ||
| clazz.constructor().setInfo( | ||
| classCompletion.staticsParser(clazz)); | ||
| // enter class | ||
| locals.enter(clazz); | ||
| locals.enter(clazz.constructor()); | ||
| // enter module, except for scala.Object class | ||
| // todo: why not there also?. | ||
| if (!(n == Names.Object.toTypeName() && | ||
| p.fullName().toTermName() == Names.scala)) { | ||
| Scope.Entry e = locals.lookupEntry(clazz.module().name); | ||
| if (e != Scope.Entry.NONE) { | ||
| // we already have a package of the same name; delete it | ||
| locals.unlink(e); | ||
| } | ||
| locals.enter(clazz.module()); | ||
| } | ||
| } else if (fname.endsWith("/") && !fname.equals("META-INF/")) { | ||
| Name n = Name.fromString(fname.substring(0, fname.length() - 1)); | ||
| if (locals.lookup(n) == Symbol.NONE) { | ||
| TermSymbol module = TermSymbol.newJavaPackageModule(n, p, this); | ||
| locals.enter(module); | ||
| } | ||
| } else if (fname.endsWith(".scala")) { | ||
| Name n = Name.fromString(fname.substring(0, fname.length() - 6)) | ||
| .toTypeName(); | ||
| if (locals.lookup(n) == Symbol.NONE) { | ||
| SourceCompleter completer = new SourceCompleter(global, | ||
| dir.getPath() + File.separatorChar + fname); | ||
| ClassSymbol clazz = new ClassSymbol(n, p, completer); | ||
| clazz.constructor().setInfo(completer); | ||
| clazz.module().setInfo(completer); | ||
| // enter class | ||
| locals.enter(clazz); | ||
| locals.enter(clazz.constructor()); | ||
| locals.enter(clazz.module()); | ||
| } | ||
| } | ||
| } | ||
| } catch (IOException e) { | ||
| } | ||
| } | ||
|
|
||
| /** return external representation of file name s, | ||
| * converting '.' to File.separatorChar | ||
| */ | ||
|
|
||
| public String externalizeFileName(Name n) { | ||
| if ((n == null) || (n.length() == 0)) | ||
| return "."; | ||
| byte[] ascii = n.toAscii(); | ||
| String s = SourceRepresentation.ascii2string( | ||
| ascii, 0, ascii.length); | ||
| return s.replace('.', File.separatorChar); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.symtab.classfile; | ||
|
|
||
| import scalac.*; | ||
| import scalac.symtab.*; | ||
| import scalac.util.*; | ||
| import java.util.*; | ||
| import Type.*; | ||
|
|
||
| public class Signatures { | ||
|
|
||
| /** signature constants | ||
| */ | ||
| Name BYTE_SIG = Name.fromString("B"); | ||
| Name SHORT_SIG = Name.fromString("S"); | ||
| Name CHAR_SIG = Name.fromString("C"); | ||
| Name INT_SIG = Name.fromString("I"); | ||
| Name LONG_SIG = Name.fromString("J"); | ||
| Name FLOAT_SIG = Name.fromString("F"); | ||
| Name DOUBLE_SIG = Name.fromString("D"); | ||
| Name BOOLEAN_SIG = Name.fromString("Z"); | ||
| Name VOID_SIG = Name.fromString("V"); | ||
| Name CLASS_SIG = Name.fromString("L"); | ||
| Name ARRAY_SIG = Name.fromString("["); | ||
| Name ARGBEGIN_SIG = Name.fromString("("); | ||
| Name ARGEND_SIG = Name.fromString(")"); | ||
|
|
||
| Global global; | ||
| JavaTypeFactory make; | ||
|
|
||
|
|
||
| public Signatures(Global global, JavaTypeFactory make) { | ||
| this.make = make; | ||
| this.global = global; | ||
| } | ||
|
|
||
| /** the type represented by signature[offset..]. | ||
| */ | ||
| protected byte[] signature; | ||
| protected int sigp; | ||
| protected int limit; | ||
|
|
||
| public Type sigToType(byte[] sig, int offset, int len) { | ||
| signature = sig; | ||
| sigp = offset; | ||
| limit = offset + len; | ||
| return sigToType(); | ||
| } | ||
|
|
||
| protected Type sigToType() { | ||
| switch (signature[sigp]) { | ||
| case 'B': | ||
| sigp++; | ||
| return make.byteType(); | ||
| case 'C': | ||
| sigp++; | ||
| return make.charType(); | ||
| case 'D': | ||
| sigp++; | ||
| return make.doubleType(); | ||
| case 'F': | ||
| sigp++; | ||
| return make.floatType(); | ||
| case 'I': | ||
| sigp++; | ||
| return make.intType(); | ||
| case 'J': | ||
| sigp++; | ||
| return make.longType(); | ||
| case 'L': | ||
| sigp++; | ||
| int start = sigp; | ||
| while (signature[sigp] != ';') | ||
| sigp++; | ||
| return make.classType(Name.fromAscii(signature, start, (sigp++) - start)); | ||
| case 'S': | ||
| sigp++; | ||
| return make.shortType(); | ||
| case 'V': | ||
| sigp++; | ||
| return make.voidType(); | ||
| case 'Z': | ||
| sigp++; | ||
| return make.booleanType(); | ||
| case '[': | ||
| sigp++; | ||
| while (('0' <= signature[sigp]) && (signature[sigp] <= '9')) | ||
| sigp++; | ||
| return make.arrayType(sigToType()); | ||
| case '(': | ||
| return make.methodType(sigToTypes(')'), sigToType(), Type.EMPTY_ARRAY); | ||
| default: | ||
| global.error("bad signature: " + | ||
| SourceRepresentation.ascii2string(signature, sigp, 1)); | ||
| return Type.ErrorType; | ||
| } | ||
| } | ||
|
|
||
| protected Type[] sigToTypes(char terminator) { | ||
| sigp++; | ||
| return sigToTypes(terminator, 0); | ||
| } | ||
|
|
||
| protected Type[] sigToTypes(char terminator, int i) { | ||
| if (signature[sigp] == terminator) { | ||
| sigp++; | ||
| return new Type[i]; | ||
| } else { | ||
| Type t = sigToType(); | ||
| Type[] vec = sigToTypes(terminator, i+1); | ||
| vec[i] = t; | ||
| return vec; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| \* */ | ||
|
|
||
| // $Id$ | ||
|
|
||
| package scalac.transformer; | ||
|
|
||
| import scalac.*; | ||
| import scalac.util.*; | ||
| import scalac.parser.*; | ||
| import scalac.symtab.*; | ||
| import scalac.checkers.*; | ||
|
|
||
| public class LambdaLiftPhase extends PhaseDescriptor implements Kinds, Modifiers { | ||
|
|
||
| private Global global; | ||
| int nextPhase; | ||
|
|
||
| public void initialize(Global global, int id) { | ||
| super.initialize(global, id); | ||
| this.global = global; | ||
| this.nextPhase = id + 1; | ||
| } | ||
|
|
||
| public String name () { | ||
| return "lambdalift"; | ||
| } | ||
|
|
||
| public String description () { | ||
| return "lambda lifter"; | ||
| } | ||
|
|
||
| public String taskDescription() { | ||
| return "lambda lifting"; | ||
| } | ||
|
|
||
| public Phase createPhase(Global global) { | ||
| return new LambdaLift(global, this); | ||
| } | ||
|
|
||
| public Type transformInfo(Symbol sym, Type tp) { | ||
| Type tp1 = transform(tp, sym.owner()); | ||
| if ((sym.flags & Modifiers.CAPTURED) != 0) return refType(tp1); | ||
| else return tp1; | ||
| } | ||
|
|
||
| /** Add proxies as type arguments for propagated type parameters. | ||
| */ | ||
| Type transform(Type tp, Symbol owner) { | ||
| return transformTypeMap.setOwner(owner).apply(tp); | ||
| } | ||
|
|
||
| private class TransformTypeMap extends Type.Map { | ||
| Symbol owner; | ||
| Type.Map setOwner(Symbol owner) { this.owner = owner; return this; } | ||
|
|
||
| public Type apply(Type tp) { | ||
| switch (tp) { | ||
| case TypeRef(Type pre, Symbol sym, Type[] targs): | ||
| switch (pre) { | ||
| case ThisType(_): | ||
| if (sym.constructor().isUpdated(nextPhase)) { | ||
| System.out.println("updated: " + sym.constructor());//debug | ||
| Symbol[] tparams = | ||
| sym.constructor().infoAt(nextPhase).typeParams(); | ||
| int i = tparams.length; | ||
| while (i > 0 && (tparams[i-1].flags & SYNTHETIC) != 0) | ||
| i--; | ||
| if (i < tparams.length) { | ||
| Type[] targs1 = new Type[tparams.length]; | ||
| System.arraycopy(map(targs), 0, targs1, 0, targs.length); | ||
| while (i < tparams.length) { | ||
| targs1[i] = proxy(tparams[i], owner).type(); | ||
| } | ||
| return Type.TypeRef(pre, sym, targs1); | ||
| } | ||
| } | ||
| } | ||
| break; | ||
| } | ||
| return map(tp); | ||
| } | ||
|
|
||
| /** All symbols are mapped to themselves. | ||
| */ | ||
| public Scope map(Scope s) { return s; } | ||
| public Symbol map(Symbol s) { return s; } | ||
| public Symbol[] map(Symbol[] ss) { return ss; } | ||
| } | ||
|
|
||
| private TransformTypeMap transformTypeMap = new TransformTypeMap(); | ||
|
|
||
| /** Return closest enclosing (type)parameter that has same name as `fv', | ||
| * or `fv' itself if this is the closest definition. | ||
| */ | ||
| Symbol proxy(Symbol fv, Symbol owner) { | ||
| if (global.debug) | ||
| global.log("proxy " + fv + " in " + LambdaLift.asFunction(owner)); | ||
| Symbol o = owner; | ||
| while (o.kind != NONE) { | ||
| Symbol fowner = LambdaLift.asFunction(o); | ||
| if (fv.owner() == fowner) return fv; | ||
| Type ft = (fowner.isUpdated(nextPhase)) ? fowner.typeAt(nextPhase) | ||
| : fowner.type(); | ||
| Symbol[] ownerparams = fv.isType() ? ft.typeParams() | ||
| : ft.firstParams(); | ||
| for (int i = 0; i < ownerparams.length; i++) { | ||
| if (ownerparams[i].name == fv.name) | ||
| return ownerparams[i]; | ||
| } | ||
| o = o.owner(); | ||
| } | ||
| throw new ApplicationError("proxy " + fv + " in " + owner); | ||
| } | ||
|
|
||
| /** The type scala.Ref[tp] | ||
| */ | ||
| Type refType(Type tp) { | ||
| Symbol refClass = global.definitions.getClass(Names.scala_Ref); | ||
| assert refClass.kind == Kinds.CLASS; | ||
| return Type.TypeRef(global.definitions.SCALA_TYPE, refClass, new Type[]{tp}); | ||
| } | ||
|
|
||
| public Checker[] postCheckers(Global global) { | ||
| return new Checker[] { | ||
| new CheckSymbols(global), | ||
| new CheckTypes(global), | ||
| new CheckOwners(global) | ||
| }; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.transformer; | ||
|
|
||
| import java.io.*; | ||
| import java.util.*; | ||
| import scalac.*; | ||
| import scalac.util.*; | ||
| import scalac.ast.*; | ||
| import scalac.symtab.*; | ||
| import Tree.*; | ||
|
|
||
|
|
||
| /** A default transformer class which also maintains owner information | ||
| * | ||
| * @author Martin Odersky | ||
| * @version 1.0 | ||
| */ | ||
| public class OwnerTransformer extends Transformer { | ||
|
|
||
| protected Symbol currentOwner; | ||
|
|
||
| public OwnerTransformer(Global global, PhaseDescriptor descr) { | ||
| super(global, descr); | ||
| } | ||
|
|
||
| public void apply(Unit unit) { | ||
| currentOwner = global.definitions.ROOT_CLASS; | ||
| unit.body = transform(unit.body); | ||
| } | ||
|
|
||
| public Tree transform(Tree tree, Symbol owner) { | ||
| Symbol prevOwner = currentOwner; | ||
| currentOwner = owner; | ||
| Tree tree1 = transform(tree); | ||
| currentOwner = prevOwner; | ||
| return tree1; | ||
| } | ||
|
|
||
| public TypeDef[] transform(TypeDef[] params, Symbol owner) { | ||
| Symbol prevOwner = currentOwner; | ||
| currentOwner = owner; | ||
| TypeDef[] res = transform(params); | ||
| currentOwner = prevOwner; | ||
| return res; | ||
| } | ||
|
|
||
| public ValDef[][] transform(ValDef[][] params, Symbol owner) { | ||
| Symbol prevOwner = currentOwner; | ||
| currentOwner = owner; | ||
| ValDef[][] res = transform(params); | ||
| currentOwner = prevOwner; | ||
| return res; | ||
| } | ||
|
|
||
| public Template transform(Template templ, Symbol owner) { | ||
| Symbol prevOwner = currentOwner; | ||
| if (owner.kind == Kinds.CLASS) | ||
| currentOwner = owner.constructor(); | ||
| Tree[] parents1 = transform(templ.parents); | ||
| currentOwner = owner; | ||
| Tree[] body1 = transformTemplateStats(templ.body, templ.symbol()); | ||
| currentOwner = prevOwner; | ||
| return copy.Template(templ, parents1, body1); | ||
| } | ||
|
|
||
| public Tree[] transformTemplateStats(Tree[] ts, Symbol tsym) { | ||
| Tree[] ts1 = ts; | ||
| for (int i = 0; i < ts.length; i++) { | ||
| Tree t = transformTemplateStat(ts[i], tsym); | ||
| if (t != ts[i] && ts1 == ts) { | ||
| ts1 = new Tree[ts.length]; | ||
| System.arraycopy(ts, 0, ts1, 0, i); | ||
| } | ||
| ts1[i] = t; | ||
| } | ||
| return ts1; | ||
| } | ||
|
|
||
| public Tree transformTemplateStat(Tree stat, Symbol tsym) { | ||
| return transform(stat, tsym); | ||
| } | ||
|
|
||
| public Tree transform(Tree tree) { | ||
| switch(tree) { | ||
| case PackageDef(Tree packaged, Template impl): | ||
| return copy.PackageDef( | ||
| tree, transform(packaged), transform(impl, packaged.symbol())); | ||
|
|
||
| case ClassDef(int mods, Name name, TypeDef[] tparams, ValDef[][] vparams, Tree tpe, Template impl): | ||
| return copy.ClassDef( | ||
| tree, mods, name, | ||
| transform(tparams, tree.symbol()), | ||
| transform(vparams, tree.symbol()), | ||
| transform(tpe), | ||
| transform(impl, tree.symbol())); | ||
|
|
||
| case ModuleDef(int mods, Name name, Tree tpe, Template impl): | ||
| return copy.ModuleDef( | ||
| tree, mods, name, transform(tpe), | ||
| transform(impl, tree.symbol().moduleClass())); | ||
|
|
||
| case DefDef(int mods, Name name, TypeDef[] tparams, ValDef[][] vparams, Tree tpe, Tree rhs): | ||
| return copy.DefDef( | ||
| tree, mods, name, | ||
| transform(tparams, tree.symbol()), | ||
| transform(vparams, tree.symbol()), | ||
| transform(tpe, tree.symbol()), | ||
| transform(rhs, tree.symbol())); | ||
|
|
||
| case ValDef(int mods, Name name, Tree tpe, Tree rhs): | ||
| return copy.ValDef( | ||
| tree, mods, name, transform(tpe), | ||
| transform(rhs)); | ||
|
|
||
| case TypeDef(int mods, Name name, TypeDef[] tparams, Tree rhs): | ||
| return copy.TypeDef( | ||
| tree, mods, name, | ||
| transform(tparams, tree.symbol()), | ||
| transform(rhs, tree.symbol())); | ||
|
|
||
| default: | ||
| return super.transform(tree); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,180 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.transformer; | ||
|
|
||
| import java.io.*; | ||
| import java.util.*; | ||
| import scalac.*; | ||
| import scalac.util.*; | ||
| import scalac.ast.*; | ||
| import scalac.symtab.*; | ||
| import Tree.*; | ||
|
|
||
| /** Make all functions into one-argument functions | ||
| */ | ||
| public class UnCurry extends OwnerTransformer | ||
| implements Modifiers { | ||
|
|
||
| UnCurryPhase descr; | ||
|
|
||
| public UnCurry(Global global, UnCurryPhase descr) { | ||
| super(global, descr); | ||
| this.descr = descr; | ||
| } | ||
|
|
||
| /** (ps_1) ... (ps_n) => (ps_1, ..., ps_n) | ||
| */ | ||
| ValDef[][] uncurry(ValDef[][] params) { | ||
| int n = 0; | ||
| for (int i = 0; i < params.length; i++) | ||
| n = n + params[i].length; | ||
| ValDef[] ps = new ValDef[n]; | ||
| int j = 0; | ||
| for (int i = 0; i < params.length; i++) { | ||
| System.arraycopy(params[i], 0, ps, j, params[i].length); | ||
| j = j + params[i].length; | ||
| } | ||
| return new ValDef[][]{ps}; | ||
| } | ||
|
|
||
| /** tree of non-method type T ==> same tree with method type ()T | ||
| */ | ||
| Tree asMethod(Tree tree) { | ||
| switch (tree.type) { | ||
| case MethodType(_, _): | ||
| return tree; | ||
| default: | ||
| return tree.setType(Type.MethodType(Symbol.EMPTY_ARRAY, tree.type)); | ||
| } | ||
| } | ||
|
|
||
| /** - uncurry all symbol and tree types (@see UnCurryPhase) | ||
| * - for every curried parameter list: (ps_1) ... (ps_n) ==> (ps_1, ..., ps_n) | ||
| * - for every curried application: f(args_1)...(args_n) ==> f(args_1, ..., args_n) | ||
| * - for every type application: f[Ts] ==> f[Ts]() unless followed by parameters | ||
| * - for every use of a parameterless function: f ==> f() and q.f ==> q.f() | ||
| * - for every def-parameter: def x: T ==> x: () => T | ||
| * - for every use of a def-parameter: x ==> x.apply() | ||
| * - for every argument to a def parameter `def x: T': | ||
| * if argument is not a reference to a def parameter: | ||
| * convert argument `e' to (expansion of) `() => e' | ||
| */ | ||
| public Tree transform(Tree tree) { | ||
| //uncurry type and symbol | ||
| if (tree.type != null) tree.type = descr.uncurry(tree.type); | ||
| switch (tree) { | ||
| case ClassDef(int mods, Name name, TypeDef[] tparams, ValDef[][] vparams, Tree tpe, Template impl): | ||
| return copy.ClassDef( | ||
| tree, mods, name, tparams, | ||
| uncurry(transform(vparams, tree.symbol())), | ||
| tpe, | ||
| transform(impl, tree.symbol())); | ||
|
|
||
| case DefDef(int mods, Name name, TypeDef[] tparams, ValDef[][] vparams, Tree tpe, Tree rhs): | ||
| Tree rhs1 = transform(rhs, tree.symbol()); | ||
| if (global.debug) global.log(name + ":" + rhs1.type);//debug | ||
| return copy.DefDef( | ||
| tree, mods, name, tparams, | ||
| uncurry(transform(vparams, tree.symbol())), | ||
| tpe, rhs1); | ||
|
|
||
| case ValDef(int mods, Name name, Tree tpe, Tree rhs): | ||
| if (tree.symbol().isDefParameter()) { | ||
| int mods1 = mods & ~ DEF; | ||
| Type newtype = global.definitions.functionType(Type.EMPTY_ARRAY, tpe.type); | ||
| Tree tpe1 = gen.mkType(tpe.pos, newtype); | ||
| return copy.ValDef(tree, mods1, name, tpe1, rhs).setType(newtype); | ||
| } else { | ||
| return tree; | ||
| } | ||
|
|
||
| case TypeApply(Tree fn, Tree[] args): | ||
| Tree tree1 = asMethod(super.transform(tree)); | ||
| return gen.Apply(tree1, new Tree[0]); | ||
|
|
||
| case Apply(Tree fn, Tree[] args): | ||
| // f(x)(y) ==> f(x, y) | ||
| // argument to parameterless function e => ( => e) | ||
| Type ftype = fn.type; | ||
| Tree fn1 = transform(fn); | ||
| Tree[] args1 = transformArgs(args, ftype); | ||
| switch (fn1) { | ||
| case Apply(Tree fn2, Tree[] args2): | ||
| Tree[] newargs = new Tree[args1.length + args2.length]; | ||
| System.arraycopy(args2, 0, newargs, 0, args2.length); | ||
| System.arraycopy(args1, 0, newargs, args2.length, args1.length); | ||
| return copy.Apply(tree, fn2, newargs); | ||
| default: | ||
| return copy.Apply(tree, fn1, args1); | ||
| } | ||
|
|
||
| case Select(_, _): | ||
| case Ident(_): | ||
| Tree tree1 = super.transform(tree); | ||
| switch (tree1.symbol().type()) { | ||
| case PolyType(Symbol[] tparams, Type restp): | ||
| if (tparams.length == 0 && !(restp instanceof Type.MethodType)) { | ||
| return gen.Apply(asMethod(tree1), new Tree[0]); | ||
| } else { | ||
| return tree1; | ||
| } | ||
| default: | ||
| if (tree1.symbol().isDefParameter()) { | ||
| tree1.type = global.definitions.functionType( | ||
| Type.EMPTY_ARRAY, tree1.type); | ||
| return gen.Apply(gen.Select(tree1, Names.apply), new Tree[0]); | ||
| } else { | ||
| return tree1; | ||
| } | ||
| } | ||
|
|
||
| default: | ||
| return super.transform(tree); | ||
| } | ||
| } | ||
|
|
||
| /** Transform arguments `args' to method with type `methtype'. | ||
| */ | ||
| private Tree[] transformArgs(Tree[] args, Type methtype) { | ||
| switch (methtype) { | ||
| case MethodType(Symbol[] params, _): | ||
| for (int i = 0; i < args.length; i++) { | ||
| args[i] = transformArg(args[i], params[i]); | ||
| } | ||
| return args; | ||
| case PolyType(_, Type restp): | ||
| return transformArgs(args, restp); | ||
| default: | ||
| throw new ApplicationError(methtype); | ||
| } | ||
| } | ||
|
|
||
| /** for every argument to a def parameter `def x: T': | ||
| * if argument is not a reference to a def parameter: | ||
| * convert argument `e' to (expansion of) `() => e' | ||
| */ | ||
| private Tree transformArg(Tree arg, Symbol formal) { | ||
| Tree arg1 = transform(arg); | ||
| if ((formal.flags & DEF) != 0) { | ||
| Symbol sym = arg.symbol(); | ||
| if (sym != null && (sym.flags & DEF) != 0) { | ||
| switch (arg1) { | ||
| case Apply(Select(Tree qual, Name name), Tree[] args1): | ||
| assert name == Names.apply && args1.length == 0; | ||
| return qual; | ||
| default: | ||
| global.debugPrinter.print(arg);//debug | ||
| throw new ApplicationError(); | ||
| } | ||
| } | ||
| return transform(gen.mkUnitFunction( | ||
| arg, descr.uncurry(arg.type), currentOwner)); | ||
| } else return arg1; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.transformer; | ||
|
|
||
| import scalac.*; | ||
| import scalac.parser.*; | ||
| import scalac.symtab.*; | ||
| import scalac.typechecker.Infer; | ||
| import scalac.checkers.*; | ||
|
|
||
| public class UnCurryPhase extends PhaseDescriptor implements Modifiers { | ||
|
|
||
| private Global global; | ||
|
|
||
| public void initialize(Global global, int id) { | ||
| super.initialize(global, id); | ||
| this.global = global; | ||
| } | ||
|
|
||
| public String name () { | ||
| return "uncurry"; | ||
| } | ||
|
|
||
| public String description () { | ||
| return "uncurry function types and applications"; | ||
| } | ||
|
|
||
| public String taskDescription() { | ||
| return "uncurried"; | ||
| } | ||
|
|
||
| public Phase createPhase(Global global) { | ||
| return new UnCurry(global, this); | ||
| } | ||
|
|
||
| /** - return symbol's transformed type, | ||
| * - if symbol is a def parameter with transformed type T, return () => T | ||
| */ | ||
| public Type transformInfo(Symbol sym, Type tp0) { | ||
| Type tp1 = uncurry(tp0); | ||
| if (sym.isDefParameter()) return global.definitions.functionType(Type.EMPTY_ARRAY, tp1); | ||
| else return tp1; | ||
| } | ||
|
|
||
| /** - (ps_1)...(ps_n)T ==> (ps_1,...,ps_n)T | ||
| */ | ||
| Type uncurry(Type tp) { | ||
| switch (tp) { | ||
| case MethodType(Symbol[] params, Type tp1): | ||
| Symbol[] uncurriedParams = uncurryParams(params); | ||
| Type uncurriedTp1 = uncurry(tp1); | ||
| switch (uncurriedTp1) { | ||
| case MethodType(Symbol[] params1, Type tp2): | ||
| Symbol[] newparams = new Symbol[uncurriedParams.length + params1.length]; | ||
| System.arraycopy(uncurriedParams, 0, newparams, 0, uncurriedParams.length); | ||
| System.arraycopy(params1, 0, newparams, uncurriedParams.length, params1.length); | ||
| return Type.MethodType(newparams, tp2); | ||
| default: | ||
| if (uncurriedParams == params && uncurriedTp1 == tp1) return tp; | ||
| else return Type.MethodType(uncurriedParams, uncurriedTp1); | ||
| } | ||
| case PolyType(Symbol[] tparams, Type tp1): | ||
| if (tp instanceof Infer.VirtualPolyType) | ||
| return uncurry(tp1); | ||
| switch (tp1) { | ||
| case MethodType(_, _): | ||
| Type newtp1 = uncurry(tp1); | ||
| if (tp1 != newtp1) return Type.PolyType(tparams, newtp1); | ||
| else return tp; | ||
| default: | ||
| Type newtp1 = Type.MethodType(Symbol.EMPTY_ARRAY, tp1); | ||
| if (tparams.length == 0) return newtp1; | ||
| else return Type.PolyType(tparams, newtp1); | ||
| } | ||
| case OverloadedType(_, _): | ||
| return new Type.Map() { | ||
| public Type apply(Type t) { return uncurry(t); } | ||
| }.map(tp); | ||
| default: | ||
| return tp; | ||
| } | ||
| } | ||
|
|
||
| Symbol[] uncurryParams(Symbol[] params) { | ||
| Symbol[] params1 = params; | ||
| for (int i = 0; i < params.length; i++) { | ||
| Symbol param = params[i]; | ||
| Symbol param1 = param; | ||
| Type tp = param.info(); | ||
| Type tp1 = transformInfo(param, tp); | ||
| if (tp != tp1) { | ||
| if (params1 == params) { | ||
| params1 = new Symbol[params.length]; | ||
| System.arraycopy(params, 0, params1, 0, i); | ||
| } | ||
| param1 = param.cloneSymbol().setType(tp1); | ||
| param1.flags &= ~DEF; | ||
| } | ||
| params1[i] = param1; | ||
| } | ||
| return params1; | ||
| } | ||
|
|
||
| public Checker[] postCheckers(Global global) { | ||
| return new Checker[] { | ||
| new CheckSymbols(global), | ||
| new CheckTypes(global), | ||
| new CheckOwners(global) | ||
| }; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.typechecker; | ||
|
|
||
| import scalac.*; | ||
| import scalac.util.*; | ||
| import scalac.ast.*; | ||
| import scalac.symtab.*; | ||
| import scalac.checkers.*; | ||
| import java.util.HashMap; | ||
| import java.util.ArrayList; | ||
|
|
||
| public class AnalyzerPhase extends PhaseDescriptor { | ||
|
|
||
| /* final */ Context startContext; | ||
| HashMap/*<Unit,Context>*/ contexts = new HashMap(); | ||
| ArrayList/*<Unit>*/ newSources = new ArrayList(); | ||
|
|
||
| public void initialize(Global global, int id) { | ||
| super.initialize(global, id); | ||
| Definitions definitions = global.definitions; | ||
| this.startContext = new Context( | ||
| Tree.Empty, | ||
| definitions.ROOT_CLASS, | ||
| definitions.ROOT_CLASS.members(), | ||
| Context.NONE); | ||
| this.startContext.enclClass = this.startContext; | ||
|
|
||
| if (!global.noimports) { | ||
| TreeFactory make = global.make; | ||
|
|
||
| Tree java = make.Ident(Position.NOPOS, Names.java) | ||
| .setSymbol(definitions.JAVA) | ||
| .setType(Type.singleType(definitions.ROOT_TYPE, definitions.JAVA)); | ||
| Tree javalang = make.Select(Position.NOPOS, java, Names.lang) | ||
| .setSymbol(definitions.JAVALANG) | ||
| .setType(Type.singleType(java.type, definitions.JAVALANG)); | ||
| Tree importjavalang = make.Import( | ||
| Position.NOPOS, javalang, new Name[]{Names.WILDCARD}) | ||
| .setSymbol(definitions.JAVALANG) | ||
| .setType(definitions.UNIT_TYPE); | ||
| startContext.imports = new ImportList( | ||
| importjavalang, startContext.scope, startContext.imports); | ||
|
|
||
| Tree scala = make.Ident(Position.NOPOS, Names.scala) | ||
| .setSymbol(definitions.SCALA) | ||
| .setType(Type.singleType(definitions.ROOT_TYPE, definitions.SCALA)); | ||
| Tree importscala = make.Import( | ||
| Position.NOPOS, scala, new Name[]{Names.WILDCARD}) | ||
| .setSymbol(definitions.SCALA) | ||
| .setType(definitions.UNIT_TYPE); | ||
| startContext.imports = new ImportList( | ||
| importscala, new Scope(), startContext.imports); | ||
|
|
||
| scala = make.Ident(Position.NOPOS, Names.scala) | ||
| .setSymbol(definitions.SCALA) | ||
| .setType(scala.type); | ||
| Symbol scalaPredefSym = definitions.getModule(Names.scala_Predef); | ||
| Tree scalaPredef = make.Select(Position.NOPOS, scala, Names.Predef) | ||
| .setSymbol(scalaPredefSym) | ||
| .setType(Type.singleType(scala.type, scalaPredefSym)); | ||
|
|
||
| Tree importscalaPredef = make.Import( | ||
| Position.NOPOS, scalaPredef, new Name[]{Names.WILDCARD}) | ||
| .setSymbol(scalaPredefSym) | ||
| .setType(definitions.UNIT_TYPE); | ||
| startContext.imports = new ImportList( | ||
| importscalaPredef, new Scope(), startContext.imports); | ||
| } | ||
| } | ||
|
|
||
| public String name() { | ||
| return "analyze"; | ||
| } | ||
|
|
||
| public String description () { | ||
| return "name and type analysis"; | ||
| } | ||
|
|
||
| public String taskDescription() { | ||
| return "type checking"; | ||
| } | ||
|
|
||
| public Phase createPhase(Global global) { | ||
| return new Analyzer(global, this); | ||
| } | ||
|
|
||
| public Checker[] postCheckers(Global global) { | ||
| return new Checker[] { | ||
| /* todo: uncomment | ||
| new CheckSymbols(global), | ||
| new CheckTypes(global), | ||
| new CheckOwners(global) | ||
| */ | ||
| }; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| /* ____ ____ ____ ____ ______ *\ | ||
| ** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** | ||
| ** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** | ||
| ** /_____/\____/\___/\____/____/ ** | ||
| ** | ||
| ** $Id$ | ||
| \* */ | ||
|
|
||
| package scalac.typechecker; | ||
|
|
||
| import scalac.symtab.*; | ||
| import scalac.ast.Tree; | ||
|
|
||
| public class Context { | ||
| Tree tree; // Tree associated with this context | ||
| Symbol owner; // The current owner | ||
| Scope scope; // The current scope | ||
| ImportList imports; // The current import list | ||
| Context outer; // The next outer context | ||
| Context enclClass = this; // The next outer context whose tree | ||
| // is a class template | ||
| boolean delayArgs = false; // delay checking of type arguments | ||
|
|
||
| public Context() {} | ||
|
|
||
| public Context(Tree tree, Context outer) { | ||
| this(tree, outer.owner, outer.scope, outer); | ||
| } | ||
|
|
||
| public Context(Tree tree, Symbol owner, Scope scope, Context outer) { | ||
| this.tree = tree; | ||
| this.owner = owner; | ||
| this.scope = scope; | ||
| this.imports = outer.imports; | ||
| if (tree instanceof Tree.Template || | ||
| tree instanceof Tree.CompoundType) this.enclClass = this; | ||
| else this.enclClass = outer.enclClass; | ||
| this.delayArgs = outer.delayArgs; | ||
| this.outer = outer; | ||
| } | ||
|
|
||
| public static Context NONE = new Context(); | ||
|
|
||
| Context outerContext(Symbol clazz) { | ||
| Context c = this; | ||
| while (c != Context.NONE && c.owner != clazz) c = c.outer; | ||
| return c; | ||
| } | ||
|
|
||
| boolean isTopLevel() { | ||
| switch (tree) { | ||
| case Block(_): | ||
| return false; | ||
| case Template(_, _): | ||
| return outer.tree instanceof Tree.PackageDef; | ||
| case Empty: | ||
| return true; | ||
| default: | ||
| return outer.isTopLevel(); | ||
| } | ||
| } | ||
| } | ||
|
|