From 4177daab2f54bdb20c71f623296a8bb32616fd12 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 13 Feb 2003 14:41:36 +0000 Subject: Initial version. --- sources/scalac/ApplicationError.java | 87 + sources/scalac/CompilerCommand.java | 221 ++ sources/scalac/Global.java | 354 +++ sources/scalac/Main.java | 38 + sources/scalac/Phase.java | 45 + sources/scalac/PhaseDescriptor.java | 169 ++ sources/scalac/PhaseRepository.java | 96 + sources/scalac/Unit.java | 123 + sources/scalac/ast/AbstractTreeCopyFactory.java | 30 + sources/scalac/ast/LazyTreeFactory.java | 430 ++++ sources/scalac/ast/Transformer.java | 401 ++++ sources/scalac/ast/Traverser.java | 215 ++ sources/scalac/ast/Tree.java | 771 +++++++ sources/scalac/ast/TreeCopyFactory.java | 165 ++ sources/scalac/ast/TreeCreator.java | 293 +++ sources/scalac/ast/TreeFactory.java | 155 ++ sources/scalac/ast/TreeGen.java | 562 +++++ sources/scalac/ast/TreeInfo.java | 136 ++ sources/scalac/ast/TreeList.java | 71 + sources/scalac/ast/parser/Parser.java | 1704 ++++++++++++++ sources/scalac/ast/parser/ParserPhase.java | 63 + sources/scalac/ast/parser/Scanner.java | 793 +++++++ .../scalac/ast/parser/SourceRepresentation.java | 205 ++ sources/scalac/ast/parser/Sourcefile.java | 304 +++ sources/scalac/ast/parser/TokenData.java | 44 + sources/scalac/ast/parser/Tokens.java | 84 + sources/scalac/ast/printer/HTMLTreePrinter.java | 173 ++ sources/scalac/ast/printer/TextTreePrinter.java | 683 ++++++ sources/scalac/ast/printer/TreePrinter.java | 34 + sources/scalac/checkers/CheckOwners.java | 168 ++ sources/scalac/checkers/CheckSymbols.java | 36 + sources/scalac/checkers/CheckTypes.java | 30 + sources/scalac/checkers/Checker.java | 41 + sources/scalac/symtab/Definitions.java | 421 ++++ sources/scalac/symtab/Kinds.java | 28 + sources/scalac/symtab/Modifiers.java | 135 ++ sources/scalac/symtab/NameMangler.java | 33 + sources/scalac/symtab/Scope.java | 306 +++ sources/scalac/symtab/SourceCompleter.java | 53 + sources/scalac/symtab/SymSet.java | 89 + sources/scalac/symtab/Symbol.java | 1291 +++++++++++ sources/scalac/symtab/Type.java | 2353 ++++++++++++++++++++ sources/scalac/symtab/TypeTags.java | 47 + .../scalac/symtab/classfile/AttributeParser.java | 439 ++++ sources/scalac/symtab/classfile/ClassParser.java | 111 + .../symtab/classfile/ClassfileConstants.java | 57 + .../scalac/symtab/classfile/ClassfileParser.java | 239 ++ sources/scalac/symtab/classfile/ConstantPool.java | 183 ++ .../scalac/symtab/classfile/JavaTypeCreator.java | 82 + .../scalac/symtab/classfile/JavaTypeFactory.java | 28 + sources/scalac/symtab/classfile/PackageParser.java | 129 ++ sources/scalac/symtab/classfile/Signatures.java | 122 + sources/scalac/transformer/LambdaLift.java | 508 +++++ sources/scalac/transformer/LambdaLiftPhase.java | 135 ++ sources/scalac/transformer/OwnerTransformer.java | 132 ++ sources/scalac/transformer/UnCurry.java | 180 ++ sources/scalac/transformer/UnCurryPhase.java | 117 + sources/scalac/typechecker/Analyzer.java | 1975 ++++++++++++++++ sources/scalac/typechecker/AnalyzerPhase.java | 103 + sources/scalac/typechecker/Context.java | 63 + sources/scalac/typechecker/DeSugarize.java | 681 ++++++ sources/scalac/typechecker/ImportList.java | 64 + sources/scalac/typechecker/Infer.java | 814 +++++++ sources/scalac/typechecker/RefCheck.java | 208 ++ sources/scalac/typechecker/RefCheckPhase.java | 42 + sources/scalac/util/AbstractFile.java | 557 +++++ sources/scalac/util/AbstractFileReader.java | 107 + sources/scalac/util/ArrayApply.java | 54 + sources/scalac/util/ClassPath.java | 161 ++ sources/scalac/util/Debug.java | 465 ++++ sources/scalac/util/FreshNameCreator.java | 59 + sources/scalac/util/Name.java | 391 ++++ sources/scalac/util/NameTransformer.java | 111 + sources/scalac/util/Names.java | 98 + sources/scalac/util/OptionParser.java | 546 +++++ sources/scalac/util/Position.java | 54 + sources/scalac/util/PrefixMatcher.java | 114 + sources/scalac/util/Reporter.java | 192 ++ sources/scalac/util/SourceRepresentation.java | 205 ++ sources/scalac/util/Strings.java | 102 + sources/scalac/util/UniqueID.java | 30 + 81 files changed, 23138 insertions(+) create mode 100644 sources/scalac/ApplicationError.java create mode 100644 sources/scalac/CompilerCommand.java create mode 100644 sources/scalac/Global.java create mode 100644 sources/scalac/Main.java create mode 100644 sources/scalac/Phase.java create mode 100644 sources/scalac/PhaseDescriptor.java create mode 100644 sources/scalac/PhaseRepository.java create mode 100644 sources/scalac/Unit.java create mode 100644 sources/scalac/ast/AbstractTreeCopyFactory.java create mode 100644 sources/scalac/ast/LazyTreeFactory.java create mode 100644 sources/scalac/ast/Transformer.java create mode 100644 sources/scalac/ast/Traverser.java create mode 100644 sources/scalac/ast/Tree.java create mode 100644 sources/scalac/ast/TreeCopyFactory.java create mode 100644 sources/scalac/ast/TreeCreator.java create mode 100644 sources/scalac/ast/TreeFactory.java create mode 100644 sources/scalac/ast/TreeGen.java create mode 100644 sources/scalac/ast/TreeInfo.java create mode 100644 sources/scalac/ast/TreeList.java create mode 100644 sources/scalac/ast/parser/Parser.java create mode 100644 sources/scalac/ast/parser/ParserPhase.java create mode 100644 sources/scalac/ast/parser/Scanner.java create mode 100644 sources/scalac/ast/parser/SourceRepresentation.java create mode 100644 sources/scalac/ast/parser/Sourcefile.java create mode 100644 sources/scalac/ast/parser/TokenData.java create mode 100644 sources/scalac/ast/parser/Tokens.java create mode 100644 sources/scalac/ast/printer/HTMLTreePrinter.java create mode 100644 sources/scalac/ast/printer/TextTreePrinter.java create mode 100644 sources/scalac/ast/printer/TreePrinter.java create mode 100644 sources/scalac/checkers/CheckOwners.java create mode 100644 sources/scalac/checkers/CheckSymbols.java create mode 100644 sources/scalac/checkers/CheckTypes.java create mode 100644 sources/scalac/checkers/Checker.java create mode 100644 sources/scalac/symtab/Definitions.java create mode 100644 sources/scalac/symtab/Kinds.java create mode 100644 sources/scalac/symtab/Modifiers.java create mode 100644 sources/scalac/symtab/NameMangler.java create mode 100644 sources/scalac/symtab/Scope.java create mode 100644 sources/scalac/symtab/SourceCompleter.java create mode 100644 sources/scalac/symtab/SymSet.java create mode 100644 sources/scalac/symtab/Symbol.java create mode 100644 sources/scalac/symtab/Type.java create mode 100644 sources/scalac/symtab/TypeTags.java create mode 100644 sources/scalac/symtab/classfile/AttributeParser.java create mode 100644 sources/scalac/symtab/classfile/ClassParser.java create mode 100644 sources/scalac/symtab/classfile/ClassfileConstants.java create mode 100644 sources/scalac/symtab/classfile/ClassfileParser.java create mode 100644 sources/scalac/symtab/classfile/ConstantPool.java create mode 100644 sources/scalac/symtab/classfile/JavaTypeCreator.java create mode 100644 sources/scalac/symtab/classfile/JavaTypeFactory.java create mode 100644 sources/scalac/symtab/classfile/PackageParser.java create mode 100644 sources/scalac/symtab/classfile/Signatures.java create mode 100644 sources/scalac/transformer/LambdaLift.java create mode 100644 sources/scalac/transformer/LambdaLiftPhase.java create mode 100644 sources/scalac/transformer/OwnerTransformer.java create mode 100644 sources/scalac/transformer/UnCurry.java create mode 100644 sources/scalac/transformer/UnCurryPhase.java create mode 100644 sources/scalac/typechecker/Analyzer.java create mode 100644 sources/scalac/typechecker/AnalyzerPhase.java create mode 100644 sources/scalac/typechecker/Context.java create mode 100644 sources/scalac/typechecker/DeSugarize.java create mode 100644 sources/scalac/typechecker/ImportList.java create mode 100644 sources/scalac/typechecker/Infer.java create mode 100644 sources/scalac/typechecker/RefCheck.java create mode 100644 sources/scalac/typechecker/RefCheckPhase.java create mode 100644 sources/scalac/util/AbstractFile.java create mode 100644 sources/scalac/util/AbstractFileReader.java create mode 100644 sources/scalac/util/ArrayApply.java create mode 100644 sources/scalac/util/ClassPath.java create mode 100644 sources/scalac/util/Debug.java create mode 100644 sources/scalac/util/FreshNameCreator.java create mode 100644 sources/scalac/util/Name.java create mode 100644 sources/scalac/util/NameTransformer.java create mode 100644 sources/scalac/util/Names.java create mode 100644 sources/scalac/util/OptionParser.java create mode 100644 sources/scalac/util/Position.java create mode 100644 sources/scalac/util/PrefixMatcher.java create mode 100644 sources/scalac/util/Reporter.java create mode 100644 sources/scalac/util/SourceRepresentation.java create mode 100644 sources/scalac/util/Strings.java create mode 100644 sources/scalac/util/UniqueID.java (limited to 'sources/scalac') diff --git a/sources/scalac/ApplicationError.java b/sources/scalac/ApplicationError.java new file mode 100644 index 0000000000..e689217eec --- /dev/null +++ b/sources/scalac/ApplicationError.java @@ -0,0 +1,87 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac; + +import java.io.PrintStream; +import java.io.PrintWriter; + +import scalac.util.Debug; + +public class ApplicationError extends Error { + + //######################################################################## + // Private state + + private final Throwable cause; // !!! remove and use API 1.4 + + //######################################################################## + // Private interface + + private static String combine(String message, Object object) { + String string = Debug.show(object); + return message == null ? string : message + ": " + string; + } + + //######################################################################## + // ApplicationError constructors + + public ApplicationError() { + this((String)null, (Throwable)null); + } + + public ApplicationError(String message) { + this(message, (Throwable)null); + } + + public ApplicationError(Object object) { + this(null, object, null); + } + + public ApplicationError(Throwable cause) { + this((String)null, cause); + } + + public ApplicationError(String message, Object object) { + this(message, object, null); + } + + public ApplicationError(String message, Throwable cause) { + super(message); + this.cause = cause; + } + + public ApplicationError(Object object, Throwable cause) { + this(null, object, cause); + } + + public ApplicationError(String message, Object object, Throwable cause) { + this(combine(message, object), cause); + } + + //######################################################################## + // Throwable interface + + public void printStackTrace(PrintStream printer) { + super.printStackTrace(printer); + if (cause != null) { + printer.print("Caused by: "); + cause.printStackTrace(printer); + } + } + + public void printStackTrace(PrintWriter printer) { + super.printStackTrace(printer); + if (cause != null) { + printer.print("Caused by: "); + cause.printStackTrace(printer); + } + } + + //######################################################################## +} diff --git a/sources/scalac/CompilerCommand.java b/sources/scalac/CompilerCommand.java new file mode 100644 index 0000000000..743187e81f --- /dev/null +++ b/sources/scalac/CompilerCommand.java @@ -0,0 +1,221 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac; + +import java.util.List; +import java.util.ArrayList; + +import scalac.util.ClassPath; +import scalac.util.Reporter; +import scalac.util.CommandParser; +import scalac.util.ArgumentParser; +import scalac.util.OptionParser; +import scalac.util.BooleanOptionParser; +import scalac.util.StringOptionParser; +import scalac.util.ChoiceOptionParser; +import scalac.util.HelpOptionParser; +import scalac.util.VersionOptionParser; +//import scalac.util.OptimizeOptionParser; +import scalac.util.PhaseSetOptionParser; +import scalac.util.PrintOptionParser; +import scalac.util.UnknownOptionParser; +import scalac.util.ScalaFileArgumentParser; +import scalac.util.UnknownArgumentParser; +import scalac.util.Strings; + +public class CompilerCommand extends CommandParser { + + public final PhaseRepository phases; + + public final BooleanOptionParser nowarn; + public final BooleanOptionParser verbose; + public final BooleanOptionParser debug; + public final BooleanOptionParser uniqid; + public final BooleanOptionParser types; + public final BooleanOptionParser prompt; + //public final OptimizeOptionParser optimize; + public final StringOptionParser classpath; + public final StringOptionParser sourcepath; + public final StringOptionParser bootclasspath; + public final StringOptionParser extdirs; + public final StringOptionParser outpath; + public final ChoiceOptionParser target; + public final BooleanOptionParser noimports; + public final StringOptionParser jaco; + public final PhaseSetOptionParser skip; + public final PhaseSetOptionParser check; + public final PrintOptionParser print; + public final ChoiceOptionParser printer; + public final StringOptionParser printfile; + public final PhaseSetOptionParser graph; + public final PhaseSetOptionParser stop; + public final PhaseSetOptionParser log; + public final VersionOptionParser version; + public final HelpOptionParser help; + public final UnknownOptionParser unknown_options; + public final ScalaFileArgumentParser files; + public final UnknownArgumentParser unknown_arguments; + + public CompilerCommand(String product, String version, + Reporter reporter, PhaseRepository phases) + { + this(product, version, "", reporter, phases); + } + + protected CompilerCommand(String product, String version, String syntax, + Reporter reporter, PhaseRepository phases) + { + super(product, version, syntax, reporter); + this.phases = phases; + + ArgumentParser[] parsers = new ArgumentParser[] { + + this.nowarn = new BooleanOptionParser(this, + "nowarn", "Generate no warnings", + false), + + this.verbose = new BooleanOptionParser(this, + "verbose", "Output messages about what the compiler is doing", + false), + + this.debug = new BooleanOptionParser(this, + "debug", "Output debugging messages", + false), + + this.uniqid = new BooleanOptionParser(this, + "uniqid", "Print identifiers with unique names (debugging option)", + false), + + this.types = new BooleanOptionParser(this, + "types", "Print tree types (debugging option)", + false), + + this.prompt = new BooleanOptionParser(this, + "prompt", "Display a prompt after each error (debugging option)", + false), + + //this.optimize = new OptimizeOptionParser(this, + // "optimize", "optimize bytecode (-optimize:help for option list)", + // null /* todo: uncomment: phases.OPTIMIZE */), + + this.classpath = new StringOptionParser(this, + "classpath", "Specify where to find user class files", + "path", ClassPath.CLASS_PATH), + + this.sourcepath = new StringOptionParser(this, + "sourcepath", "Specify where to find input source files", + "path", ClassPath.SOURCE_PATH), + + this.bootclasspath = new StringOptionParser(this, + "bootclasspath", "Override location of bootstrap class files", + "path", ClassPath.BOOT_PATH), + + this.extdirs = new StringOptionParser(this, + "extdirs", "Override location of installed extensions", + "dirs", ClassPath.EXTENSION_PATH), + + this.outpath = new StringOptionParser(this, + "d", "Specify where to place generated class files", + "directory", "."), + + this.target = new ChoiceOptionParser(this, + "target", "Specify which bakend to use", + "target", Global.TARGETS, Global.TARGET_JVM), + + this.noimports = new BooleanOptionParser(this, + "noimports", "Compile without any implicit imports", + false), + + this.jaco = new StringOptionParser(this, + "jaco", "Pass argument to jaco backend (debugging option)", + "argument", null), + + this.skip = new PhaseSetOptionParser(this, + "skip", "Skip (see below)", + phases.phases, PhaseDescriptor.SKIP), + + this.check = new PhaseSetOptionParser(this, + "check", "Check the tree after (see below)", + phases.phases, PhaseDescriptor.CHECK), + + this.print = new PrintOptionParser(this, + "print", "Print out program after (see below)", + phases.phases, PhaseDescriptor.PRINT), + + this.printer = new ChoiceOptionParser(this, + "printer", "Printer to use", + "printer", Global.PRINTERS, Global.PRINTER_TEXT), + + this.printfile = new StringOptionParser(this, + "print-file", "Specify file in which to print trees", + "file", "-"), + + this.graph = new PhaseSetOptionParser(this, + "graph", "Graph the program after (see below)", + phases.phases, PhaseDescriptor.GRAPH), + + this.stop = new PhaseSetOptionParser(this, + "stop", "Stop after first phase in (see below)", + phases.phases, PhaseDescriptor.STOP), + + this.log = new PhaseSetOptionParser(this, + "log", "Log operations in (see below)", + phases.phases, PhaseDescriptor.LOG), + + this.version = new VersionOptionParser(this, + "version", "Print product version and exit", + product() + " " + version() + " -- (c) 2002 LAMP/EPFL"), + + this.help = new HelpOptionParser(this, + "help", "Print a synopsis of standard options"), + + this.unknown_options = new UnknownOptionParser(this), + + this.files = new ScalaFileArgumentParser(this), + + this.unknown_arguments = new UnknownArgumentParser(this), + + }; + + for (int i = 0; i < parsers.length; i++) add(parsers[i]); + } + + public boolean parse(String[] args) { + boolean result = super.parse(args); + reporter().nowarn = nowarn.value; + reporter().verbose = verbose.value; + reporter().prompt = prompt.value; + return result; + } + + public String getHelpMessage() { + StringBuffer buffer = new StringBuffer(super.getHelpMessage()); + buffer.append(Strings.EOL); + buffer.append("and possible compilation phases include:"); + buffer.append(Strings.EOL); + List lines = new ArrayList(phases.phases.length); + for (int i = 0; i < phases.phases.length; i++) { + PhaseDescriptor phase = phases.phases[i]; + lines.add(" " + phase.name() + "\t " + phase.description()); + } + lines.add(" " + "all" + "\t " + "matches all phases"); + buffer.append(Strings.format(lines)); + return buffer.toString(); + } + + public ClassPath classpath() { + return new ClassPath(classpath.value, sourcepath.value, + bootclasspath.value, extdirs.value); + } + + public String outpath() { + return outpath.value + (outpath.value.endsWith("/") ? "" : "/"); + } + +} diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java new file mode 100644 index 0000000000..3c3d73c0e6 --- /dev/null +++ b/sources/scalac/Global.java @@ -0,0 +1,354 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac; + +import java.io.*; +import java.util.*; +import scalac.util.*; +import scalac.ast.*; +import scalac.ast.parser.*; +import scalac.symtab.Definitions; +import scalac.ast.printer.*; + + +/** The global environment of a compiler run + * + * @author Matthias Zenger + * @version 1.0 + */ +public class Global { + + public static Global instance; + + /** global options + */ + public final boolean noimports; + //public final boolean optimize; + public final boolean debug; + public final boolean uniqid; + + public final boolean printtypes; + public final boolean printtokens; + + public final String outpath; + public final String target; + + public final String jacoDebug; + + /** the message reporter + */ + public final Reporter reporter; + + /** a stack for maintaining timestamps + */ + private final Stack startTimes = new Stack(); + + /** all compilation units + */ + public Unit[] units; + + /** the class path + */ + public final ClassPath classPath; + + /** the global tree factory + */ + public final TreeFactory make; + + /** the fresh name creator + */ + public final FreshNameCreator freshNameCreator; + + /** the tree generator + */ + public final TreeGen treeGen; + + /** the unique-id generator + */ + public final UniqueID uniqueID; + + /** the global tree printer + */ + public final TreePrinter printer; + public OutputStream printStream; + public final TreePrinter debugPrinter; + + /** the current phase + */ + public PhaseDescriptor currentPhase; + + /** the global definitions + */ + public Definitions definitions; + + /** the global primitives + */ + //public Primitives primitives; + + /** compilation phases. + */ + public final PhaseRepository PHASE; + public final PhaseDescriptor[] phases; + + public final int POST_ANALYZER_PHASE_ID = 3; + + /** compilation targets + */ + public static final String TARGET_INT; + public static final String TARGET_JAVA; + public static final String TARGET_JVM; + public static final String TARGET_MSIL; + + public static final String[] TARGETS = new String[] { + TARGET_INT = "int".intern(), + TARGET_JAVA = "java".intern(), + TARGET_JVM = "jvm".intern(), + TARGET_MSIL = "msil".intern(), + }; + + /** tree printers + */ + public static final String PRINTER_TEXT; + public static final String PRINTER_HTML; + + public static final String[] PRINTERS = new String[] { + PRINTER_TEXT = "text".intern(), + PRINTER_HTML = "html".intern(), + }; + + public Global(CompilerCommand args) { + this(args, false); + } + + public Global(CompilerCommand args, boolean interpret) { + if (Global.instance != null) { // jaco bug: can't use assert here + new Error("Duplicate creation of Global").printStackTrace(); + System.exit(1); + }; + Global.instance = this; + this.reporter = args.reporter(); + this.start(); // timestamp to compute the total time + this.noimports = args.noimports.value; + //this.optimize = args.optimize.optimize; + this.debug = args.debug.value; + this.uniqid = args.uniqid.value; + this.printtypes = args.types.value; + this.printtokens = args.print.tokens; + this.classPath = args.classpath(); + this.outpath = args.outpath(); + this.target = interpret ? TARGET_INT : args.target.value.intern(); + this.jacoDebug = args.jaco.value; + this.uniqueID = new UniqueID(); + String printFile = args.printfile.value; + try { + this.printStream = "-".equals(printFile) + ? System.out + : new FileOutputStream(printFile); + } catch (FileNotFoundException e) { + error("unable to open file " + printFile + ". Printing on console"); + this.printStream = System.out; + } + String printerName = args.printer.value.intern(); + if (printerName == PRINTER_TEXT) + this.printer = new TextTreePrinter(printStream); + else + this.printer = new HTMLTreePrinter(printStream); + this.debugPrinter = new TextTreePrinter(System.err); + this.freshNameCreator = new FreshNameCreator(); + this.make = new TreeCreator(); + this.currentPhase = PhaseDescriptor.INITIAL; + this.definitions = new Definitions(this); + //this.primitives = new Primitives(this); + this.treeGen = new TreeGen(this, make); + this.PHASE = args.phases; + List phases = new ArrayList(); + phases.add(PHASE.INITIAL); + phases.add(PHASE.PARSER); + phases.add(PHASE.ANALYZER); + phases.add(PHASE.REFCHECK); + phases.add(PHASE.UNCURRY); + /* + if (optimize) { + phases.add(PHASE.OPTIMIZE); + } + phases.add(PHASE.TRANSMATCH); + */ + //phases.add(PHASE.LAMBDALIFT); + /* + phases.add(PHASE.EXPLICITOUTER); + phases.add(PHASE.ADDACCESSORS); + phases.add(PHASE.ADDINTERFACES); + phases.add(PHASE.EXPANDMIXIN); + phases.add(PHASE.ERASURE); + if (target == TARGET_INT || target == TARGET_MSIL || target == TARGET_JVM) { + phases.add(PHASE.ADDCONSTRUCTORS); + } + if (target == TARGET_JAVA) phases.add(PHASE.GENJAVA); + if (target == TARGET_MSIL) phases.add(PHASE.GENMSIL); + if (target == TARGET_JVM) phases.add(PHASE.GENJVM); + */ + phases.add(PHASE.TERMINAL); + this.phases = new PhaseDescriptor[phases.size()]; + for (int i = 0; i < phases.size(); i++) { + PhaseDescriptor phase = (PhaseDescriptor)phases.get(i); + this.phases[i] = phase; + if (i > 0) this.phases[i - 1].flags |= phase.flags >>> 16; + phase.initialize(this, i); + assert phase.id == i; + } + assert PHASE.ANALYZER.id + 1 == POST_ANALYZER_PHASE_ID; + } + + /** Move to next phase + */ + public void nextPhase() { + currentPhase = phases[currentPhase.id + 1]; + } + + /** Move to previous phase + */ + public void prevPhase() { + currentPhase = phases[currentPhase.id - 1]; + } + + /** the top-level compilation process + */ + public void compile(String[] files, boolean console) { + reporter.resetCounters(); + // parse files + List units = new ArrayList(files.length); + for (int i = 0; i < files.length; i++) { + String file = files[i]; + try { + units.add(new Unit(this, new Sourcefile(file, console))); + } catch (FileNotFoundException e) { + error("file " + file + " not found"); + } catch (IOException e) { + error(e.toString()); + } + } + this.units = (Unit[])units.toArray(new Unit[units.size()]); + compile(); + } + + /** the top-level compilation process + */ + public void compile(String input, boolean console) { + reporter.resetCounters(); + Sourcefile source = new Sourcefile(input.getBytes(), console); + units = new Unit[]{new Unit(this, source)}; + compile(); + } + + /** compile all compilation units + */ + private void compile() { + printer.begin(); + + // apply successive phases and pray that it works + for (int i = 0; i < phases.length && reporter.errors() == 0; ++i) { + currentPhase = phases[i]; + if ((currentPhase.flags & PhaseDescriptor.SKIP) != 0) { + operation("skipping phase " + currentPhase.name()); + } else { + currentPhase.apply(this); + } + if ((currentPhase.flags & PhaseDescriptor.PRINT) != 0) + currentPhase.print(this); + if ((currentPhase.flags & PhaseDescriptor.GRAPH) != 0) + currentPhase.graph(this); + if ((currentPhase.flags & PhaseDescriptor.CHECK) != 0) + currentPhase.check(this); + if ((currentPhase.flags & PhaseDescriptor.STOP) != 0) { + operation("stopped after phase " + currentPhase.name()); + break; + } + } + + printer.end(); + } + + /** stop the compilation process immediately + */ + public Error fail() { + throw new ApplicationError(); + } + + /** stop the compilation process immediately + */ + public Error fail(String message) { + throw new ApplicationError(message); + } + + /** stop the compilation process immediately + */ + public Error fail(String message, Object object) { + throw new ApplicationError(message, object); + } + + /** stop the compilation process immediately + */ + public Error fail(Object value) { + throw new ApplicationError(value); + } + + /** issue a global error + */ + public void error(String message) { + reporter.error("error: " + message); + } + + /** issue a global warning + */ + public void warning(String message) { + reporter.warning("warning: " + message); + } + + /** issue a global note (if in verbose mode) + */ + public void note(String message) { + reporter.note("note: " + message); + } + + /** issue an operation note + */ + public void operation(String message) { + reporter.inform("[" + message + "]"); + } + + /** issue a debug message from currentPhase + */ + // the boolean return value is here to let one write "assert log( ... )" + public boolean log(String message) { + if (log()) { + reporter.report("[log " + currentPhase.name() + "] " + message); + } + return true; + } + + /** return true if logging is switched on for the current phase + */ + public boolean log() { + return (currentPhase.flags & PhaseDescriptor.LOG) != 0; + } + + /** start a new timer + */ + public void start() { + startTimes.push(new Long(System.currentTimeMillis())); + } + + /** issue timing information + */ + public void stop(String message) { + long start = ((Long)startTimes.pop()).longValue(); + reporter.inform("[" + message + " in " + + (System.currentTimeMillis() - start) + "ms]"); + } +} diff --git a/sources/scalac/Main.java b/sources/scalac/Main.java new file mode 100644 index 0000000000..2c0dc78140 --- /dev/null +++ b/sources/scalac/Main.java @@ -0,0 +1,38 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac; + +import scalac.util.Reporter; + +/** The main class for SoCoS, a compiler for the programming + * language Scala. + * + * @author Matthias Zenger + * @version 1.0 + */ +public class Main { + + public static final String PRODUCT = + System.getProperty("scala.product", "socos"); + public static final String VERSION = + System.getProperty("scala.version", "unknown version"); + + public static void main(String[] args) { + Reporter reporter = new Reporter(); + CompilerCommand command = new CompilerCommand( + PRODUCT, VERSION, reporter, new PhaseRepository()); + if (command.parse(args) && command.files.list.size() > 0) { + Global global = new Global(command); + global.compile(command.files.toArray(), false); + global.stop("total"); + global.reporter.printSummary(); + } + System.exit((reporter.errors() > 0) ? -1 : 0); + } +} diff --git a/sources/scalac/Phase.java b/sources/scalac/Phase.java new file mode 100644 index 0000000000..bbce46e013 --- /dev/null +++ b/sources/scalac/Phase.java @@ -0,0 +1,45 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac; + +/** Representation of a compiler phase. PhaseDescriptors create + * phase. Phases operate subsequently on all compilation units. + * + * @author Matthias Zenger + * @version 1.0 + */ +public abstract class Phase { + + /** the global environment + */ + public final Global global; + + /** the descriptor for this phase + */ + public final PhaseDescriptor descr; + + /** constructor + */ + public Phase(Global global, PhaseDescriptor descr) { + this.global = global; + this.descr = descr; + } + + /** apply this phase to all compilation units + */ + public void apply() { + for (int i = 0; i < global.units.length; i++) { + apply(global.units[i]); + } + } + + /** apply this phase to the given compilation unit + */ + public abstract void apply(Unit unit); +} diff --git a/sources/scalac/PhaseDescriptor.java b/sources/scalac/PhaseDescriptor.java new file mode 100644 index 0000000000..0316a80215 --- /dev/null +++ b/sources/scalac/PhaseDescriptor.java @@ -0,0 +1,169 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac; + +import java.util.*; +import scalac.ast.printer.*; +import scalac.ast.*; +import scalac.symtab.*; +import scalac.checkers.*; +import java.io.PrintWriter; + +/** + * Information about a compiler phase. + * + * @author Michel Schinz + */ + +public abstract class PhaseDescriptor { + + private static class InitialPhaseDescriptor extends PhaseDescriptor { + + public String name() { + return "initial"; + } + + public String description() { + return "initializing compiler"; + } + + public Phase createPhase(Global global) { + return null; + } + + /** apply phase to all compilation units + */ + public void apply(Global global) {} + } + + private static class TerminalPhaseDescriptor extends PhaseDescriptor { + + public String name() { + return "terminal"; + } + + public String description() { + return "compilation terminated "; + } + + public Phase createPhase(Global global) { + return null; + } + + /** apply phase to all compilation units + */ + public void apply(Global global) {} + } + + public static PhaseDescriptor INITIAL = new InitialPhaseDescriptor(); + public static PhaseDescriptor TERMINAL = new TerminalPhaseDescriptor(); + + public static final int SKIP = 0x0001; + public static final int CHECK = 0x0002; + public static final int PRINT = 0x0004; + public static final int GRAPH = 0x0008; + public static final int STOP = 0x0010; + public static final int LOG = 0x0020; + + public int flags; + public int id; + + /** return a short, one-word name for the phase. + */ + public abstract String name(); + + /** return a one-line description for the phase. + */ + public abstract String description(); + + /** a one-line task description of this phase + */ + public String taskDescription() { + return description(); + } + + /** initialize the phase + */ + public final void initialize(Global global) { + throw new Error(); + } + public void initialize(Global global, int id) { + this.id = id; + } + + /** create a phase + */ + public abstract Phase createPhase(Global global); + + /** Assume that `tp' is the info of symbol `sym' before this phase. + * Return the info of `sym' after the phase. + */ + public Type transformInfo(Symbol sym, Type tp) { + return tp; + } + + /** apply phase to all compilation units + */ + public void apply(Global global) { + global.start(); + createPhase(global).apply(); + global.stop(taskDescription()); + } + + /** check all compilation units + */ + public void check(Global global) { + for (int i = 0; i < global.units.length; i++) + check(global.units[i]); + } + + /** print all compilation units + */ + public void print(Global global) { + TreePrinter printer = global.printer; + + printer.beginSection(1, "Trees after phase " + name()); + for (int i = 0; i < global.units.length; i++) + printer.print(global.units[i]); + } + + /** graph all compilation units + */ + public void graph(Global global) { + for (int i = 0; i < global.units.length; i++) + graph(global.units[i]); + } + + /** return an array of checkers which can be applied after the phase + */ + public Checker[] postCheckers(Global global) { + return new Checker[0]; + } + + /** check the result of this phase for the given compilation unit + */ + public void check(Unit unit) { + Checker[] checkers = postCheckers(unit.global); + for (int i = 0; i < checkers.length; i++) + checkers[i].traverse(unit); + } + + /** graph the result of this phase for the given compilation unit + */ + public void graph(Unit unit) { + /* todo: uncomment + new scala.compiler.gdl.TreePrinter().printInFile( + unit, unit.source + "-" + name() + ".gdl"); + */ + } + + public String toString() { + return name(); + } +} diff --git a/sources/scalac/PhaseRepository.java b/sources/scalac/PhaseRepository.java new file mode 100644 index 0000000000..4b7e3d4343 --- /dev/null +++ b/sources/scalac/PhaseRepository.java @@ -0,0 +1,96 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package scalac; + +import scalac.ast.parser.ParserPhase; +import scalac.typechecker.AnalyzerPhase; +import scalac.typechecker.RefCheckPhase; +import scalac.transformer.UnCurryPhase; +/* +import scalac.transformer.TransMatchPhase; +*/ +import scalac.transformer.LambdaLiftPhase; +/* +import scalac.transformer.ExplicitOuterClassesPhase; +import scalac.transformer.AddInterfacesPhase; +import scalac.transformer.AddAccessorsPhase; +import scalac.transformer.ExpandMixinsPhase; +import scalac.transformer.ErasurePhase; +import scalac.optimizer.OptimizePhase; +import scalac.backend.AddConstructorsPhase; +import scalac.backend.msil.GenMSILPhase; +import scalac.backend.jvm.GenJVMPhase; +import scalac.jaco.GenJavaPhase; +*/ + +public class PhaseRepository { + + //######################################################################## + // Private state + + public final PhaseDescriptor[] phases; + + //######################################################################## + // Reporter constructors + + public PhaseRepository() { + this.phases = new PhaseDescriptor[] { + INITIAL = PhaseDescriptor.INITIAL, + PARSER = new ParserPhase(), + ANALYZER = new AnalyzerPhase(), + REFCHECK = new RefCheckPhase(), + UNCURRY = new UnCurryPhase(), + /* + OPTIMIZE = new OptimizePhase(), + TRANSMATCH = new TransMatchPhase(), + */ + LAMBDALIFT = new LambdaLiftPhase(), + /* + EXPLICITOUTER = new ExplicitOuterClassesPhase(), + ADDACCESSORS = new AddAccessorsPhase(), + ADDINTERFACES = new AddInterfacesPhase(), + EXPANDMIXIN = new ExpandMixinsPhase(), + ERASURE = new ErasurePhase(), + ADDCONSTRUCTORS = new AddConstructorsPhase(), + GENMSIL = new GenMSILPhase(), + GENJAVA = new GenJavaPhase(), + GENJVM = new GenJVMPhase(), + */ + TERMINAL = PhaseDescriptor.TERMINAL, + }; + } + + //######################################################################## + // Reporter interface + + public final PhaseDescriptor INITIAL; + public final ParserPhase PARSER; + public final AnalyzerPhase ANALYZER; + public final RefCheckPhase REFCHECK; + public final UnCurryPhase UNCURRY; + /* + public final OptimizePhase OPTIMIZE; + public final TransMatchPhase TRANSMATCH; + */ + public final LambdaLiftPhase LAMBDALIFT; + /* + public final ExplicitOuterClassesPhase EXPLICITOUTER; + public final AddAccessorsPhase ADDACCESSORS; + public final AddInterfacesPhase ADDINTERFACES; + public final ExpandMixinsPhase EXPANDMIXIN; + public final ErasurePhase ERASURE; + public final AddConstructorsPhase ADDCONSTRUCTORS; + public final GenMSILPhase GENMSIL; + public final GenJavaPhase GENJAVA; + public final GenJVMPhase GENJVM; + */ + public final PhaseDescriptor TERMINAL; + + //######################################################################## +} diff --git a/sources/scalac/Unit.java b/sources/scalac/Unit.java new file mode 100644 index 0000000000..f9a3ec81c6 --- /dev/null +++ b/sources/scalac/Unit.java @@ -0,0 +1,123 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac; + +import scalac.util.*; +import scalac.symtab.NameMangler; +import scalac.ast.parser.Sourcefile; +import scalac.ast.Tree; +import scala.compiler.typechecker.*; +import java.io.*; +import java.util.*; + + +/** A representation for a compilation unit in scala + * + * @author Matthias Zenger + * @version 1.0 + */ +public class Unit { + + /** the global compilation environment + */ + public Global global; + + /** the associated source code file + */ + public Sourcefile source; + + /** the content of the compilation unit in tree form + */ + public Tree[] body; + + /** the generated symbol data; Symbol -> byte[] + public SymData symdata; + */ + + /** the name mangler + */ + public NameMangler mangler = new NameMangler(); + + /** number of errors issued for this compilation unit + */ + public int errors; + + /** number of warnings issued for this compilation unit + */ + public int warnings; + + /** number of notes issued for this compilation unit + */ + public int notes; + + public Unit(Global global, Sourcefile source) { + this.global = global; + this.source = source; + } + /* + public void print(String message) { + print(System.out, message); + } + + public void print(PrintStream out, String message) { + out.println("[[begin " + message + "]]"); + new Printer(out).printCompilationUnit(this); + out.println(); + out.println("[[end " + message + "]]"); + } + */ + /** issue an error in this compilation unit + */ + public void error(String message) { + error(Position.NOPOS, message); + } + + /** issue an error in this compilation unit at a specific location + */ + public void error(int pos, String message) { + boolean hidden = source.testAndSetLog(pos, message); + if (!hidden) errors++; + global.reporter.error(source.getMessage(pos, message), hidden); + } + + /** issue a warning in this compilation unit + */ + public void warning(String message) { + warning(Position.NOPOS, message); + } + + /** issue a warning in this compilation unit at a specific location + */ + public void warning(int pos, String message) { + if (global.reporter.nowarn) return; + message = "warning: " + message; + boolean hidden = source.testAndSetLog(pos, message); + if (!hidden) warnings++; + global.reporter.warning(source.getMessage(pos, message), hidden); + } + + /** issue a note in this compilation unit + */ + public void note(String message) { + note(Position.NOPOS, message); + } + + /** issue a note in this compilation unit at a specific location + */ + public void note(int pos, String message) { + global.reporter.note(source.getMessage(pos, message)); + notes++; + } + + /** return a string representation + */ + public String toString() { + return source.toString(); + } +} diff --git a/sources/scalac/ast/AbstractTreeCopyFactory.java b/sources/scalac/ast/AbstractTreeCopyFactory.java new file mode 100644 index 0000000000..358d468cd4 --- /dev/null +++ b/sources/scalac/ast/AbstractTreeCopyFactory.java @@ -0,0 +1,30 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + +package scalac.ast; + +import scalac.ast.*; + +/** + * Abstract superclass for all TreeCopyFactories, which provides only + * the code to copy the attribution from the "old" to the "new" tree. + * + * @author Michel Schinz + * @version 1.0 + */ + +public abstract class AbstractTreeCopyFactory implements TreeCopyFactory { + public void attribute(Tree newTree, Tree oldTree) { + if (newTree != oldTree) { + newTree.type = oldTree.type; + if (newTree.hasSymbol()) + newTree.setSymbol(oldTree.symbol()); + } + } +} diff --git a/sources/scalac/ast/LazyTreeFactory.java b/sources/scalac/ast/LazyTreeFactory.java new file mode 100644 index 0000000000..43cef5652a --- /dev/null +++ b/sources/scalac/ast/LazyTreeFactory.java @@ -0,0 +1,430 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast; + +import scalac.util.Name; +import Tree.*; + +public class LazyTreeFactory extends AbstractTreeCopyFactory { + protected final TreeFactory make; + + public LazyTreeFactory(TreeFactory make) { + this.make = make; + } + + public Tree Bad(Tree tree) { + return tree; + } + + public Tree ClassDef(Tree tree, + int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Template impl) { + ClassDef t = (ClassDef)tree; + if ((t.mods == mods) && + (t.name == name) && + (t.tparams == tparams) && + (t.vparams == vparams) && + (t.tpe == tpe) && + (t.impl == impl)) + return t; + tree = make.ClassDef(t.pos, mods, name, tparams, vparams, tpe, impl); + attribute(tree, t); + return tree; + } + + public Tree PackageDef(Tree tree, + Tree packaged, + Template impl) { + PackageDef t = (PackageDef)tree; + if ((t.packaged == packaged) && + (t.impl == impl)) + return t; + tree = make.PackageDef(t.pos, packaged, impl); + attribute(tree, t); + return tree; + } + + public Tree ModuleDef(Tree tree, + int mods, + Name name, + Tree tpe, + Template impl) { + ModuleDef t = (ModuleDef)tree; + if ((t.mods == mods) && + (t.name == name) && + (t.tpe == tpe) && + (t.impl == impl)) + return t; + tree = make.ModuleDef(t.pos, mods, name, tpe, impl); + attribute(tree, t); + return tree; + } + + public Tree ValDef(Tree tree, + int mods, + Name name, + Tree tpe, + Tree rhs) { + ValDef t = (ValDef)tree; + if ((t.mods == mods) && + (t.name == name) && + (t.tpe == tpe) && + (t.rhs == rhs)) + return t; + tree = make.ValDef(t.pos, mods, name, tpe, rhs); + attribute(tree, t); + return tree; + } + + public Tree PatDef(Tree tree, + int mods, + Tree pat, + Tree rhs) { + PatDef t = (PatDef)tree; + if ((t.mods == mods) && + (t.pat == pat) && + (t.rhs == rhs)) + return t; + tree = make.PatDef(t.pos, mods, pat, rhs); + attribute(tree, t); + return tree; + } + + public Tree DefDef(Tree tree, + int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Tree rhs) { + DefDef t = (DefDef)tree; + if ((t.mods == mods) && + (t.name == name) && + (t.tparams == tparams) && + (t.vparams == vparams) && + (t.tpe == tpe) && + (t.rhs == rhs)) + return t; + tree = make.DefDef(t.pos, mods, name, tparams, vparams, tpe, rhs); + attribute(tree, t); + return tree; + } + + public Tree TypeDef(Tree tree, + int mods, + Name name, + TypeDef[] tparams, + Tree rhs) { + TypeDef t = (TypeDef)tree; + if ((t.mods == mods) && + (t.name == name) && + (t.tparams == tparams) && + (t.rhs == rhs)) + return t; + tree = make.TypeDef(t.pos, mods, name, tparams, rhs); + attribute(tree, t); + return tree; + } + + public Tree Import(Tree tree, + Tree expr, + Name[] selectors) { + Import t = (Import)tree; + if (t.expr == expr && t.selectors == selectors) + return t; + tree = make.Import(t.pos, expr, selectors); + attribute(tree, t); + return tree; + } + + public Tree CaseDef(Tree tree, + Tree pat, + Tree guard, + Tree body) { + CaseDef t = (CaseDef)tree; + if ((t.pat == pat) && + (t.guard == guard) && + (t.body == body)) + return t; + tree = make.CaseDef(t.pos, pat, guard, body); + attribute(tree, t); + return tree; + } + + public Template Template(Tree tree, + Tree[] parents, + Tree[] body) { + Template t = (Template)tree; + if ((t.parents == parents) && + (t.body == body)) + return t; + Template newTree = make.Template(t.pos, parents, body); + attribute(newTree, t); + return newTree; + } + + public Tree LabelDef(Tree tree, + Tree[] params, + Tree rhs) { + LabelDef t = (LabelDef)tree; + if ((t.params == params) && + (t.rhs == rhs)) + return t; + tree = make.LabelDef(t.pos,params,rhs); + attribute(tree,t); + return tree; + } + + public Tree Block(Tree tree, + Tree[] stats) { + Block t = (Block)tree; + if (t.stats == stats) + return t; + tree = make.Block(t.pos, stats); + attribute(tree, t); + return tree; + } + + public Tree Tuple(Tree tree, + Tree[] trees) { + Tuple t = (Tuple)tree; + if (t.trees == trees) + return t; + tree = make.Tuple(t.pos, trees); + attribute(tree, t); + return tree; + } + + public Tree Visitor(Tree tree, + CaseDef[] cases) { + Visitor t = (Visitor)tree; + if (t.cases == cases) + return t; + tree = make.Visitor(t.pos, cases); + attribute(tree, t); + return tree; + } + + public Tree Function(Tree tree, + ValDef[] vparams, + Tree body) { + Function t = (Function)tree; + if ((t.vparams == vparams) && + (t.body == body)) + return t; + tree = make.Function(t.pos, vparams, body); + attribute(tree, t); + return tree; + } + + public Tree Assign(Tree tree, + Tree lhs, + Tree rhs) { + Assign t = (Assign)tree; + if ((t.lhs == lhs) && + (t.rhs == rhs)) + return t; + tree = make.Assign(t.pos, lhs, rhs); + attribute(tree, t); + return tree; + } + + public Tree If(Tree tree, + Tree cond, + Tree thenp, + Tree elsep) { + If t = (If)tree; + if ((t.cond == cond) && + (t.thenp == thenp) && + (t.elsep == elsep)) + return t; + tree = make.If(t.pos, cond, thenp, elsep); + attribute(tree, t); + return tree; + } + + public Tree New(Tree tree, + Template templ) { + New t = (New)tree; + if (t.templ == templ) + return t; + tree = make.New(t.pos, templ); + attribute(tree, t); + return tree; + } + + public Tree Typed(Tree tree, + Tree expr, + Tree tpe) { + Typed t = (Typed)tree; + if ((t.expr == expr) && + (t.tpe == tpe)) + return t; + tree = make.Typed(t.pos, expr, tpe); + attribute(tree, t); + return tree; + } + + public Tree TypeApply(Tree tree, + Tree fun, + Tree[] args) { + TypeApply t = (TypeApply)tree; + if ((t.fun == fun) && + (t.args == args)) + return t; + tree = make.TypeApply(t.pos, fun, args); + attribute(tree, t); + return tree; + } + + public Tree Apply(Tree tree, + Tree fun, + Tree[] args) { + Apply t = (Apply)tree; + if ((t.fun == fun) && + (t.args == args)) + return t; + tree = make.Apply(t.pos, fun, args); + attribute(tree, t); + return tree; + } + + public Tree Super(Tree tree, + Tree tpe) { + Super t = (Super)tree; + if (t.tpe == tpe) + return t; + tree = make.Super(t.pos, tpe); + attribute(tree, t); + return tree; + } + + public Tree This(Tree tree, + Tree qualifier) { + This t = (This)tree; + if (t.qualifier == qualifier) + return t; + tree = make.This(t.pos, qualifier); + attribute(tree, t); + return tree; + } + + public Tree Select(Tree tree, + Tree qualifier, + Name selector) { + Select t = (Select)tree; + if ((t.qualifier == qualifier) && + (t.selector == selector)) + return t; + tree = make.Select(t.pos, qualifier, selector); + attribute(tree, t); + return tree; + } + + public Tree Ident(Tree tree, + Name name) { + Ident t = (Ident)tree; + if (t.name == name) + return t; + tree = make.Ident(t.pos, name); + attribute(tree, t); + return tree; + } + + public Tree Literal(Tree tree, + Object value) { + Literal t = (Literal)tree; + if (t.value == value) + return t; + tree = make.Literal(t.pos, value); + attribute(tree, t); + return tree; + } + + public Tree SingletonType(Tree tree, + Tree ref) { + SingletonType t = (SingletonType)tree; + if (t.ref == ref) + return t; + tree = make.SingletonType(t.pos, ref); + attribute(tree, t); + return tree; + } + + public Tree SelectFromType(Tree tree, + Tree qualifier, + Name selector) { + SelectFromType t = (SelectFromType)tree; + if (t.qualifier == qualifier && + t.selector == selector) + return t; + tree = make.SelectFromType(t.pos, qualifier, selector); + attribute(tree, t); + return tree; + } + + public Tree FunType(Tree tree, + Tree[] argtpes, + Tree restpe) { + FunType t = (FunType)tree; + if ((t.argtpes == argtpes) && + (t.restpe == restpe)) + return t; + tree = make.FunType(t.pos, argtpes, restpe); + attribute(tree, t); + return tree; + } + + public Tree CompoundType(Tree tree, + Tree[] parents, + Tree[] refinements) { + CompoundType t = (CompoundType)tree; + if ((t.parents == parents) && + (t.refinements == refinements)) + return t; + tree = make.CompoundType(t.pos, parents, refinements); + attribute(tree, t); + return tree; + } + + public Tree TupleType(Tree tree, + Tree[] types) { + TupleType t = (TupleType)tree; + if (t.types == types) + return t; + tree = make.TupleType(t.pos, types); + attribute(tree, t); + return tree; + } + + public Tree AppliedType(Tree tree, + Tree tpe, + Tree[] args) { + AppliedType t = (AppliedType)tree; + if ((t.tpe == tpe) && + (t.args == args)) + return t; + tree = make.AppliedType(t.pos, tpe, args); + attribute(tree, t); + return tree; + } + + public Tree CovariantType(Tree tree, + Tree tpe) { + CovariantType t = (CovariantType)tree; + if (t.tpe == tpe) return t; + tree = make.CovariantType(t.pos, tpe); + attribute(tree, t); + return tree; + } +} diff --git a/sources/scalac/ast/Transformer.java b/sources/scalac/ast/Transformer.java new file mode 100644 index 0000000000..1789801c7e --- /dev/null +++ b/sources/scalac/ast/Transformer.java @@ -0,0 +1,401 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast; + +import java.io.*; +import java.util.*; +import scalac.*; +import scalac.util.*; +import scalac.symtab.*; +import Tree.*; + + +/** A default transformer class. This class traverses the abstract + * syntax tree but does not do any transformations. + * + * @author Matthias Zenger + * @version 1.0 + */ +public class Transformer extends Phase { + /** the tree factory + */ + public final TreeFactory make; + + /** a factory for copying trees; the attribution is preserved + * or translated according to the TreeCopyFactory; trees are + * only copied if new tree introduces changes + */ + public final TreeCopyFactory copy; + + /** a tree generator + */ + public final TreeGen gen; + + /** various constructors + */ + public Transformer(Global global, PhaseDescriptor descr) { + this(global, descr, global.make, new LazyTreeFactory(global.make)); + } + + public Transformer(Global global, + PhaseDescriptor descr, + TreeFactory make) { + this(global, descr, make, new LazyTreeFactory(make)); + } + + public Transformer(Global global, + PhaseDescriptor descr, + TreeFactory make, + TreeCopyFactory copy) { + super(global, descr); + this.make = make; + this.copy = copy; + this.gen = global.treeGen; + } + + public void apply() { + super.apply(); + } + + public void apply(Unit unit) { + unit.body = transform(unit.body); + } + + public Tree[] transform(Tree[] ts) { + for (int i = 0; i < ts.length; i++) { + Tree t = transform(ts[i]); + if (t != ts[i]) { + Tree[] res = new Tree[ts.length]; + System.arraycopy(ts, 0, res, 0, i); + res[i] = t; + for (int j = i + 1; j < ts.length; j++) + res[j] = transform(ts[j]); + return res; + } + } + return ts; + } + + public Tree[][] transform(Tree[][] ts) { + for (int i = 0; i < ts.length; i++) { + Tree[] t = transform(ts[i]); + if (t != ts[i]) { + Tree[][] res = new Tree[ts.length][]; + System.arraycopy(ts, 0, res, 0, i); + res[i] = t; + for (int j = i + 1; j < ts.length; j++) + res[j] = transform(ts[j]); + return res; + } + } + return ts; + } + + public ValDef[][] transform(ValDef[][] ts) { + for (int i = 0; i < ts.length; i++) { + ValDef[] t = transform(ts[i]); + if (t != ts[i]) { + ValDef[][] res = new ValDef[ts.length][]; + System.arraycopy(ts, 0, res, 0, i); + res[i] = t; + for (int j = i + 1; j < ts.length; j++) + res[j] = transform(ts[j]); + return res; + } + } + return ts; + } + + public ValDef[] transform(ValDef[] ts) { + for (int i = 0; i < ts.length; i++) { + Tree t = transform(ts[i]); + if (t != ts[i]) { + ValDef[] res = new ValDef[ts.length]; + System.arraycopy(ts, 0, res, 0, i); + res[i] = (ValDef)t; + for (int j = i + 1; j < ts.length; j++) + res[j] = (ValDef)transform(ts[j]); + return res; + } + } + return ts; + } + + public TypeDef[] transform(TypeDef[] ts) { + for (int i = 0; i < ts.length; i++) { + Tree t = transform(ts[i]); + if (t != ts[i]) { + TypeDef[] res = new TypeDef[ts.length]; + System.arraycopy(ts, 0, res, 0, i); + res[i] = (TypeDef)t; + for (int j = i + 1; j < ts.length; j++) + res[j] = (TypeDef)transform(ts[j]); + return res; + } + } + return ts; + } + + public CaseDef[] transform(CaseDef[] ts) { + for (int i = 0; i < ts.length; i++) { + Tree t = transform(ts[i]); + if (t != ts[i]) { + CaseDef[] res = new CaseDef[ts.length]; + System.arraycopy(ts, 0, res, 0, i); + res[i] = (CaseDef)t; + for (int j = i + 1; j < ts.length; j++) + res[j] = (CaseDef)transform(ts[j]); + return res; + } + } + return ts; + } + + public Template transform(Template tree) { + return (Template)transform((Tree)tree); + } + + public Tree transform(Tree tree) { + if (tree == null) + return null; + switch (tree) { + case ClassDef(int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Template impl): + return copy.ClassDef(tree, + mods, + name, + transform(tparams), + transform(vparams), + transform(tpe), + transform(impl)); + case PackageDef(Tree packaged, Template impl): + return copy.PackageDef(tree, + transform(packaged), + transform(impl)); + case ModuleDef(int mods, + Name name, + Tree tpe, + Template impl): + return copy.ModuleDef(tree, + mods, + name, + transform(tpe), + transform(impl)); + case ValDef(int mods, + Name name, + Tree tpe, + Tree rhs): + return copy.ValDef(tree, + mods, + name, + transform(tpe), + transform(rhs)); + case PatDef(int mods, + Tree pat, + Tree rhs): + return copy.PatDef(tree, + mods, + transform(pat), + transform(rhs)); + case DefDef(int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Tree rhs): + return copy.DefDef(tree, + mods, + name, + transform(tparams), + transform(vparams), + transform(tpe), + transform(rhs)); + case TypeDef(int mods, + Name name, + TypeDef[] tparams, + Tree rhs): + return copy.TypeDef(tree, + mods, + name, + transform(tparams), + transform(rhs)); + case Import(Tree expr, Name[] selectors): + return copy.Import(tree, + transform(expr), + selectors); + case CaseDef(Tree pat, Tree guard, Tree body): + return copy.CaseDef(tree, + transform(pat), + transform(guard), + transform(body)); + case Template(Tree[] parents, Tree[] body): + return copy.Template(tree, + transform(parents), + transform(body)); + case LabelDef(Tree[] params,Tree rhs): + return copy.LabelDef(tree, + transform(params), + transform(rhs)); + case Block(Tree[] stats): + return copy.Block(tree, + transform(stats)); + case Tuple(Tree[] trees): + return copy.Tuple(tree, + transform(trees)); + case Visitor(CaseDef[] cases): + return copy.Visitor(tree, + transform(cases)); + case Function(ValDef[] vparams, Tree body): + return copy.Function(tree, + transform(vparams), + transform(body)); + case Assign(Tree lhs, Tree rhs): + return copy.Assign(tree, + transform(lhs), + transform(rhs)); + case If(Tree cond, Tree thenp, Tree elsep): + return copy.If(tree, + transform(cond), + transform(thenp), + transform(elsep)); + case New(Template templ): + return copy.New(tree, + transform(templ)); + case Typed(Tree expr, Tree tpe): + return copy.Typed(tree, + transform(expr), + transform(tpe)); + case TypeApply(Tree fun, Tree[] args): + return copy.TypeApply(tree, + transform(fun), + transform(args)); + case Apply(Tree fun, Tree[] args): + return copy.Apply(tree, + transform(fun), + transform(args)); + case Super(Tree tpe): + return copy.Super(tree, + transform(tpe)); + case This(Tree qualifier): + return copy.This(tree, + transform(qualifier)); + case Select(Tree qualifier, Name selector): + return copy.Select(tree, + transform(qualifier), + selector); + case Ident(Name name): + return copy.Ident(tree, name); + case Literal(Object value): + return copy.Literal(tree, value); + case SingletonType(Tree ref): + return copy.SingletonType(tree, + transform(ref)); + case SelectFromType(Tree qualifier, Name selector): + return copy.SelectFromType(tree, + transform(qualifier), + selector); + case FunType(Tree[] argtpes, Tree restpe): + return copy.FunType(tree, + transform(argtpes), + transform(restpe)); + case CompoundType(Tree[] parents, Tree[] refinements): + return copy.CompoundType(tree, + transform(parents), + transform(refinements)); + case TupleType(Tree[] types): + return copy.TupleType(tree, + transform(types)); + case AppliedType(Tree tpe, Tree[] args): + return copy.AppliedType(tree, + transform(tpe), + transform(args)); + case CovariantType(Tree tpe): + return copy.CovariantType(tree, + transform(tpe)); + default: + return tree; + } + } + /* a full pattern-matching statement: + + switch (tree) { + case PackageDef(Tree packaged, Template impl): + + case ClassDef(int mods, Name name, TypeDef[] tparams, ValDef[][] vparams, + Template impl): + + case ModuleDef(int mods, Name name, Tree tpe, Template impl): + + case ValDef(int mods, Name name, Tree tpe, Tree rhs): + + case PatDef(int mods, Tree pat, Tree rhs): + + case DefDef(int mods, Name name, TypeDef[] tparams, ValDef[][] vparams, + Tree tpe, Tree rhs): + + case TypeDef(int mods, Name name, TypeDef[] tparams, Tree rhs): + + case Import(Tree expr): + + case CaseDef(Tree pat, Tree guard, Tree body): + + case Template(Tree[] baseClasses, Tree[] body): + + case LabelDef(Tree[] params,Tree rhs): + + case Block(Tree[] stats): + + case Tuple(Tree[] trees): + + case Visitor(CaseDef[] cases): + + case Function(ValDef[] vparams, Tree body): + + case Assign(Tree lhs, Tree rhs): + + case If(Tree cond, Tree thenp, Tree elsep): + + case New(Template templ): + + case Typed(Tree expr, Tree tpe): + + case TypeApply(Tree fun, Tree[] args): + + case Apply(Tree fun, Tree[] args): + + case Super(Tree tpe): + + case Select(Tree qualifier, Name selector): + + case Ident(Name name): + + case Literal(int kind, Object value): + + case SingletonType(Tree ref): + + case SelectFromType(Tree qualifier, Name selector): + + case FunType(Tree argtpe, Tree restpe): + + case CompoundType(Tree[] baseTypes, Tree[] refinements): + + case TupleType(Tree[] types): + + case AppliedType(Tree tpe, Tree[] args): + + default: + return tree; + } + */ + +} diff --git a/sources/scalac/ast/Traverser.java b/sources/scalac/ast/Traverser.java new file mode 100644 index 0000000000..5c39d9e315 --- /dev/null +++ b/sources/scalac/ast/Traverser.java @@ -0,0 +1,215 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + +package scalac.ast; + +import java.io.*; +import java.util.*; +import scalac.*; +import scalac.util.*; +import Tree.*; + + +/** Class to traverse a tree without modifying it. + * + * @author Michel Schinz + */ + +public class Traverser { + public Traverser() {} + + // this should be removed in the future + public Traverser(Global global) {} + + public void traverse(Unit unit) { + traverse(unit.body); + } + + public void traverse(Tree tree) { + switch (tree) { + case Bad(): + case Empty: + case Ident(_): + case Literal(_): + return; + + case ClassDef(int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Template impl): + traverse(tparams); + traverse(vparams); + traverse(tpe); + traverse(impl); + return; + + case PackageDef(Tree packaged, Template impl) : + traverse(packaged); + traverse(impl); + return; + + case ModuleDef(int mods, Name name, Tree tpe, Template impl): + traverse(tpe); + traverse(impl); + return; + + case ValDef(int mods, Name name, Tree tpe, Tree rhs): + traverse(tpe); + traverse(rhs); + return; + + case PatDef(int mods, Tree pat, Tree rhs): + traverse(pat); + traverse(rhs); + return; + + case DefDef(int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Tree rhs): + traverse(tparams); + traverse(vparams); + traverse(tpe); + traverse(rhs); + return; + + case TypeDef(int mods, Name name, TypeDef[] tparams, Tree rhs): + traverse(tparams); + traverse(rhs); + return; + + case Import(Tree expr, Name[] selectors): + traverse(expr); + return; + + case CaseDef(Tree pat, Tree guard, Tree body): + traverse(pat); + traverse(guard); + traverse(body); + return; + + case Template(Tree[] baseClasses, Tree[] body): + traverse(baseClasses); + traverse(body); + return; + + case LabelDef(Tree[] params,Tree rhs): + traverse(params); + traverse(rhs); + return; + + case Block(Tree[] stats): + traverse(stats); + return; + + case Tuple(Tree[] trees): + traverse(trees); + return; + + case Visitor(CaseDef[] cases): + traverse(cases); + return; + + case Function(ValDef[] vparams, Tree body): + traverse(vparams); + traverse(body); + return; + + case Assign(Tree lhs, Tree rhs): + traverse(lhs); + traverse(rhs); + return; + + case If(Tree cond, Tree thenp, Tree elsep): + traverse(cond); + traverse(thenp); + traverse(elsep); + return; + + case New(Template templ): + traverse(templ); + return; + + case Typed(Tree expr, Tree tpe): + traverse(expr); + traverse(tpe); + return; + + case TypeApply(Tree fun, Tree[] tparams): + traverse(fun); + traverse(tparams); + return; + + case Apply(Tree fun, Tree[] vparam): + traverse(fun); + traverse(vparam); + return; + + case Super(Tree tpe): + traverse(tpe); + return; + + case This(Tree qualifier): + traverse(qualifier); + return; + + case Select(Tree qualifier, Name selector): + traverse(qualifier); + return; + + case SingletonType(Tree ref): + traverse(ref); + return; + + case SelectFromType(Tree qualifier, Name selector): + traverse(qualifier); + return; + + case FunType(Tree[] argtpes, Tree restpe): + traverse(argtpes); + traverse(restpe); + return; + + case CompoundType(Tree[] baseTypes, Tree[] refinements): + traverse(baseTypes); + traverse(refinements); + return; + + case TupleType(Tree[] types): + traverse(types); + return; + + case AppliedType(Tree tpe, Tree[] args): + traverse(tpe); + traverse(args); + return; + + case CovariantType(Tree tpe): + traverse(tpe); + return; + + default: + throw new ApplicationError("unknown node " + tree); + } + } + + public void traverse(Tree[] array) { + for (int i = 0; i < array.length; ++i) + traverse(array[i]); + } + + public void traverse(Tree[][] array) { + for (int i = 0; i < array.length; ++i) + traverse(array[i]); + } +} diff --git a/sources/scalac/ast/Tree.java b/sources/scalac/ast/Tree.java new file mode 100644 index 0000000000..80304ea78e --- /dev/null +++ b/sources/scalac/ast/Tree.java @@ -0,0 +1,771 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast; + +import scalac.ast.printer.*; +import scalac.ApplicationError; +import scalac.util.Name; +import scalac.util.Position; +import scalac.symtab.Type; +import scalac.symtab.Symbol; + +public class Tree { + + public int pos = Position.NOPOS; + public Type type; + +/** empty tree array + */ + public static final Tree[] EMPTY_ARRAY = new Tree[0]; + +/** representation for parser errors + */ + public case Bad(); + +/** a tree node for the absence of a tree + */ + public case Empty; + static { Empty.type = Type.NoType; } + +/** class and data declaration + */ + public case ClassDef(int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Template impl) { + assert name.isTypeName(); + } + +/** package declaration + */ + public case PackageDef(Tree packaged, + Template impl) { + if (!packaged.isTerm()) + throw new ApplicationError("PackageDef expects term as rhs."); + } + +/** module declaration + */ + public case ModuleDef(int mods, + Name name, + Tree tpe, + Template impl) { + assert !name.isTypeName(); + } + +/** var or let declaration + */ + public case ValDef(int mods, + Name name, + Tree tpe, + Tree rhs) { + assert !name.isTypeName(); + if (!tpe.isType()) + throw new ApplicationError("ValDef expects type as tpe; found: " + tpe); + if (!rhs.isTerm()) + throw new ApplicationError("ValDef expects term as rhs."); + } + +/** val declaration + */ + public case PatDef(int mods, + Tree pat, + Tree rhs) { + if (!rhs.isTerm()) + throw new ApplicationError("PatDef expects term as rhs."); + } + +/** def declaration + */ + public case DefDef(int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Tree rhs) { + assert !name.isTypeName(); + if (!tpe.isType()) + throw new ApplicationError("DefDef expects type as tpe."); + if (!rhs.isTerm()) + throw new ApplicationError("DefDef expects term as rhs. Found: " + rhs.getClass()); + } + +/** type declaration + */ + public case TypeDef(int mods, + Name name, + TypeDef[] tparams, + Tree rhs) { + assert name.isTypeName(); + if (!rhs.isType()) + throw new ApplicationError("TypeDef expects type as rhs; found: " + rhs); + } + +/** import declaration + */ + public case Import(Tree expr, Name[] selectors) { + if (!expr.isTerm()) + throw new ApplicationError("Import expects term."); + } + +/** case declaration + */ + public case CaseDef(Tree pat, + Tree guard, + Tree body) { + if (!guard.isTerm()) + throw new ApplicationError("CaseDef expects term as guard."); + if (!body.isTerm()) + throw new ApplicationError("CaseDef expects term as body."); + } + +/** instantiation templates +*/ + public case Template(Tree[] parents, + Tree[] body) { + if (parents != null) { + for (int i = 0; i < parents.length; i++) { + if (!parents[i].isTerm()) + throw new ApplicationError("Template requires terms as baseClasses."); + } + } + } + +/** labelled expression - the symbols in the array (must be Idents!) are those the + label takes as argument +*/ + public case LabelDef(Tree[] params,Tree rhs) { + for (int i = 0;i < params.length; i++) { + if (!(params[i] instanceof Ident)) + throw new ApplicationError("LabelDef requires Idents"); + } + } + +/** block of expressions (semicolon separated expressions) + */ + public case Block(Tree[] stats); + +/** tuple of expressions (comma separated expressions) + */ + public case Tuple(Tree[] trees) { + if (trees != null) { + for (int i = 0; i < trees.length; i++) { + if (!trees[i].isTerm()) + throw new ApplicationError("Tuple requires terms"); + } + } + } + +/** visitor (a sequence of cases) + */ + public case Visitor(CaseDef[] cases); + +/** an anonymous function + */ + public case Function(ValDef[] vparams, + Tree body) { + if (!body.isTerm()) + throw new ApplicationError("Function body has to be a term."); + } + +/** assignment + */ + public case Assign(Tree lhs, + Tree rhs) { + if (!lhs.isTerm()) + throw new ApplicationError("lhs of Assign has to be a term."); + if (!rhs.isTerm()) + throw new ApplicationError("rhs of Assign has to be a term."); + } + +/** conditional expression + */ + public case If(Tree cond, + Tree thenp, + Tree elsep) { + assert cond.isTerm() && + thenp.isTerm() && + elsep.isTerm(); + } + +/** instantiation + */ + public case New(Template templ); + +/** type annotation + */ + public case Typed(Tree expr, + Tree tpe) { + if (!expr.isTerm()) + throw new ApplicationError("Typed expects term as first argument."); + if (!tpe.isType()) + throw new ApplicationError("Typed expects type as second argument."); + } + +/** type application + */ + public case TypeApply(Tree fun, + Tree[] args) { + if (!fun.isTerm()) { + new TextTreePrinter().print(fun).println().end();//debug + throw new ApplicationError("TypeApply expects term as function."); + } + for (int i = 0; i < args.length; i++) { + if (!args[i].isType()) + throw new ApplicationError("TypeApply expects types as arguments."); + } + } + +/** value application + */ + public case Apply(Tree fun, + Tree[] args) { + if (args != null) { + for (int i = 0; i < args.length; i++) { + if (!args[i].isTerm()) + throw new ApplicationError("Apply expects terms as arguments. Found: " + args[i].getClass()); + } + } + } + +/** super reference + */ + public case Super(Tree tpe) { + if (!tpe.isType()) { + throw new ApplicationError("Super expects type."); + } + } + +/** self reference + */ + public case This(Tree qualifier) { + if (!qualifier.isType()) + throw new ApplicationError("This expects type."); + } + +/** designator + */ + public case Select(Tree qualifier, + Name selector) { + if (!qualifier.isTerm()) + throw new ApplicationError("Select expects term."); + } + +/** identifier + */ + public case Ident(Name name) { + assert name != null; + } + +/** literal + */ + public case Literal(Object value); + +/** singleton type + */ + public case SingletonType(Tree ref) { + if (!ref.isTerm()) + throw new ApplicationError("SingletonType expects term."); + } + +/** type selection + */ + public case SelectFromType(Tree qualifier, + Name selector) { + if (!qualifier.isType()) + throw new ApplicationError("SelectFromType expects type."); + assert selector.isTypeName(); + } + +/** function type + */ + public case FunType(Tree[] argtpes, + Tree restpe) { + for (int i = 0; i < argtpes.length; i++) + if (!argtpes[i].isType()) + throw new ApplicationError("FunType requires types as args."); + if (!restpe.isType()) + throw new ApplicationError("FunType requires type as result."); + } + +/** object type (~ Template) + */ + public case CompoundType(Tree[] parents, + Tree[] refinements) { + if (parents != null) { + assert parents.length > 0; + for (int i = 0; i < parents.length; i++) { + if (!parents[i].isType()) + throw new ApplicationError("CompoundType requires types as parents."); + } + } + } + +/** tuple type (~ Tuple) + */ + public case TupleType(Tree[] types) { + if (types != null) { + for (int i = 0; i < types.length; i++) { + if (!types[i].isType()) + throw new ApplicationError("TupleType requires types."); + } + } + } + + /** applied type + */ + public case AppliedType(Tree tpe, Tree[] args) { + assert tpe.isType() : this; + for (int i = 0; i < args.length; i++) assert args[i].isType() : args[i]; + } + + /** a covariant type + */ + public case CovariantType(Tree tpe) { + assert tpe.isType(); + } + + /** Get the type of the node. */ + public Type type() { + assert type != null : this; + return type; + } + + /** Set the type of the node. */ + public Tree setType(Type type) { + assert !(type instanceof Type.LazyType) : symbol(); + this.type = type; + return this; + } + + /** + * Get types attached to array of nodes. + */ + public static Type[] typeOf(Tree[] trees) { + Type[] tps = new Type[trees.length]; + for (int i = 0; i < trees.length; i++) + tps[i] = trees[i].type(); + return tps; + } + + /** Has this tree a symbol field? */ + public boolean hasSymbol() { + return false; + } + + /** + * Get symbol attached to the node, if any. + */ + public Symbol symbol () { + return null; + } + + /** + * Set symbol attached to the node, if possible. + */ + public Tree setSymbol(Symbol sym) { + throw new ApplicationError ("no settable symbol for node", this); + } + + /** + * Get symbols attached to array of nodes. + */ + public static Symbol[] symbolOf(Tree[] trees) { + Symbol[] syms = new Symbol[trees.length]; + for (int i = 0; i < trees.length; i++) + syms[i] = trees[i].symbol(); + return syms; + } + + /** + * Tells if the tree defines a symbol. + **/ + public boolean definesSymbol() { + return false; + } + + /** Get string corresponding to this tree + * only implemented for prefix trees, maybe we should generalize this; + * the PatternMatch phase needs support for Apply, so this case got added + */ + public String toString() { + switch (this) { + case This(Tree qual): + return (qual == Tree.Empty) ? "this" : qual + ".this"; + case Select(Tree qual, Name name): + return qual + "." + name; + case Ident(Name name): + return name.toString(); + case Apply(Tree fn, Tree[] args): + String res = fn + "("; + if ((args == null) || (args.length == 0)) + return res + ")"; + res += args[0].toString(); + for (int i = 1; i < args.length; i++) + res += ", " + args[i]; + return res + ")"; + case Literal(Object value): + if (value instanceof String) + return "\"" + value + "\""; + else + return value.toString(); + case Import(Tree expr, _): + return "import " + expr; + case Empty: + return ""; + default: + return super.toString(); + } + } + + public static class ExtBad extends Bad { + private Symbol symbol; + + public ExtBad() { + super(); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + } + + public static class ExtClassDef extends ClassDef { + private Symbol symbol; + + public ExtClassDef(int mods, Name name, TypeDef[] tparams, + ValDef[][] vparams, Tree tpe, Template impl) + { + super(mods, name, tparams, vparams, tpe, impl); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + + public boolean definesSymbol() { + return true; + } + } + + public static class ExtModuleDef extends ModuleDef { + private Symbol symbol; + + public ExtModuleDef(int mods, Name name, Tree tpe, Template impl) + { + super(mods, name, tpe, impl); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + + public boolean definesSymbol() { + return true; + } + } + + public static class ExtValDef extends ValDef { + + public static final ValDef[] EMPTY_ARRAY = new ValDef[0]; + public static final ValDef[][] EMPTY_ARRAY_ARRAY = new ValDef[0][0]; + + private Symbol symbol; + + public ExtValDef(int mods, Name name, Tree tpe, Tree rhs) + { + super(mods, name, tpe, rhs); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + + public boolean definesSymbol() { + return true; + } + } + + public static class ExtDefDef extends DefDef { + private Symbol symbol; + + public ExtDefDef(int mods, Name name, TypeDef[] tparams, + ValDef[][] vparams, Tree tpe, Tree rhs) + { + super(mods, name, tparams, vparams, tpe, rhs); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + + public boolean definesSymbol() { + return true; + } + } + + public static class ExtTypeDef extends TypeDef { + private Symbol symbol; + + public static final TypeDef[] EMPTY_ARRAY = new TypeDef[0]; + + public ExtTypeDef(int mods, Name name, TypeDef[] tparams, Tree rhs) + { + super(mods, name, tparams, rhs); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + + public boolean definesSymbol() { + return true; + } + } + + public static class ExtImport extends Import { + private Symbol symbol; + + public ExtImport(Tree expr, Name[] selectors) { + super(expr, selectors); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + } + + public static class ExtLabelDef extends LabelDef { + private Symbol symbol; + + public ExtLabelDef(Tree[] params,Tree rhs) { + super(params,rhs); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + + public boolean definesSymbol() { + return true; + } + } + + public static class ExtSelect extends Select { + private Symbol symbol; + + public ExtSelect(Tree qualifier, Name selector) { + super(qualifier, selector); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + } + + public static class ExtSelectFromType extends SelectFromType { + private Symbol symbol; + + public ExtSelectFromType(Tree qualifier, Name selector) { + super(qualifier, selector); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + } + + public static class ExtIdent extends Ident { + private Symbol symbol; + + public ExtIdent(Name name) { + super(name); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + } + + public static class ExtTemplate extends Template { + private Symbol symbol; + + public ExtTemplate(Tree[] parents, Tree[] body) { + super(parents, body); + } + + public boolean hasSymbol() { + return true; + } + + public Symbol symbol() { + return symbol; + } + + public Tree setSymbol(Symbol symbol) { + this.symbol = symbol; + return this; + } + + public boolean definesSymbol() { + return true; + } + } + + public boolean isTerm() { + switch(this) { + case Bad(): + case Empty: + case Tuple(_): + case If(_, _, _): + case Typed(_, _): + case Apply(_, _): + case TypeApply(_, _): + case Visitor(_): + case New(_): + case Literal(_): + case LabelDef(_,_): + case Block(_): + case Function(_, _): + case Assign(_, _): + case Super(_): + case This(_): + return true; + case Ident(Name name): + return !name.isTypeName(); + case Select(_, Name name): + return !name.isTypeName(); + default: + return false; + } + } + + public boolean isType() { + switch(this) { + case Bad(): + case Empty: + case SingletonType(_): + case SelectFromType(_, _): + case CompoundType(_, _): + case FunType(_, _): + case TupleType(_): + case AppliedType(_, _): + case CovariantType(_): + return true; + case Ident(Name name): + return name.isTypeName(); + case Select(_, Name name): + return name.isTypeName(); + default: + return false; + } + } +} + diff --git a/sources/scalac/ast/TreeCopyFactory.java b/sources/scalac/ast/TreeCopyFactory.java new file mode 100644 index 0000000000..5a9074c39f --- /dev/null +++ b/sources/scalac/ast/TreeCopyFactory.java @@ -0,0 +1,165 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast; + +import scalac.util.Name; +import Tree.*; + +/** + * Interface for a kind of factory which, for each node constructor, + * takes an original node from which some data will be copied or shared. + * + * @author Michel Schinz + * @version 1.1 + */ +public interface TreeCopyFactory { + + public void attribute(Tree newTree, Tree oldTree); + + public Tree Bad(Tree tree); + + public Tree ClassDef(Tree tree, + int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Template impl); + + public Tree PackageDef(Tree tree, + Tree packaged, + Template impl); + + public Tree ModuleDef(Tree tree, + int mods, + Name name, + Tree tpe, + Template impl); + + public Tree ValDef(Tree tree, + int mods, + Name name, + Tree tpe, + Tree rhs); + + public Tree PatDef(Tree tree, + int mods, + Tree pat, + Tree rhs); + + public Tree DefDef(Tree tree, + int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Tree rhs); + + public Tree TypeDef(Tree tree, + int mods, + Name name, + TypeDef[] tparams, + Tree rhs); + + public Tree Import(Tree tree, + Tree expr, + Name[] selectors); + + public Tree CaseDef(Tree tree, + Tree pat, + Tree guard, + Tree body); + + public Template Template(Tree tree, + Tree[] baseClasses, + Tree[] body); + + public Tree LabelDef(Tree tree, + Tree[] params, + Tree rhs); + + public Tree Block(Tree tree, + Tree[] stats); + + public Tree Tuple(Tree tree, + Tree[] trees); + + public Tree Visitor(Tree tree, + CaseDef[] cases); + + public Tree Function(Tree tree, + ValDef[] vparams, + Tree body); + + public Tree Assign(Tree tree, + Tree lhs, + Tree rhs); + + public Tree If(Tree tree, + Tree cond, + Tree thenp, + Tree elsep); + + public Tree New(Tree tree, + Template templ); + + public Tree Typed(Tree tree, + Tree expr, + Tree tpe); + + public Tree TypeApply(Tree tree, + Tree fun, + Tree[] args); + + public Tree Apply(Tree tree, + Tree fun, + Tree[] args); + + public Tree Super(Tree tree, + Tree tpe); + + public Tree This(Tree tree, + Tree qualifier); + + public Tree Select(Tree tree, + Tree qualifier, + Name selector); + + public Tree Ident(Tree tree, + Name name); + + public Tree Literal(Tree tree, + Object value); + + public Tree SingletonType(Tree tree, + Tree ref); + + public Tree SelectFromType(Tree tree, + Tree qualifier, + Name selector); + + public Tree FunType(Tree tree, + Tree[] argtpes, + Tree restpe); + + public Tree CompoundType(Tree tree, + Tree[] baseTypes, + Tree[] refinements); + + public Tree TupleType(Tree tree, + Tree[] types); + + public Tree AppliedType(Tree tree, + Tree tpe, + Tree[] args); + + public Tree CovariantType(Tree tree, + Tree tpe); + +} diff --git a/sources/scalac/ast/TreeCreator.java b/sources/scalac/ast/TreeCreator.java new file mode 100644 index 0000000000..6cb8afa1d8 --- /dev/null +++ b/sources/scalac/ast/TreeCreator.java @@ -0,0 +1,293 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast; + +import Tree.*; +import scalac.util.Name; + + +public class TreeCreator implements TreeFactory { + + public Tree Bad(int pos) { + Tree t = new ExtBad(); + t.pos = pos; + return t; + } + + public Tree ClassDef(int pos, + int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Template impl) { + Tree t = new ExtClassDef(mods, name, tparams, vparams, tpe, impl); + t.pos = pos; + return t; + } + + public Tree PackageDef(int pos, + Tree packaged, + Template impl) { + Tree t = new PackageDef(packaged, impl); + t.pos = pos; + return t; + } + + public Tree ModuleDef(int pos, + int mods, + Name name, + Tree tpe, + Template body) { + Tree t = new ExtModuleDef(mods, name, tpe, body); + t.pos = pos; + return t; + } + + public Tree ValDef(int pos, + int mods, + Name name, + Tree tpe, + Tree rhs) { + Tree t = new ExtValDef(mods, name, tpe, rhs); + t.pos = pos; + return t; + } + + public Tree PatDef(int pos, + int mods, + Tree pat, + Tree rhs) { + Tree t = new PatDef(mods, pat, rhs); + t.pos = pos; + return t; + } + + public Tree DefDef(int pos, + int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Tree rhs) { + Tree t = new ExtDefDef(mods, name, tparams, vparams, tpe, rhs); + t.pos = pos; + return t; + } + + + public Tree TypeDef(int pos, + int mods, + Name name, + TypeDef[] tparams, + Tree rhs) { + Tree t = new ExtTypeDef(mods, name, tparams, rhs); + t.pos = pos; + return t; + } + + public Tree Import(int pos, + Tree expr, + Name[] selectors) { + Tree t = new ExtImport(expr, selectors); + t.pos = pos; + return t; + } + + public CaseDef CaseDef(int pos, + Tree pat, + Tree guard, + Tree body) { + CaseDef t = new CaseDef(pat, guard, body); + t.pos = pos; + return t; + } + + public Template Template(int pos, + Tree[] baseClasses, + Tree[] body) { + Template t = new ExtTemplate(baseClasses, body); + t.pos = pos; + return t; + } + + public Tree LabelDef(int pos, + Tree[] params, + Tree body) { + Tree t = new ExtLabelDef(params,body); + t.pos = pos; + return t; + } + + public Tree Block(int pos, + Tree[] stats) { + Tree t = new Block(stats); + t.pos = pos; + return t; + } + + public Tree Tuple(int pos, + Tree[] trees) { + Tree t = new Tuple(trees); + t.pos = pos; + return t; + } + + public Tree Visitor(int pos, + CaseDef[] cases) { + Tree t = new Visitor(cases); + t.pos = pos; + return t; + } + + public Tree Function(int pos, + ValDef[] vparams, + Tree body) { + Tree t = new Function(vparams, body); + t.pos = pos; + return t; + } + + public Tree Assign(int pos, + Tree lhs, + Tree rhs) { + Tree t = new Assign(lhs, rhs); + t.pos = pos; + return t; + } + + public Tree If(int pos, + Tree cond, + Tree thenp, + Tree elsep) { + Tree t = new If(cond, thenp, elsep); + t.pos = pos; + return t; + } + + public Tree New(int pos, + Template templ) { + Tree t = new New(templ); + t.pos = pos; + return t; + } + + public Tree Typed(int pos, + Tree expr, + Tree tpe) { + Tree t = new Typed(expr, tpe); + t.pos = pos; + return t; + } + + public Tree TypeApply(int pos, + Tree fun, + Tree[] tparams) { + Tree t = new TypeApply(fun, tparams); + t.pos = pos; + return t; + } + + public Tree Apply(int pos, + Tree fun, + Tree[] vparam) { + Tree t = new Apply(fun, vparam); + t.pos = pos; + return t; + } + + public Tree Super(int pos, + Tree tpe) { + Tree t = new Super(tpe); + t.pos = pos; + return t; + } + + public Tree This(int pos, + Tree qualifier) { + Tree t = new This(qualifier); + t.pos = pos; + return t; + } + + public Tree Select(int pos, + Tree qualifier, + Name selector) { + Tree t = new ExtSelect(qualifier, selector); + t.pos = pos; + return t; + } + + public Tree Ident(int pos, + Name name) { + Tree t = new ExtIdent(name); + t.pos = pos; + return t; + } + + public Tree Literal(int pos, + Object value) { + Tree t = new Literal(value); + t.pos = pos; + return t; + } + + + public Tree SingletonType(int pos, Tree ref) { + Tree t = new SingletonType(ref); + t.pos = pos; + return t; + } + + public Tree SelectFromType(int pos, + Tree qualifier, + Name selector) { + Tree t = new ExtSelectFromType(qualifier, selector); + t.pos = pos; + return t; + } + + public Tree FunType(int pos, + Tree[] argtpes, + Tree restpe) { + Tree t = new FunType(argtpes, restpe); + t.pos = pos; + return t; + } + + public Tree CompoundType(int pos, + Tree[] mixins, + Tree[] fields) { + Tree t = new CompoundType(mixins, fields); + t.pos = pos; + return t; + } + + public Tree TupleType(int pos, + Tree[] types) { + Tree t = new TupleType(types); + t.pos = pos; + return t; + } + + public Tree AppliedType(int pos, + Tree tpe, + Tree[] args) { + Tree t = new AppliedType(tpe, args); + t.pos = pos; + return t; + } + + public Tree CovariantType(int pos, + Tree tpe) { + Tree t = new CovariantType(tpe); + t.pos = pos; + return t; + } +} diff --git a/sources/scalac/ast/TreeFactory.java b/sources/scalac/ast/TreeFactory.java new file mode 100644 index 0000000000..31ee67042e --- /dev/null +++ b/sources/scalac/ast/TreeFactory.java @@ -0,0 +1,155 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast; + +import scalac.util.Name; +import Tree.*; + +public interface TreeFactory { + + public Tree Bad(int pos); + + public Tree ClassDef(int pos, + int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Template impl); + + public Tree PackageDef(int pos, + Tree packaged, + Template impl); + + public Tree ModuleDef(int pos, + int mods, + Name name, + Tree tpe, + Template impl); + + public Tree ValDef(int pos, + int mods, + Name name, + Tree tpe, + Tree rhs); + + public Tree PatDef(int pos, + int mods, + Tree pat, + Tree rhs); + + public Tree DefDef(int pos, + int mods, + Name name, + TypeDef[] tparams, + ValDef[][] vparams, + Tree tpe, + Tree rhs); + + public Tree TypeDef(int pos, + int mods, + Name name, + TypeDef[] tparams, + Tree rhs); + + public Tree Import(int pos, + Tree expr, + Name[] selectors); + + public CaseDef CaseDef(int pos, + Tree pat, + Tree guard, + Tree body); + + public Template Template(int pos, + Tree[] baseClasses, + Tree[] body); + + public Tree LabelDef(int pos, + Tree[] params, + Tree rhs); + + public Tree Block(int pos, + Tree[] stats); + + public Tree Tuple(int pos, + Tree[] trees); + + public Tree Visitor(int pos, + CaseDef[] cases); + + public Tree Function(int pos, + ValDef[] vparams, + Tree body); + + public Tree Assign(int pos, + Tree lhs, + Tree rhs); + + public Tree If(int pos, + Tree cond, + Tree thenp, + Tree elsep); + + public Tree New(int pos, + Template templ); + + public Tree Typed(int pos, + Tree expr, + Tree tpe); + + public Tree TypeApply(int pos, + Tree fun, + Tree[] tparams); + + public Tree Apply(int pos, + Tree fun, + Tree[] vparam); + + public Tree Super(int pos, + Tree tpe); + + public Tree This(int pos, + Tree qualifier); + + public Tree Select(int pos, + Tree qualifier, + Name selector); + + public Tree Ident(int pos, + Name name); + + public Tree Literal(int pos, + Object value); + + public Tree SingletonType(int pos, + Tree ref); + + public Tree SelectFromType(int pos, + Tree qualifier, + Name selector); + + public Tree FunType(int pos, + Tree[] argtpes, + Tree restpe); + + public Tree CompoundType(int pos, + Tree[] baseTypes, + Tree[] refinements); + + public Tree TupleType(int pos, + Tree[] types); + + public Tree AppliedType(int pos, + Tree tpe, + Tree[] args); + + public Tree CovariantType(int pos, + Tree tpe); +} diff --git a/sources/scalac/ast/TreeGen.java b/sources/scalac/ast/TreeGen.java new file mode 100644 index 0000000000..26b02eb862 --- /dev/null +++ b/sources/scalac/ast/TreeGen.java @@ -0,0 +1,562 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast; + +import java.io.*; +import java.util.*; +import scalac.*; +import scalac.symtab.*; +import scalac.util.*; +import Tree.*; + +/** A helper class for building trees + * + * @author Martin Odersky, Christine Roeckl + * @version 1.0 + */ +public class TreeGen implements Kinds, Modifiers { + + /********************************************************************************/ + /********************************************************************************/ + /** VARIABLES **/ + + /** the global environment + */ + protected Global global; + + /** the global definitions + */ + protected Definitions definitions; + + /** the tree factory + */ + public TreeFactory make; + + /************************************************************************/ + /************************************************************************/ + /** CONSTRUCTORS **/ + + public TreeGen(Global global, TreeFactory make) { + this.global = global; + this.definitions = global.definitions; + this.make = make; + } + + public TreeGen(Global global) { + this(global, global.make); + } + + /*************************************************************************/ + /*************************************************************************/ + /** METHODS **/ + + /** Create a dummy symbol to be used for templates. + */ + public Symbol localDummy(int pos, Symbol owner) { + return new TermSymbol(pos, Name.EMPTY, owner, 0) + .setInfo(Type.NoType); + } + + public Tree mkRef(int pos, Type pre, Symbol sym) { + if (pre == Type.localThisType || pre.symbol().isRoot()) + return Ident(pos, sym); + else + return Select(pos, mkStableId(pos, pre), sym); + } + + /** Build and attribute stable identifier tree corresponding to given prefix. + */ + public Tree mkStableId(int pos, Type pre) { + switch (pre.expandModuleThis()) { + case ThisType(Symbol sym): + return make.This(pos, Ident(pos, sym)).setType(pre); + case SingleType(Type pre1, Symbol sym): + return mkRef(pos, pre1, sym); + default: + throw new ApplicationError(); + } + } + + /** Build and attribute tree corresponding to given type. + */ + public Tree mkType(int pos, Type type) { + Tree tree = mkTycon(pos, type); + switch (type) { + case TypeRef(Type pre, Symbol sym, Type[] args): + if (args.length != 0) + return make.AppliedType(pos, tree, mkType(pos, args)) + .setType(type); + } + return tree; + } + + /** Build and attribute tree corresponding to given type constructor. + */ + public Tree mkTycon(int pos, Type type) { + //System.out.println("making type " + type);//DEBUG + switch (type) { + + case NoType: + return Tree.Empty; + + case ErrorType: + case AnyType: + return make.Bad(pos).setSymbol(Symbol.ERROR).setType(type); + + case ThisType(_): + case SingleType(_, _): + return make.SingletonType(pos, mkStableId(pos, type)).setType(type); + + case TypeRef(Type pre, Symbol sym, Type[] args): + return mkRef(pos, pre, sym); + + case CompoundType(Type[] parents, Scope members): + if (parents.length == 1 && members.elems == Scope.Entry.NONE) + return mkType(pos, parents[0]); + else + return make.CompoundType( + pos, mkType(pos, parents), mkDefs(pos, members.elements())) + .setType(type); + + case CovarType(Type tp): + return make.CovariantType(pos, mkType(pos, tp)) + .setType(type); + + case UnboxedType(_): + case UnboxedArrayType(_): + return make.Ident(pos, Name.fromString(type.toString()).toTypeName()) + .setType(type); + + default: + throw new ApplicationError("illegal type", type); + } + } + + /** Build and attribute tree array corresponding to given type array. + */ + public Tree[] mkType(int pos, Type[] types) { + Tree[] res = new Tree[types.length]; + for (int i = 0; i < types.length; i++) { + res[i] = mkType(pos, types[i]); + } + return res; + } + + /** Build and attribute tree corresponding to symbol's declaration. + */ + public Tree mkDef(int pos, Symbol sym) { + switch (sym.kind) { + case ERROR: + return make.Bad(pos).setSymbol(Symbol.ERROR).setType(Type.ErrorType); + case TYPE: case ALIAS: + return TypeDef(pos, sym); + case VAL: + if (sym.isMethod()) return DefDef(pos, sym, Tree.Empty); + else return Param(pos, sym); + default: + throw new ApplicationError(); + } + } + + /** Build and attribute tree array corresponding to given symbol's declarations. + */ + public Tree[] mkDefs(int pos, Symbol[] syms) { + Tree[] res = new Tree[syms.length]; + for (int i = 0; i < syms.length; i++) { + res[i] = mkDef(pos, syms[i]); + } + return res; + } + + /** Build a tree to be used as a base class constructor for a template. + */ + public Tree mkParentConstr(int pos, Type parentType, Type root) { + switch (parentType) { + case TypeRef(Type pre, Symbol sym, Type[] args): + Tree ref = mkRef(pos, pre, sym.constructor()); + Tree constr = (args.length == 0) ? ref + : TypeApply(ref, mkType(sym.pos, args)); + switch (parentType) { + case MethodType(Symbol[] params, Type restpe): + assert params.length == 0 : parentType; + return Apply(constr, Tree.EMPTY_ARRAY); + default: + return constr; + } + default: + throw global.fail("invalid parent type", parentType); + } + } + + /** Build an array of trees to be used as base classes for a template. + */ + public Tree[] mkParentConstrs(int pos, Type[] parents, Type root) { + Tree[] constrs = new Tree[parents.length]; + for (int i = 0; i < parents.length; ++i) + constrs[i] = mkParentConstr(pos, parents[i], root); + return constrs; + } + + /** Build parameter sections corresponding to type. + */ + public ValDef[][] mkParams(int pos, Type type) { + switch (type) { + case PolyType(Symbol[] tparams, Type restype): + return mkParams(pos, restype); + case MethodType(Symbol[] vparams, Type restype): + ValDef[] params1 = mkParams(pos, vparams); + ValDef[][] paramss = mkParams(pos, restype); + if (paramss.length == 0) { + return new ValDef[][]{params1}; + } else { + ValDef[][] paramss1 = new ValDef[paramss.length + 1][]; + paramss1[0] = params1; + System.arraycopy(paramss, 0, paramss1, 1, paramss.length); + return paramss1; + } + default: + return new ValDef[][]{}; + } + } + + /** Build parameter section corresponding to given array of symbols . + */ + public ValDef[] mkParams(int pos, Symbol[] symbols) { + ValDef[] res = new ValDef[symbols.length]; + for (int i = 0; i < symbols.length; i++) { + res[i] = Param(pos, symbols[i]); + } + return res; + } + + /** Build type parameter section corresponding to given array of symbols . + */ + public TypeDef[] mkTypeParams(int pos, Symbol[] symbols) { + TypeDef[] res = new TypeDef[symbols.length]; + for (int i = 0; i < symbols.length; i++) { + res[i] = (TypeDef)TypeDef(pos, symbols[i]); + } + return res; + } + + /** Build type definition corresponding to given symbol . + */ + public TypeDef TypeDef(int pos, Symbol sym) { + Global.instance.nextPhase(); + Type symtype = sym.info(); + Global.instance.prevPhase(); + return (TypeDef) make.TypeDef( + pos, + sym.flags & SOURCEFLAGS, + sym.name, + mkTypeParams(pos, sym.typeParams()), + mkType(pos, symtype)) + .setSymbol(sym).setType(definitions.UNIT_TYPE); + } + + public Tree TypeDef(Symbol sym) { + return TypeDef(sym.pos, sym); + } + + /** Build parameter + */ + public ValDef Param(int pos, Symbol sym) { + return (ValDef)ValDef(pos, sym, Tree.Empty); + } + + public ValDef Param(Symbol sym) { + return Param(sym.pos, sym); + } + + /** Build and attribute block with given statements, starting + * at given position. The type is the type of the last + * statement in the block. + */ + public Tree Block(int pos, Tree[] stats) { + Type tp = (stats.length == 0) ? definitions.UNIT_TYPE + : stats[stats.length - 1].type; + return make.Block(pos, stats).setType(tp); + } + + /** Build and attribute non-empty block with given statements. + */ + public Tree Block(Tree[] stats) { + return Block(stats[0].pos, stats); + } + + public Tree Typed(Tree tree, Type tp) { + return make.Typed(tree.pos, tree, mkType(tree.pos, tp)).setType(tp); + } + + /** Build and attribute the assignment lhs = rhs + */ + public Tree Assign(int pos, Tree lhs, Tree rhs) { + return make.Assign(pos, lhs, rhs).setType(definitions.UNIT_TYPE); + } + + public Tree Assign(Tree lhs, Tree rhs) { + return Assign(lhs.pos, lhs, rhs); + } + + /** Build and attribute new B, given constructor expression B. + */ + public Tree New(Tree constr) { + Template templ = make.Template( + constr.pos, new Tree[]{constr}, Tree.EMPTY_ARRAY); + templ.setType(constr.type); + templ.setSymbol(localDummy(constr.pos, Symbol.NONE)); + return make.New(constr.pos, templ).setType(constr.type); } + + /** Build an allocation new P.C[TARGS](ARGS) + * given a (singleton) type P, class C, type arguments TARGS and arguments ARGS + */ + public Tree New(int pos, Type pre, Symbol clazz, + Type[] targs, Tree[] args) { + Tree constr = mkRef(pos, pre, clazz.constructor()); + if (targs.length != 0) constr = TypeApply(constr, mkType(pos, targs)); + Tree base = Apply(constr, args); + return New(base); + } + + /** Build a monomorphic allocation new P.C(ARGS) + * given a prefix P, class C and arguments ARGS + */ + public Tree New(int pos, Type pre, Symbol clazz, Tree[] args) { + return New(pos, pre, clazz, Type.EMPTY_ARRAY, args); + } + + /** Build and attribute application node with given function + * and argument trees. + */ + public Tree Apply(int pos, Tree fn, Tree[] args) { + switch (fn.type) { + case Type.MethodType(Symbol[] vparams, Type restpe): + return make.Apply(pos, fn, args).setType(restpe); + default: + throw new ApplicationError("method type required", fn.type); + } + } + + public Tree Apply(Tree fn, Tree[] args) { + return Apply(fn.pos, fn, args); + } + + /** Build and attribute type application node with given function + * and argument trees. + */ + public Tree TypeApply(int pos, Tree fn, Tree[] args) { + switch (fn.type) { + case Type.PolyType(Symbol[] tparams, Type restpe): + return make.TypeApply(pos, fn, args) + .setType(restpe.subst(tparams, Tree.typeOf(args))); + default: + throw new ApplicationError("poly type required", fn.type); + } + } + + public Tree TypeApply(Tree fn, Tree[] args) { + return TypeApply(fn.pos, fn, args); + } + + /** Build and applied type node with given function + * and argument trees. + */ + public Tree AppliedType(int pos, Tree fn, Tree[] args) { + return make.AppliedType(pos, fn, args) + .setType(Type.appliedType(fn.type, Tree.typeOf(args))); + } + + public Tree AppliedType(Tree fn, Tree[] args) { + return AppliedType(fn.pos, fn, args); + } + + /** Build and attribute select node of given symbol. + * It is assumed that the prefix is not empty. + */ + public Tree Select(int pos, Tree qual, Symbol sym) { + assert sym.kind != NONE; + Global.instance.nextPhase(); + Type symtype = qual.type.memberType(sym); + Global.instance.prevPhase(); + if (sym.kind == VAL && qual.type.isStable() && symtype.isObjectType()) + symtype = Type.singleType(qual.type, sym); + return make.Select(pos, qual, sym.name) + .setSymbol(sym).setType(symtype); + } + + public Tree Select(Tree qual, Symbol sym) { + return Select(qual.pos, qual, sym); + } + + public Tree Select(Tree qual, Name name) { + Symbol sym = qual.type.lookup(name); + assert (sym.kind != NONE && sym != Symbol.ERROR) : name + " from " + qual.type; + return Select(qual, sym); + } + + /** Build and attribute ident node with given symbol. + */ + public Tree Ident(int pos, Symbol sym) { + Global.instance.nextPhase(); + Type symtype = sym.type(); + Global.instance.prevPhase(); + if (sym.kind == VAL && symtype.isObjectType()) + symtype = Type.singleType(sym.owner().thisType(), sym); + return make.Ident(pos, sym.name) + .setSymbol(sym).setType(symtype); + } + + public Tree Ident(Symbol sym) { + return Ident(sym.pos, sym); + } + + /** Build and attribute this node with given symbol. + */ + public Tree This(int pos, Symbol sym) { + return make.This(pos, Ident(pos, sym)).setType(sym.thisType()); + } + + /** Build and attribute super node with given type. + */ + public Tree Super(int pos, Type type) { + return make.Super(pos, mkType(pos, type)).setType(type); + } + + /** Build and attribute value/variable/let definition node whose signature + * corresponds to given symbol and which has given rhs. + */ + public Tree ValDef(int pos, Symbol sym, Tree rhs) { + Global.instance.nextPhase(); + Type symtype = sym.type(); + Global.instance.prevPhase(); + return make.ValDef(pos, + sym.flags & SOURCEFLAGS, + sym.name, + mkType(pos, symtype), + rhs) + .setSymbol(sym).setType(definitions.UNIT_TYPE); + } + + public Tree ValDef(Symbol sym, Tree rhs) { + return ValDef(sym.pos, sym, rhs); + } + + /** Build and attribute value/variable/let definition node whose signature + * corresponds to given symbol and which has given body. + */ + public Tree DefDef(int pos, Symbol sym, Tree body) { + Global.instance.nextPhase(); + Type symtype = sym.type(); + Global.instance.prevPhase(); + return make.DefDef(pos, + sym.flags & SOURCEFLAGS, + sym.name, + mkTypeParams(pos, symtype.typeParams()), + mkParams(pos, symtype), + mkType(pos, symtype.resultType()), + body) + .setSymbol(sym).setType(definitions.UNIT_TYPE); + } + + public Tree DefDef(Symbol sym, Tree rhs) { + return DefDef(sym.pos, sym, rhs); + } + + /** Generate class definition from class symbol, parent constructors, and body. + */ + public Tree ClassDef(int pos, Symbol clazz, Tree[] constrs, Tree[] body) { + Global.instance.nextPhase(); + Type clazzinfo = clazz.info(); + Type constrtype = clazz.constructor().info(); + Global.instance.prevPhase(); + switch (clazzinfo) { + case CompoundType(Type[] parents, Scope members): + Template templ = make.Template(pos, constrs, body); + templ.setType(clazzinfo); + templ.setSymbol(localDummy(pos, clazz.owner())); + return make.ClassDef( + pos, + clazz.flags & SOURCEFLAGS, + clazz.name, + mkTypeParams(pos, constrtype.typeParams()), + mkParams(pos, constrtype), + Tree.Empty, + templ) + .setSymbol(clazz).setType(definitions.UNIT_TYPE); + default: + throw new ApplicationError(); + } + } + + public Tree ClassDef(Symbol clazz, Tree[] constrs, Tree[] body) { + return ClassDef(clazz.pos, clazz, constrs, body); + } + + /** Generate class definition from class symbol and body. + * All parents must by parameterless, or take unit parameters. + */ + public Tree ClassDef(int pos, Symbol clazz, Tree[] body) { + Global.instance.nextPhase(); + Type clazzinfo = clazz.info(); + Global.instance.prevPhase(); + return ClassDef(pos, + clazz, + mkParentConstrs(pos, clazzinfo.parents(), clazzinfo), + body); + } + + public Tree ClassDef(Symbol clazz, Tree[] body) { + return ClassDef(clazz.pos, clazz, body); + } + + /** Build the expansion of (() => expr) + * This is: + * { class $clazz() extends scala.Function0 { def apply() = expr } ; new $clazz() } + */ + public Tree mkUnitFunction(Tree expr, Type tp, Symbol owner) { + int pos = expr.pos; + Type f0t = definitions.functionType(Type.EMPTY_ARRAY, tp); + + ClassSymbol clazz = new ClassSymbol( + pos, Names.ANON_CLASS_NAME.toTypeName(), owner, 0); + clazz.setInfo(Type.compoundType(new Type[]{f0t}, new Scope(), clazz)); + clazz.constructor().setInfo( + Type.MethodType( + Symbol.EMPTY_ARRAY, + Type.TypeRef(owner.thisType(), clazz, Type.EMPTY_ARRAY))); + + Symbol applyMeth = new TermSymbol(pos, Names.apply, clazz, FINAL) + .setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, tp)); + clazz.info().members().enter(applyMeth); + + Tree applyDef = DefDef(applyMeth, changeOwner(expr, owner, applyMeth)); + Tree classDef = ClassDef(clazz, new Tree[]{applyDef}); + Tree alloc = New(pos, Type.localThisType, clazz, Tree.EMPTY_ARRAY); + return Block(new Tree[]{classDef, alloc}); + } + + /** Change owner of all defined symbols from `prevOwner' to `newOwner' + */ + public Tree changeOwner(Tree tree, final Symbol prevOwner, final Symbol newOwner) { + Transformer lifter = new Transformer(global, global.currentPhase) { + public Tree transform(Tree tree) { + if (TreeInfo.isDefinition(tree)) { + Symbol sym = tree.symbol(); + if (sym != null && sym.owner() == prevOwner) { + sym.setOwner(newOwner); + if (sym.kind == Kinds.CLASS) + sym.constructor().setOwner(newOwner); + } + } + return super.transform(tree); + } + }; + return lifter.transform(tree); + } +} diff --git a/sources/scalac/ast/TreeInfo.java b/sources/scalac/ast/TreeInfo.java new file mode 100644 index 0000000000..81d9481f31 --- /dev/null +++ b/sources/scalac/ast/TreeInfo.java @@ -0,0 +1,136 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast; + +import scalac.ApplicationError; +import scalac.util.Name; +import scalac.symtab.Type; +import scalac.symtab.Symbol; +import scalac.symtab.Modifiers; + +public class TreeInfo { + + public static boolean isTerm(Tree tree) { + return tree.isTerm(); + } + + public static boolean isType(Tree tree) { + return tree.isType(); + } + + public static boolean isOwnerDefinition(Tree tree) { + switch (tree) { + case PackageDef(_, _): + case ClassDef(_, _, _, _, _, _): + case ModuleDef(_, _, _, _): + case DefDef(_, _, _, _, _, _): + case Import(_, _): + return true; + default: + return false; + } + } + + public static boolean isDefinition(Tree tree) { + switch (tree) { + case PackageDef(_, _): + case ClassDef(_, _, _, _, _, _): + case ModuleDef(_, _, _, _): + case DefDef(_, _, _, _, _, _): + case ValDef(_, _, _, _): + case TypeDef(_, _, _, _): + case Import(_, _): + return true; + default: + return false; + } + } + + public static boolean isDeclaration(Tree tree) { + switch (tree) { + case DefDef(_, _, _, _, _, Tree rhs): + return rhs == Tree.Empty; + case ValDef(_, _, _, Tree rhs): + return rhs == Tree.Empty; + case TypeDef(_, _, _, _): + return true; + default: + return false; + } + } + + /** Is tree a pure definition? + */ + public static boolean isPureDef(Tree tree) { + switch (tree) { + case ClassDef(_, _, _, _, _, _): + case ModuleDef(_, _, _, _): + case DefDef(_, _, _, _, _, _): + case TypeDef(_, _, _, _): + case Import(_, _): + return true; + case ValDef(int mods, _, _, Tree rhs): + return (mods & Modifiers.MUTABLE) == 0 && isPureExpr(rhs); + default: + return false; + } + } + + /** Is tree a stable & pure expression? + */ + public static boolean isPureExpr(Tree tree) { + switch (tree) { + case Empty: + case This(_): + case Super(_): + return true; + case Ident(_): + return tree.type.isStable(); + case Select(Tree qual, _): + return tree.type.isStable() && isPureExpr(qual); + case Typed(Tree expr, _): + return isPureExpr(expr); + case Literal(_): + return true; + default: + return false; + } + } + + /** Is tree a pure constructor? + * //todo: update + */ + public static boolean isPureConstr(Tree tree) { + switch (tree) { + case Ident(_): + return tree.symbol() != null && tree.symbol().isPrimaryConstructor(); + case Select(Tree qual, _): + return isPureExpr(qual) && + tree.symbol() != null && tree.symbol().isPrimaryConstructor(); + case TypeApply(Tree constr, _): + return isPureConstr(constr); + default: + return false; + } + } + + /** The method symbol of an application node, or Symbol.NONE, if none exists. + */ + public static Symbol methSymbol(Tree tree) { + switch (tree) { + case Apply(Tree fn, _): + return methSymbol(fn); + case TypeApply(Tree fn, _): + return methSymbol(fn); + default: + if (tree.hasSymbol()) return tree.symbol(); + else return Symbol.NONE; + } + } +} diff --git a/sources/scalac/ast/TreeList.java b/sources/scalac/ast/TreeList.java new file mode 100644 index 0000000000..d35627c686 --- /dev/null +++ b/sources/scalac/ast/TreeList.java @@ -0,0 +1,71 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id +\* */ + +package scalac.ast; + + +public final class TreeList { + Tree[] trees; + int len; + + public TreeList(Tree[] ts) { + trees = ts; + len = ts.length; + } + + public TreeList() { + this(new Tree[4]); + len = 0; + } + + public void append(Tree tree) { + if (len == trees.length) { + Tree[] ts = new Tree[len * 2]; + System.arraycopy(trees, 0, ts, 0, len); + trees = ts; + } + trees[len++] = tree; + } + + public void append(Tree[] ts) { + for (int j = 0; j < ts.length; j++) + append(ts[j]); + } + + public void append(TreeList tl) { + for (int j = 0; j < tl.len; j++) + append(tl.trees[j]); + } + + public int length() { + return len; + } + + public Tree get(int i) { + return trees[i]; + } + + public Tree first() { + return trees[0]; + } + + public Tree removeLast() { + return trees[--len]; + } + + public Tree[] toArray() { + Tree[] ts = new Tree[len]; + System.arraycopy(trees, 0, ts, 0, len); + return ts; + } + + public Tree[] copyTo(Tree[] ts) { + System.arraycopy(trees, 0, ts, 0, len); + return ts; + } +} diff --git a/sources/scalac/ast/parser/Parser.java b/sources/scalac/ast/parser/Parser.java new file mode 100644 index 0000000000..cd491e2af9 --- /dev/null +++ b/sources/scalac/ast/parser/Parser.java @@ -0,0 +1,1704 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast.parser; + +import java.util.*; +import scalac.*; +import scalac.util.*; +import scalac.symtab.Modifiers; +import scalac.ast.*; +import Tree.*; + +/** A recursive descent parser for the programming language Scala. + * + * @author Martin Odersky, Matthias Zenger + * @version 1.2 + */ +public class Parser implements Tokens { + + /** the lexical analyzer + */ + Scanner s; + + /** the tree factory + */ + TreeFactory make; + + public Parser(Unit unit) { + s = new Scanner(unit); + make = unit.global.make; + } + + /** this is the general parse method + */ + public Tree[] parse() { + Tree[] ts = compilationUnit(); + accept(EOF); + return ts; + } + +/////// ERROR HANDLING ////////////////////////////////////////////////////// + + private void skip() { + //System.out.println(" " + s.token2string(s.token));//DEBUG + int nparens = 0; + int nbraces = 0; + while (true) { + switch (s.token) { + case EOF: + return; + case SEMI: + if (nparens == 0 && nbraces == 0) + return; + break; + case RPAREN: + nparens--; + break; + case RBRACE: + if (nbraces == 0) + return; + nbraces--; + break; + case LPAREN: + nparens++; + break; + case LBRACE: + nbraces++; + break; + } + //System.out.println("skipped: " + s.token2string(s.token));//DEBUG + s.nextToken(); + } + } + + Tree syntaxError(String msg, boolean skip) { + return syntaxError(s.pos, msg, skip); + } + + Tree syntaxError(int pos, String msg, boolean skip) { + if (pos != s.errpos) { + s.unit.error(pos, msg); + s.errpos = pos; + } + if (skip) skip(); + return make.Bad(pos); + } + + int accept(int token) { + int pos = s.pos; + if (s.token != token) { + int errpos = ((s.pos >>> Position.LINESHIFT) > + (s.lastpos >>> Position.LINESHIFT)) ? + s.lastpos : s.pos; + syntaxError(errpos, s.token2string(token) + " expected but " + + s.token2string(s.token) + " found.", true); + } + if (s.token == token) s.nextToken(); + return pos; + } + +/////// TOKEN CLASSES ////////////////////////////////////////////////////// + + boolean isModifier() { + return (s.token == ABSTRACT) + || (s.token == FINAL) + || (s.token == PRIVATE) + || (s.token == PROTECTED) +// || (s.token == QUALIFIED) + || (s.token == OVERRIDE); + } + + boolean isLocalClassModifier() { + return (s.token == ABSTRACT) + || (s.token == FINAL); + } + + boolean isDefIntro() { + switch (s.token) { + case VAL: case VAR: case DEF: case CONSTR: case TYPE: + case MODULE: case CLASS: case CASECLASS: case TRAIT: + return true; + default: + return false; + } + } + + boolean isDclIntro() { + switch (s.token) { + case VAL: case VAR: case DEF: case CONSTR: case TYPE: + return true; + default: + return false; + } + } + + boolean isExprIntro() { + switch (s.token) { + case CHARLIT: case INTLIT: case LONGLIT: + case FLOATLIT: case DOUBLELIT: case STRINGLIT: case NULL: + case IDENTIFIER: case THIS: case SUPER: + case IF: case FOR: case NEW: case USCORE: + case LPAREN: case LBRACKET: case LBRACE: + return true; + default: + return false; + } + } + +/////// TREE CONSTRUCTION //////////////////////////////////////////////////// + + /** Name supply + */ + int fresh = 0; + + Name fresh() { + return Name.fromString("x$" + (fresh++)); + } + + /** Create tree representing binary operation expression or pattern. + */ + Tree makeBinop(boolean isExpr, int pos, Tree left, Name op, Tree right) { + if (isExpr) { + if (op.leftAssoc()) { + return make.Apply(pos, + make.Select(pos, left, NameTransformer.encode(op)), + new Tree[]{right}); + } else { + Name x = fresh(); + return make.Block(pos, + new Tree[]{ + make.ValDef(pos, 0, x, Tree.Empty, left), + make.Apply(pos, + make.Select(pos, right, NameTransformer.encode(op)), + new Tree[]{make.Ident(left.pos, x)})}); + } + } else { + return make.Apply(pos, + make.Ident(pos, NameTransformer.encode(op).toTypeName()), + new Tree[]{left, right}); + } + } + + /** Create tree representing type scala.Any + */ + Tree scalaAnyType(int pos) { + return make.Select(pos, make.Ident(pos, Names.scala), Names.Any.toTypeName()); + } + + /** Create tree representing constructor scala.Object + */ + Tree scalaObjectConstr(int pos) { + return make.Select(pos, make.Ident(pos, Names.scala), Names.Object.toConstrName()); + } + + /** Create tree for for-comprehension or + * where mapName and flatmapName are chosen + * corresponding to whether this is a for-do or a for-yield. + */ + Tree makeFor(Tree[] enums, Name mapName, Name flatmapName, Tree body) { + switch (enums[0]) { + case PatDef(int mods, Tree pat, Tree rhs): + if (enums.length == 1) + return makeFor1(enums[0].pos, mapName, pat, rhs, body); + Tree[] newenums = new Tree[enums.length - 1]; + switch (enums[1]) { + case PatDef(int mods2, Tree pat2, Tree rhs2): + System.arraycopy(enums, 1, newenums, 0, newenums.length); + return makeFor1(enums[0].pos, flatmapName, pat, rhs, + makeFor(newenums, mapName, flatmapName, body)); + default: + System.arraycopy(enums, 2, newenums, 1, newenums.length - 1); + newenums[0] = make.PatDef( + enums[0].pos, mods, pat, + makeFor1(enums[0].pos, Names.filter, pat, rhs, enums[1])); + return makeFor(newenums, mapName, flatmapName, body); + } + default: + throw new ApplicationError(); + } + } + + //where + Tree makeFor1(int pos, Name name, Tree pat, Tree rhs, Tree body) { + Tree cont; + switch (pat) { + case Ident(Name name1): + cont = make.Function(pos, + new Tree.ValDef[]{ + (ValDef) + make.ValDef(pat.pos, Modifiers.PARAM, name1, Tree.Empty, Tree.Empty)}, + body); + break; + default: + cont = make.Visitor(pos, new Tree.CaseDef[]{ + (CaseDef)make.CaseDef(pos, pat, Tree.Empty, body)}); + } + return make.Apply(pos, make.Select(pos, rhs, name), new Tree[]{cont}); + } + + /** Convert tree to formal parameter list + */ + ValDef[] convertToParams(Tree t) { + switch (t) { + case Function(ValDef[] params, Tree.Empty): + return params; + case Ident(_): + case Typed(Ident(_), _): + return new ValDef[]{convertToParam(t)}; + case Block(Tree[] stats): + if (stats.length == 0) return Tree.ExtValDef.EMPTY_ARRAY; + } + syntaxError(t.pos, "malformed formal parameter list", false); + return Tree.ExtValDef.EMPTY_ARRAY; + } + + /** Convert list of trees to formal parameter list + */ + ValDef[] convertToParams(Tree[] ts) { + ValDef[] res = new ValDef[ts.length]; + for (int i = 0; i < res.length; i++) + res[i] = convertToParam(ts[i]); + return res; + } + + /** Convert tree to formal parameter + */ + ValDef convertToParam(Tree tree) { + switch (tree) { + case Ident(Name name): + return (ValDef)make.ValDef( + tree.pos, Modifiers.PARAM, name, Tree.Empty, Tree.Empty); + case Typed(Ident(Name name), Tree tpe): + return (ValDef)make.ValDef( + tree.pos, Modifiers.PARAM, name, tpe, Tree.Empty); + default: + Tree tpe = syntaxError(tree.pos, "not a legal formal parameter", false); + return (ValDef)make.ValDef( + tree.pos, Modifiers.PARAM, Names.ERROR, tpe, Tree.Empty); + } + } + + /** Convert (qual)ident to type identifier + */ + Tree convertToTypeId(Tree t) { + switch (t) { + case Ident(Name name): + return make.Ident(t.pos, name.toTypeName()); + case Select(Tree qual, Name name): + return make.Select(t.pos, qual, name.toTypeName()); + default: + return t; + } + } + + /** Convert (qual)ident to constructor identifier + */ + Tree convertToConstr(Tree t) { + switch (t) { + case Apply(Tree fn, Tree[] args): + return make.Apply(t.pos, convertToConstr(fn), args); + case TypeApply(Tree fn, Tree[] args): + return make.TypeApply(t.pos, convertToConstr(fn), args); + case Ident(Name name): + return make.Ident(t.pos, name.toConstrName()); + case Select(Tree qual, Name name): + return make.Select(t.pos, qual, name.toConstrName()); + default: + return syntaxError(t.pos, "class constructor expected", false); + } + } + +/////// OPERAND/OPERATOR STACK ///////////////////////////////////////////////// + + Tree[] operands = new Tree[8]; + int[] positions = new int[8]; + Name[] operators = new Name[8]; + int sp = 0; + + void push(Tree od, int pos, Name op) { + if (sp == operands.length) { + Tree[] operands1 = new Tree[sp * 2]; + System.arraycopy(operands, 0, operands1, 0, sp); + operands = operands1; + int[] positions1 = new int[sp * 2]; + System.arraycopy(positions, 0, positions1, 0, sp); + positions = positions1; + Name[] operators1 = new Name[sp * 2]; + System.arraycopy(operators, 0, operators1, 0, sp); + operators = operators1; + } + operands[sp] = od; + positions[sp] = pos; + operators[sp] = op; + sp++; + } + + Tree reduceStack(boolean isExpr, int base, Tree top, + int prec, boolean leftAssoc) { + if (sp != base && + operators[sp-1].precedence() == prec && + operators[sp-1].leftAssoc() != leftAssoc) { + syntaxError( + positions[sp-1], + "left- and right-associative operators with same precedence may not be mixed", + false); + } + while (sp != base && + (prec < operators[sp-1].precedence() || + (leftAssoc && prec == operators[sp-1].precedence()))) { + sp--; + top = makeBinop(isExpr, positions[sp], operands[sp], operators[sp], top); + } + return top; + } + +/////// IDENTIFIERS AND LITERALS //////////////////////////////////////////////////////////// + + static final Name MINUS = Name.fromString("-"); + static final Name PLUS = Name.fromString("+"); + static final Name BANG = Name.fromString("!"); + static final Name TILDE = Name.fromString("~"); + + Name ident() { + if (s.token == IDENTIFIER) { + Name name = NameTransformer.encode(s.name); + s.nextToken(); + return name; + } else { + accept(IDENTIFIER); + return Names.ERROR; + } + } + + /** StableRef ::= StableId + * | [Ident `.'] this + * SimpleType ::= StableRef [`.' type] + */ + Tree stableRef(boolean thisOK, boolean typeOK) { + Tree t; + if (s.token == THIS) { + t = make.This(s.skipToken(), Tree.Empty); + if (!thisOK || s.token == DOT) + t = selectors(accept(DOT), t, typeOK); + } else { + t = make.Ident(s.pos, ident()); + if (s.token == DOT) { + int pos = s.skipToken(); + if (s.token == THIS) { + s.nextToken(); + t = make.This(pos, convertToTypeId(t)); + if (!thisOK || s.token == DOT) + t = selectors(accept(DOT), t, typeOK); + } else { + t = selectors(pos, t, typeOK); + } + } + } + return t; + } + + Tree selectors(int pos, Tree t, boolean typeOK) { + if (typeOK && s.token == TYPE) { + s.nextToken(); + return make.SingletonType(pos, t); + } else { + t = make.Select(pos, t, ident()); + if (s.token == DOT) { + t = selectors(s.skipToken(), t, typeOK); + } + return t; + } + } + + /** StableId ::= [[Ident `.'] this `.'] {Id `.'} Id + */ + Tree stableId() { + return stableRef(false, false); + } + + /** QualId ::= Id {`.' Id} + */ + Tree qualId() { + Tree id = make.Ident(s.pos, ident()); + if (s.token == DOT) return selectors(s.skipToken(), id, false); + else return id; + } + + /** SimpleExpr ::= literal + * | null + */ + Tree literal() { + Tree t; + switch (s.token) { + case CHARLIT: + t = make.Literal(s.pos, new Character((char)s.intVal)); + break; + case INTLIT: + t = make.Literal(s.pos, new Integer((int)s.intVal)); + break; + case LONGLIT: + t = make.Literal(s.pos, new Long(s.intVal)); + break; + case FLOATLIT: + t = make.Literal(s.pos, new Float((float)s.floatVal)); + break; + case DOUBLELIT: + t = make.Literal(s.pos, new Double(s.floatVal)); + break; + case STRINGLIT: + t = make.Literal(s.pos, s.name.toString()); + break; + case NULL: + t = make.Ident(s.pos, Names.null_); + break; + default: + return syntaxError("illegal literal", true); + } + s.nextToken(); + return t; + } + +//////// TYPES /////////////////////////////////////////////////////////////// + + /** TypedOpt ::= [`:' Type] + */ + Tree typedOpt() { + if (s.token == COLON) { + s.nextToken(); + return type(); + } else { + return Tree.Empty; + } + } + + /** Types ::= Type {`,' Type} + */ + Tree[] types() { + TreeList ts = new TreeList(); + ts.append(type()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(type()); + } + return ts.toArray(); + } + + /** Type ::= Type1 `=>' Type + * | `(' [Types] `)' `=>' Type + * | Type1 + */ + Tree type() { + Tree t; + if (s.token == LPAREN) { + s.nextToken(); + if (s.token == RPAREN) { + s.nextToken(); + int pos = accept(ARROW); + return make.FunType(pos, Tree.EMPTY_ARRAY, type()); + } else { + t = type(); + if (s.token == COMMA) { + s.nextToken(); + TreeList ts = new TreeList(); + ts.append(t); + ts.append(types()); + accept(RPAREN); + int pos = accept(ARROW); + return make.FunType(pos, ts.toArray(), type()); + } else { + accept(RPAREN); + } + } + } else { + t = type1(); + } + if (s.token == ARROW) + return make.FunType(s.skipToken(), new Tree[]{t}, type()); + else + return t; + } + + /** Type1 ::= SimpleType {with SimpleType} [with Refinement] + */ + Tree type1() { + int pos = s.pos; + Tree t = simpleType(); + if (s.token == WITH) { + TreeList ts = new TreeList(); + ts.append(t); + while (s.token == WITH) { + s.nextToken(); + if (s.token == LBRACE) + return make.CompoundType(pos, ts.toArray(), refinement()); + else + ts.append(simpleType()); + } + return make.CompoundType(pos, ts.toArray(), Tree.EMPTY_ARRAY); + } else { + return t; + } + } + + /** SimpleType ::= SimpleType TypeArgs + * | SimpleType `#' Id + * | StableId + * | StableRef `.' type + * | `[' Types `]' + * | `(' Type `)' + */ + Tree simpleType() { + int pos = s.pos; + Tree t; + if (s.token == LPAREN) { + s.nextToken(); + t = type(); + accept(RPAREN); + } else if (s.token == LBRACKET) { + s.nextToken(); + Tree[] ts = types(); + accept(RBRACKET); + t = make.TupleType(pos, ts); + } else { + t = convertToTypeId(stableRef(false, true)); + } + while (true) { + if (s.token == HASH) + t = make.SelectFromType(s.skipToken(), t, ident().toTypeName()); + else if (s.token == LBRACKET) + t = make.AppliedType(pos, t, varTypeArgs()); + else break; + } + return t; + } + + /** TypeArgs ::= `[' Types `]' + */ + Tree[] typeArgs() { + accept(LBRACKET); + Tree[] ts = types(); + accept(RBRACKET); + return ts; + } + + /** VarTypeArgs ::= `[' VarType {`,' VarType} `]' + */ + Tree[] varTypeArgs() { + int pos = accept(LBRACKET); + TreeList ts = new TreeList(); + ts.append(varType()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(varType()); + } + accept(RBRACKET); + return ts.toArray(); + } + + /** VarType ::= [`+'] Type + */ + Tree varType() { + int pos = s.pos; + if (s.token == IDENTIFIER && s.name == PLUS) + return make.CovariantType(s.skipToken(), type()); + else + return type(); + } + +//////// EXPRESSIONS //////////////////////////////////////////////////////// + + /** EqualsExpr ::= `=' Expr + */ + Tree equalsExpr() { + accept(EQUALS); + return expr(); + } + + /** Exprs ::= Expr {`,' Expr} + */ + Tree[] exprs() { + TreeList ts = new TreeList(); + ts.append(expr()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(expr()); + } + return ts.toArray(); + } + + /** Expr ::= [Bindings `=>'] Expr + * | if `(' Expr `)' Expr [[`;'] else Expr] + * | for `(' Enumerators `)' [do | yield] Expr + * | Designator `=' Expr + * | SimpleExpr ArgumentExprs `=' Expr + * | PostfixExpr [`:' Type1 | as Type1 | is Type1] + * Bindings ::= Id [`:' Type1] + * | `(' [Binding {`,' Binding}] `)' + */ + Tree expr() { + if (s.token == IF) { + int pos = s.skipToken(); + accept(LPAREN); + Tree cond = expr(); + accept(RPAREN); + Tree thenp = expr(); + Tree elsep = Tree.Empty; + if (s.token == ELSE) { + s.nextToken(); + elsep = expr(); + } else { + elsep = Tree.Empty; + } + return make.If(pos, cond, thenp, elsep) ; + } else if (s.token == FOR) { + s.nextToken(); + accept(LPAREN); + Tree[] enums = enumerators(); + accept(RPAREN); + if (s.token == DO) { + s.nextToken(); + return makeFor(enums, Names.foreach, Names.foreach, expr()); + } else if (s.token == YIELD) { + s.nextToken(); + return makeFor(enums, Names.map, Names.flatmap, expr()); + } else { + return syntaxError("`do' or `yield' expected", true); + } +// } else if (s.token == ARROW) { +// return make.Function(s.skipToken(), new ValDef[]{}, expr()); + } else { + Tree t = postfixExpr(); + if (s.token == EQUALS) { + switch (t) { + case Ident(_): + case Select(_, _): + case Apply(_, _): + t = make.Assign(s.skipToken(), t, expr()); + } + } else if (s.token == COLON) { + int pos = s.skipToken(); + Tree tp = type1(); + t = make.Typed(pos, t, tp); + } else if (s.token == AS || s.token == IS) { + Name op = (s.token == AS) ? Names.as : Names.is; + int pos = s.skipToken(); + t = make.TypeApply(pos, make.Select(pos, t, op), new Tree[]{type1()}); + } + if (s.token == ARROW) { + t = make.Function(s.skipToken(), convertToParams(t), expr()); + } + return t; + } + } + + /** PostfixExpr ::= InfixExpr [Id] + * InfixExpr ::= PrefixExpr + * | InfixExpr Id InfixExpr + */ + Tree postfixExpr() { + int base = sp; + Tree top = prefixExpr(); + while (s.token == IDENTIFIER) { + top = reduceStack( + true, base, top, s.name.precedence(), s.name.leftAssoc()); + push(top, s.pos, s.name); + ident(); + if (isExprIntro()) { + top = prefixExpr(); + } else { + sp--; + int pos = positions[sp]; + Name postOp = operators[sp]; + top = reduceStack(true, base, operands[sp], 0, true); + return make.Select(pos, top, postOp); + } + } + return reduceStack(true, base, top, 0, true); + } + + /** PrefixExpr ::= [op] SimpleExpr + */ + Tree prefixExpr() { + Tree t; + if (s.token == IDENTIFIER && + (s.name == MINUS || + s.name == PLUS || + s.name == TILDE || + s.name == BANG)) { + Name name = ident(); + t = make.Select(s.pos, simpleExpr(), name); + } else { + t = simpleExpr(); + } + return t; + } + + /* SimpleExpr ::= literal + * | null + * | StableRef + * | super `.' Id + * | SimpleExpr `.' Id + * | `(' [Expr] `)' + * | `[' [Exprs] `]' + * | BlockExpr + * | SimpleExpr `@' TypeArgs + * | SimpleExpr ArgumentExprs + * | new Template + * | `_' + */ + Tree simpleExpr() { + Tree t; + switch (s.token) { + case CHARLIT: + case INTLIT: + case LONGLIT: + case FLOATLIT: + case DOUBLELIT: + case STRINGLIT: + case NULL: + t = literal(); + break; + case IDENTIFIER: + case THIS: + t = stableRef(true, false); + break; + case SUPER: + int pos = s.skipToken(); + t = make.Select(accept(DOT), make.Super(pos, Tree.Empty), ident()); + break; + case LPAREN: + int pos = s.skipToken(); + if (s.token == RPAREN) { + s.nextToken(); + t = make.Block(pos, Tree.EMPTY_ARRAY); + } else { + t = expr(); + if (s.token == COMMA) { + int commapos = s.skipToken(); + TreeList ts = new TreeList(); + ts.append(t); + ts.append(exprs()); + accept(RPAREN); + if (s.token == ARROW) { + t = make.Function(pos, convertToParams(ts.toArray()), Tree.Empty); + } else { + t = syntaxError(commapos, "`)' expected", false); + } + } else { + accept(RPAREN); + } + } + break; + case LBRACKET: + int pos = s.skipToken(); + Tree[] ts; + if (s.token == RBRACKET) ts = Tree.EMPTY_ARRAY; + else ts = exprs(); + t = make.Tuple(pos, ts); + accept(RBRACKET); + break; + case LBRACE: + t = blockExpr(); + break; + case NEW: + t = make.New(s.skipToken(), template()); + break; + default: + return syntaxError("illegal start of expression", true); + } + while (true) { + switch (s.token) { + case DOT: + t = make.Select(s.skipToken(), t, ident()); + break; + case AT: + int pos = s.skipToken(); + t = make.TypeApply(pos, t, typeArgs()); + break; + case LPAREN: + case LBRACKET: + case LBRACE: + t = make.Apply(s.pos, t, argumentExprs()); + break; + default: + return t; + } + } + } + + /** ArgumentExprs ::= `(' [Exprs] `)' + * | `[' [Exprs] `]' + * | BlockExpr + */ + Tree[] argumentExprs() { + Tree[] ts = Tree.EMPTY_ARRAY; + if (s.token == LBRACE) { + ts = new Tree[]{blockExpr()}; + } else if (s.token == LBRACKET) { + int pos = s.skipToken(); + if (s.token != RBRACKET) + ts = exprs(); + accept(RBRACKET); + ts = new Tree[]{make.Tuple(pos, ts)}; + } else { + accept(LPAREN); + if (s.token != RPAREN) + ts = exprs(); + accept(RPAREN); + } + return ts; + } + + /** BlockExpr ::= `{' CaseClause {CaseClause} `}' + * | `{' Block `}' + */ + Tree blockExpr() { + Tree res; + int pos = accept(LBRACE); + if (s.token == CASE) { + TreeList stats = new TreeList(); + do { + stats.append(caseClause()); + } while (s.token == CASE); + res = make.Visitor( + pos, (CaseDef[]) stats.copyTo(new CaseDef[stats.length()])); + } else { + res = block(pos); + } + accept(RBRACE); + return res; + } + + /** BlockConstr ::= `{' Block `}' + */ + Tree blockConstr() { + int pos = accept(LBRACE); + Tree res = block(pos); + switch (res) { + case Block(Tree[] stats): + if (stats.length > 0) + stats[stats.length - 1] = convertToConstr(stats[stats.length - 1]); + else + syntaxError(res.pos, "class constructor expected", false); + } + accept(RBRACE); + return res; + } + + /** Block ::= BlockStatSeq + */ + Tree block(int pos) { + Tree[] stats = blockStatSeq(new TreeList()); + if (stats.length == 1) return stats[0]; + else return make.Block(pos, stats); + } + + /** CaseClause ::= case Pattern [if `(' Expr `)'] `=>' Block + */ + Tree caseClause() { + int pos = accept(CASE); + Tree pat = pattern(); + Tree guard = Tree.Empty; + if (s.token == IF) { + s.nextToken(); + accept(LPAREN); + guard = expr(); + accept(RPAREN); + } + accept(ARROW); + return make.CaseDef(pos, pat, guard, block(s.pos)); + } + + /** Enumerators ::= Generator {`;' Enumerator} + * Enumerator ::= Generator + * | Expr + */ + Tree[] enumerators() { + TreeList enums = new TreeList(); + enums.append(generator()); + while (s.token == SEMI) { + s.nextToken(); + if (s.token == VAL) enums.append(generator()); + else enums.append(expr()); + } + return enums.toArray(); + } + + /** Generator ::= val Pattern `<-' Expr + */ + Tree generator() { + int pos = accept(VAL); + Tree p = pattern(); + accept(LARROW); + return make.PatDef(pos, 0, p, expr()); + } + +//////// PATTERNS //////////////////////////////////////////////////////////// + + /** Patterns ::= Pattern {`,' Pattern} + */ + Tree[] patterns() { + TreeList ts = new TreeList(); + ts.append(pattern()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(pattern()); + } + return ts.toArray(); + } + + /** Pattern ::= varid `:' Type1 + * | `_' `:' Type1 + * | SimplePattern {Id SimplePattern} + */ + Tree pattern() { + int base = sp; + Tree top = simplePattern(); + if (s.token == COLON) { + switch (top) { + case Ident(Name name): + if (name.isVariable()) + return make.Typed(s.skipToken(), top, type1()); + } + } + while (s.token == IDENTIFIER) { + top = reduceStack( + false, base, top, s.name.precedence(), s.name.leftAssoc()); + push(top, s.pos, s.name); + ident(); + top = simplePattern(); + } + return reduceStack(false, base, top, 0, true); + } + + /** SimplePattern ::= varid + * | `_' + * | literal + * | null + * | StableId {ArgumentPatterns} + * | `(' Pattern `)' + * | `[' [Patterns] `]' + */ + Tree simplePattern() { + switch (s.token) { + case IDENTIFIER: + case THIS: + Tree t = stableId(); + while (s.token == LPAREN || s.token == LBRACKET) { + t = make.Apply(s.pos, convertToConstr(t), argumentPatterns()); + } + return t; + case USCORE: + return make.Ident(s.skipToken(), Names.WILDCARD); + case CHARLIT: + case INTLIT: + case LONGLIT: + case FLOATLIT: + case DOUBLELIT: + case STRINGLIT: + case NULL: + return literal(); + case LPAREN: + s.nextToken(); + Tree t = pattern(); + accept(RPAREN); + return t; + case LBRACKET: + return tuplePattern(); + default: + return syntaxError("illegal start of pattern", true); + } + } + + /** SimplePattern ::= `[' [Patterns] ']' + */ + Tree tuplePattern() { + int pos = accept(LBRACKET); + Tree[] ts; + if (s.token == RBRACKET) ts = Tree.EMPTY_ARRAY; + else ts = patterns(); + accept(RBRACKET); + return make.Tuple(pos, ts); + } + + /** ArgumentPatterns ::= `(' [Patterns] `)' + * | `[' [Patterns] `]' + */ + Tree[] argumentPatterns() { + if (s.token == LBRACKET) { + return new Tree[]{tuplePattern()}; + } else { + Tree[] ts = Tree.EMPTY_ARRAY; + accept(LPAREN); + if (s.token != RPAREN) + ts = patterns(); + accept(RPAREN); + return ts; + } + } + +////////// MODIFIERS //////////////////////////////////////////////////////////// + + /** Modifiers ::= {Modifier} + * Modifier ::= final + * | private + * | protected + * | override + * | abstract + */ + int modifiers() { + int mods = 0; + while (true) { + int mod; + switch (s.token) { + case ABSTRACT: + mod = Modifiers.ABSTRACTCLASS; + break; + case FINAL: + mod = Modifiers.FINAL; + break; + case PRIVATE: + mod = Modifiers.PRIVATE; + break; + case PROTECTED: + mod = Modifiers.PROTECTED; + break; + case OVERRIDE: + mod = Modifiers.OVERRIDE; + break; + default: + return mods; + } + if ((mods & mod) != 0) + syntaxError(s.pos, "repeated modifier", false); + mods |= mod; + s.nextToken(); + } + } + + /** LocalClassModifiers ::= {LocalClassModifier} + * LocalClassModifier ::= final + * | private + */ + int localClassModifiers() { + int mods = 0; + while (true) { + int mod; + switch (s.token) { + case ABSTRACT: + mod = Modifiers.ABSTRACTCLASS; + break; + case FINAL: + mod = Modifiers.FINAL; + break; + default: + return mods; + } + if ((mods & mod) != 0) + syntaxError(s.pos, "repeated modifier", false); + mods |= mod; + s.nextToken(); + } + } + +//////// PARAMETERS ////////////////////////////////////////////////////////// + + /** ParamClauses ::= {ParamClause} + */ + ValDef[][] paramClauses() { + ArrayList ts = new ArrayList(); + while (s.token == LPAREN) + ts.add(paramClause()); + return (ValDef[][])ts.toArray(new ValDef[ts.size()][]); + } + + /** ParamClause ::= `(' [Param {`,' Param}] `)' + */ + ValDef[] paramClause() { + int pos = accept(LPAREN); + TreeList params = new TreeList(); + if (s.token != RPAREN) { + params.append(param()); + while (s.token == COMMA) { + s.nextToken(); + params.append(param()); + } + } + accept(RPAREN); + return (ValDef[])params.copyTo(new ValDef[params.length()]); + } + + /** Param ::= [def] Id `:' Type + */ + ValDef param() { + int pos = s.pos; + int mods = Modifiers.PARAM; + if (s.token == DEF) { + mods |= Modifiers.DEF; + s.nextToken(); + } + Name name = ident(); + accept(COLON); + return (ValDef)make.ValDef(pos, mods, name, type(), Tree.Empty); + } + + /** TypeParamClauseOpt ::= [`[' TypeSig {`,' TypeSig} `]'] + */ + TypeDef[] typeParamClauseOpt() { + TreeList params = new TreeList(); + if (s.token == LBRACKET) { + s.nextToken(); + params.append(typeParam()); + while (s.token == COMMA) { + s.nextToken(); + params.append(typeParam()); + } + accept(RBRACKET); + } + return (TypeDef[])params.copyTo(new TypeDef[params.length()]); + } + + /** TypeSig ::= Id [<: Type] + */ + Tree typeParam() { + int pos = s.pos; + Name name = ident(); + Tree tp; + if (s.token == SUBTYPE) { + s.nextToken(); + tp = type(); + } else { + tp = scalaAnyType(pos); + } + return make.TypeDef(pos, Modifiers.PARAM, name.toTypeName(), + Tree.ExtTypeDef.EMPTY_ARRAY, tp); + } + +//////// DEFS //////////////////////////////////////////////////////////////// + + /** Import ::= import ImportRef {`,' ImportRef} + */ + Tree[] importClause() { + accept(IMPORT); + TreeList ts = new TreeList(); + ts.append(importRef()); + while (s.token == COMMA) { + s.nextToken(); + ts.append(importRef()); + } + return ts.toArray(); + } + + /** ImportRef ::= StableId `.' (Id | `_' | ImportSelectors) + */ + Tree importRef() { + Tree t; + int startpos = s.pos; + int pos; + if (s.token == THIS) { + t = make.This(s.skipToken(), Tree.Empty); + t = make.Select(accept(DOT), t, ident()); + pos = accept(DOT); + } else { + t = make.Ident(s.pos, ident()); + pos = accept(DOT); + if (s.token == THIS) { + s.nextToken(); + t = make.This(pos, convertToTypeId(t)); + t = make.Select(accept(DOT), t, ident()); + pos = accept(DOT); + } + } + while (true) { + if (s.token == USCORE) { + s.nextToken(); + return make.Import(startpos, t, new Name[]{Names.WILDCARD}); + } else if (s.token == LBRACE) { + return make.Import(startpos, t, importSelectors()); + } else { + Name name = ident(); + if (s.token == DOT) { + t = make.Select(pos, t, name); + pos = accept(DOT); + } else { + return make.Import(startpos, t, new Name[]{name, name}); + } + } + } + } + + /** ImportSelectors ::= `{' {ImportSelector `,'} (ImportSelector | `_') `}' + */ + Name[] importSelectors() { + LinkedList/**/ names = new LinkedList(); + accept(LBRACE); + boolean isLast = importSelector(names); + while (!isLast && s.token == COMMA) { + s.nextToken(); + isLast = importSelector(names); + } + accept(RBRACE); + return (Name[])names.toArray(new Name[]{}); + } + + /** ImportSelector ::= Id [`=>' [Id | `_']] + */ + boolean importSelector(LinkedList/**/ names) { + if (s.token == USCORE) { + s.nextToken(); + names.add(Names.WILDCARD); + return true; + } else { + Name name = ident(); + names.add(name); + if (s.token == ARROW) { + s.nextToken(); + if (s.token == USCORE) { + s.nextToken(); + names.add(Names.WILDCARD); + } else { + names.add(ident()); + } + } else { + names.add(name); + } + return false; + } + } + + /** Def ::= val PatDef {`,' PatDef} + * | var VarDef {`,' VarDef} + * | def FunDef {`,' FunDef} + * | constr ConstrDef {`,' ConstrDef} + * | type TypeDef {`,' TypeDef} + * | TopDef + * Dcl ::= val ValSig {`,' ValSig} + * | var ValSig {`,' ValSig} + * | def FunSig {`,' FunSig} + * | constr ConstrSig {`,' ConstrSig} + * | type TypeSig {`,' TypeSig} + */ + Tree[] defOrDcl(int mods) { + TreeList ts = new TreeList(); + switch (s.token) { + case VAL: + do { + s.nextToken(); + ts.append(patDefOrSig(mods)); + } while (s.token == COMMA); + return ts.toArray(); + case VAR: + do { + s.nextToken(); + ts.append(varDefOrSig(mods)); + } while (s.token == COMMA); + return ts.toArray(); + case DEF: + do { + s.nextToken(); + ts.append(funDefOrSig(mods)); + } while (s.token == COMMA); + return ts.toArray(); + case CONSTR: + do { + s.nextToken(); + ts.append(constrDefOrSig(mods)); + } while (s.token == COMMA); + return ts.toArray(); + case TYPE: + do { + s.nextToken(); + ts.append(typeDefOrSig(mods)); + } while (s.token == COMMA); + return ts.toArray(); + default: + return topDef(mods); + } + } + + /** TopDef ::= ([case] class) ClassDef {`,' ClassDef} + * | trait TraitDef {`,' TraitDef} + * | module ModuleDef {`,' ModuleDef} + * LocalTopDef ::= class ClassDef {`,' ClassDef} + * | trait TraitDef {`,' TraitDef} + * | module ModuleDef {`,' ModuleDef} + */ + Tree[] topDef(int mods) { + TreeList ts = new TreeList(); + switch (s.token) { + case CLASS: + case CASECLASS: + case TRAIT: + if (s.token == CASECLASS) mods |= Modifiers.CASE; + else if (s.token == TRAIT) mods |= Modifiers.TRAIT | Modifiers.ABSTRACTCLASS; + do { + s.nextToken(); + ts.append(classDef(mods)); + } while (s.token == COMMA); + return ts.toArray(); + case MODULE: + do { + s.nextToken(); + ts.append(moduleDef(mods)); + } while (s.token == COMMA); + return ts.toArray(); + default: + return new Tree[]{syntaxError("illegal start of definition", true)}; + } + } + + /** PatDef ::= Pattern `=' Expr + * ValSig ::= Id `:' Type + */ + Tree patDefOrSig(int mods) { + int pos = s.pos; + Tree pat = pattern(); + Tree tp; + switch (pat) { + case Typed(Tree pat1, Tree tp1): + pat = pat1; + tp = tp1; + break; + default: + if (s.token == COLON) tp = typedOpt(); + else tp = Tree.Empty; + } + switch (pat) { + case Ident(Name name): + if (tp == Tree.Empty || s.token == EQUALS) + return make.ValDef(pos, mods, name, tp, equalsExpr()); + else + return make.ValDef(pos, mods | Modifiers.ABSTRACT, name, tp, Tree.Empty); + default: + return make.PatDef(pos, mods, pat, equalsExpr()); + } + } + + /** VarDef ::= Id [`:' Type] `=' Expr + * | Id `:' Type `=' `_' + * VarSig ::= Id `:' Type + */ + Tree varDefOrSig(int mods) { + int pos = s.pos; + Name name = ident(); + Tree type = typedOpt(); + if (type == Tree.Empty || s.token == EQUALS) { + accept(EQUALS); + Tree rhs; + if (type != Tree.Empty && s.token == USCORE) { + rhs = Tree.Empty; + s.nextToken(); + } else { + rhs = expr(); + } + return make.ValDef(pos, mods | Modifiers.MUTABLE, name, type, rhs); + } else { + return make.ValDef(pos, mods | Modifiers.MUTABLE | Modifiers.ABSTRACT, + name, type, Tree.Empty); + } + } + + /** FunDef ::= Id [TypeParamClause] {ParamClause} [`:' Type] + * (`=' Expr | BlockExpr) + * FunSig ::= Id [TypeParamClause] {ParamClause} `:' Type + */ + Tree funDefOrSig(int mods) { + int pos = s.pos; + Name name = ident(); + TypeDef[] tparams = typeParamClauseOpt(); + ValDef[][] vparams = paramClauses(); + Tree restype = typedOpt(); + if (s.token == LBRACE) + return make.DefDef(pos, mods, name, tparams, vparams, + restype, blockExpr()); + else if (s.token == EQUALS || restype == Tree.Empty) + return make.DefDef(pos, mods, name, tparams, vparams, + restype, equalsExpr()); + else + return make.DefDef(pos, mods | Modifiers.ABSTRACT, name, + tparams, vparams, restype, Tree.Empty); + } + + /* ConstrDef ::= Id [TypeParamClause] [ParamClause] [`:' Type] + * (`=' Constr | `=' BlockConstr | BlockConstr) + */ + Tree constrDefOrSig(int mods) { + int pos = s.pos; + Name name = ident().toConstrName(); + TypeDef[] tparams = typeParamClauseOpt(); + ValDef[][] vparams = new ValDef[][]{paramClause()}; + Tree restype = typedOpt(); + if (s.token == LBRACE) + return make.DefDef(pos, mods, name, tparams, vparams, + restype, blockConstr()); + else if (s.token == EQUALS || restype == Tree.Empty) { + accept(EQUALS); + return make.DefDef(pos, mods, name, tparams, vparams, + restype, (s.token == LBRACE) ? blockConstr() : constr()); + } else + return make.DefDef(pos, mods | Modifiers.ABSTRACT, name, + tparams, vparams, restype, Tree.Empty); + } + + /** TypeDef ::= Id [TypeParamClause] `=' Type + * TypeSig ::= Id [`<:' Type] + */ + Tree typeDefOrSig(int mods) { + int pos = s.pos; + Name name = ident().toTypeName(); + if (s.token == SUBTYPE) { + s.nextToken(); + return make.TypeDef(pos, mods | Modifiers.ABSTRACT, name, + Tree.ExtTypeDef.EMPTY_ARRAY, type()); + } else if (s.token == LBRACKET) { + TypeDef[] tparams = typeParamClauseOpt(); + accept(EQUALS); + return make.TypeDef(pos, mods, name, tparams, type()); + } else if (s.token == EQUALS) { + s.nextToken(); + return make.TypeDef(pos, mods, name, + Tree.ExtTypeDef.EMPTY_ARRAY, type()); + } else if (s.token == SEMI || s.token == COMMA) { + return make.TypeDef( + pos, mods | Modifiers.ABSTRACT, name, + Tree.ExtTypeDef.EMPTY_ARRAY, scalaAnyType(pos)); + } else { + return syntaxError("`=' or `<:' expected", true); + } + } + + /** ClassDef ::= Id [TypeParamClause] ParamClause [`:' Type] ClassTemplate + * TraitDef ::= Id [TypeParamClause] [`:' Type] ClassTemplate + */ + Tree classDef(int mods) { + int pos = s.pos; + Name name = ident(); + TypeDef[] tparams = typeParamClauseOpt(); + ValDef[][] params; + if ((mods & Modifiers.TRAIT) == 0) params = new ValDef[][]{paramClause()}; + else params = new ValDef[][]{}; + return make.ClassDef(pos, mods, name.toTypeName(), tparams, params, + typedOpt(), classTemplate()); + } + + /** ModuleDef ::= Id [`:' Type] ClassTemplate + */ + Tree moduleDef(int mods) { + return make.ModuleDef( + s.pos, mods, ident(), typedOpt(), classTemplate()); + } + + /** ClassTemplate ::= extends Template + * | TemplateBody + */ + Template classTemplate() { + int pos = s.pos; + if (s.token == EXTENDS) { + s.nextToken(); + return template(); + } else if (s.token == LBRACE) { + return (Template)make.Template( + pos, new Tree[]{scalaObjectConstr(pos)}, templateBody()); + } else { + syntaxError("`extends' or `{' expected", true); + return (Template)make.Template( + pos, new Tree[]{scalaObjectConstr(pos)}, Tree.EMPTY_ARRAY); + } + } + +////////// TEMPLATES //////////////////////////////////////////////////////////// + + + /** Template ::= Constr {`with' Constr} [TemplateBody] + */ + Template template() { + int pos = s.pos; + TreeList parents = new TreeList(); + parents.append(constr()); + while (s.token == WITH) { + s.nextToken(); + if (s.token == LBRACE) + return (Template)make.Template(pos, parents.toArray(), templateBody()); + else + parents.append(constr()); + } + Tree[] stats = (s.token == LBRACE) ? templateBody() : Tree.EMPTY_ARRAY; + return (Template)make.Template(pos, parents.toArray(), stats); + } + + /** Constr ::= StableId [TypeArgs] [`(' [Exprs] `)'] + */ + Tree constr() { + Tree t = convertToConstr(stableId()); + if (s.token == LBRACKET) + t = make.TypeApply(s.pos, t, typeArgs()); + if (s.token == LPAREN) + t = make.Apply(s.pos, t, argumentExprs()); + return t; + } + + /** TemplateBody ::= `{' [TemplateStat {`;' TemplateStat}] `}' + */ + Tree[] templateBody() { + accept(LBRACE); + Tree[] body = templateStatSeq(); + accept(RBRACE); + return body; + } + + /** Refinement ::= `{' [RefineStat {`;' RefineStat}] `}' + */ + Tree[] refinement() { + accept(LBRACE); + Tree[] body = refineStatSeq(); + accept(RBRACE); + return body; + } + +/////// STATSEQS ////////////////////////////////////////////////////////////// + + /** Packaging ::= package QualId `{' TopStatSeq `}' + */ + Tree packaging() { + int pos = accept(PACKAGE); + Tree pkg = qualId(); + accept(LBRACE); + Tree[] stats = topStatSeq(); + accept(RBRACE); + return + make.PackageDef(pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, stats)); + } + + /** TopStatSeq ::= [TopStat {`;' TopStat}] + * TopStat ::= Modifiers TopDef + * | Packaging + * | Import + * | + */ + Tree[] topStatSeq() { + TreeList stats = new TreeList(); + while (s.token != RBRACE && s.token != EOF) { + if (s.token == PACKAGE) { + stats.append(packaging()); + } else if (s.token == IMPORT) { + stats.append(importClause()); + } else if (s.token == CLASS || + s.token == CASECLASS || + s.token == TRAIT || + s.token == MODULE || + isModifier()) { + stats.append(topDef(modifiers())); + } else if (s.token != SEMI) { + syntaxError("illegal start of class or module definition", true); + } + if (s.token != RBRACE && s.token != EOF) accept(SEMI); + } + return stats.toArray(); + } + + /** TemplateStatSeq ::= TemplateStat {`;' TemplateStat} + * TemplateStat ::= Import + * | Modifiers Def + * | Modifiers Dcl + * | Expr + * % | val this `:' Type + * | + */ + Tree[] templateStatSeq() { + TreeList stats = new TreeList(); + while (s.token != RBRACE && s.token != EOF) { + if (s.token == IMPORT) { + stats.append(importClause()); + } else if (isExprIntro()) { + stats.append(expr()); + } else if (isDefIntro() || isModifier()) { + stats.append(defOrDcl(modifiers())); + } else if (s.token != SEMI) { + syntaxError("illegal start of definition", true); + } + if (s.token != RBRACE) accept(SEMI); + } + return stats.toArray(); + } + + /** RefineStatSeq ::= RefineStat {`;' RefineStat} + * RefineStat ::= Dcl + * | type TypeDef {`,' TypeDef} + * | + */ + Tree[] refineStatSeq() { + TreeList stats = new TreeList(); + while (s.token != RBRACE && s.token != EOF) { + if (isDclIntro()) { + stats.append(defOrDcl(0)); + } else if (s.token != SEMI) { + syntaxError("illegal start of declaration", true); + } + if (s.token != RBRACE) accept(SEMI); + } + return stats.toArray(); + } + + /** BlockStatSeq ::= { BlockStat `;' } [Expr] + * BlockStat ::= Import + * | Def + * | LocalClassModifiers LocalTopDef + * | Expr + * | + */ + Tree[] blockStatSeq(TreeList stats) { + while ((s.token != RBRACE) && (s.token != EOF) && (s.token != CASE)) { + if (s.token == IMPORT) { + stats.append(importClause()); + accept(SEMI); + } else if (isExprIntro()) { + stats.append(expr()); + if (s.token != RBRACE && s.token != CASE) accept(SEMI); + } else if (isDefIntro()) { + stats.append(defOrDcl(0)); + accept(SEMI); + } else if (isLocalClassModifier()) { + stats.append(topDef(localClassModifiers())); + accept(SEMI); + } else if (s.token == SEMI) { + s.nextToken(); + } else { + syntaxError("illegal start of statement", true); + } + } + return stats.toArray(); + } + + + /** CompilationUnit = [package QualId `;'] TopStatSeq + */ + Tree[] compilationUnit() { + if (s.token == PACKAGE) { + int pos = s.skipToken(); + Tree pkg = qualId(); + if (s.token == SEMI) { + s.nextToken(); + return new Tree[]{ + make.PackageDef( + pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, topStatSeq()))}; + } else { + TreeList stats = new TreeList(); + accept(LBRACE); + stats.append( + make.PackageDef( + pos, pkg, make.Template(pos, Tree.EMPTY_ARRAY, topStatSeq()))); + accept(RBRACE); + stats.append(topStatSeq()); + return stats.toArray(); + } + } else { + return topStatSeq(); + } + } +} + diff --git a/sources/scalac/ast/parser/ParserPhase.java b/sources/scalac/ast/parser/ParserPhase.java new file mode 100644 index 0000000000..204fb2b925 --- /dev/null +++ b/sources/scalac/ast/parser/ParserPhase.java @@ -0,0 +1,63 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** +** $Id$ +\* */ + +package scalac.ast.parser; + +import java.io.*; +import scalac.*; + +public class ParserPhase extends PhaseDescriptor { + + public String name() { + return "parse"; + } + + public String description () { + return "parse source files"; + } + + public String taskDescription() { + return "parsed"; + } + + public Phase createPhase(Global global) { + return new ParserWorker(global, this); + } +} + +public class ParserWorker extends Phase { + + /** constructor + */ + public ParserWorker(Global global, PhaseDescriptor descr) { + super(global, descr); + } + + /** apply this phase to all compilation units + */ + public void apply() { + super.apply(); + int count = 0; + for (int i = 0; i < global.units.length; i++) { + if (global.units[i].body != null) count++; + } + Unit[] units = new Unit[count]; + for (int i = 0, j = 0; i < global.units.length; i++) { + if (global.units[i].body != null) units[j++] = global.units[i]; + } + global.units = units; + } + + /** apply this phase to the given compilation unit + */ + public void apply(Unit unit) { + global.start(); + unit.body = new Parser(unit).parse(); + global.stop("parsed " + unit.source); + } +} diff --git a/sources/scalac/ast/parser/Scanner.java b/sources/scalac/ast/parser/Scanner.java new file mode 100644 index 0000000000..0e4af3a09d --- /dev/null +++ b/sources/scalac/ast/parser/Scanner.java @@ -0,0 +1,793 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast.parser; + +import scalac.*; +import scalac.util.Name; +import scalac.util.Position; + +/** A scanner for the programming language Scala. + * + * @author Matthias Zenger, Martin Odersky + * @version 1.0 + */ +public class Scanner extends TokenData { + + /** layout & character constants + */ + public int tabinc = 8; + public final static byte LF = 0xA; + protected final static byte FF = 0xC; + protected final static byte CR = 0xD; + protected final static byte SU = Sourcefile.SU; + + /** the names of all tokens + */ + public Name[] tokenName = new Name[128]; + public int numToken = 0; + + /** keyword array; maps from name indices to tokens + */ + protected byte[] key; + protected int maxKey = 0; + + /** we need one token lookahead + */ + protected TokenData next = new TokenData(); + protected TokenData prev = new TokenData(); + + /** the first character position after the previous token + */ + public int lastpos = 0; + + /** the last error position + */ + public int errpos = -1; + + /** the input buffer: + */ + protected byte[] buf; + protected int bp; + + /** the current character + */ + protected byte ch; + + /** the line and column position of the current character + */ + public int cline; + public int ccol; + + /** the current sourcefile + */ + public Sourcefile currentSource; + + /** a buffer for character and string literals + */ + protected byte[] lit = new byte[64]; + protected int litlen; + + /** the compilation unit + */ + public Unit unit; + + + /** Construct a scanner from a file input stream. + */ + public Scanner(Unit unit) { + this.unit = unit; + buf = (currentSource = unit.source).getBuffer(); + cline = 1; + bp = -1; + ccol = 0; + nextch(); + token = EMPTY; + init(); + nextToken(); + } + + private void nextch() { + ch = buf[++bp]; ccol++; + } + + /** read next token and return last position + */ + public int skipToken() { + int p = pos; + nextToken(); + return p; + } + + public void nextToken() { + if (token == RBRACE) { + int prevpos = pos; + fetchToken(); + switch (token) { + case ELSE: case EXTENDS: case WITH: + case YIELD: case DO: + case COMMA: case SEMI: case DOT: + case COLON: case EQUALS: case ARROW: + case LARROW: case SUBTYPE: case AT: + case HASH: case AS: case IS: + case RPAREN: case RBRACKET: case RBRACE: + break; + default: + if (token == EOF || + ((pos >>> Position.LINESHIFT) > + (prevpos >>> Position.LINESHIFT))) { + next.copyFrom(this); + this.token = SEMI; + this.pos = prevpos; + } + } + } else { + if (next.token == EMPTY) { + fetchToken(); + } else { + copyFrom(next); + next.token = EMPTY; + } + if (token == CASE) { + prev.copyFrom(this); + fetchToken(); + if (token == CLASS) { + token = CASECLASS; + } else { + next.copyFrom(this); + this.copyFrom(prev); + } + } else if (token == SEMI) { + prev.copyFrom(this); + fetchToken(); + if (token != ELSE) { + next.copyFrom(this); + this.copyFrom(prev); + } + } + } + //System.out.println("<" + token2string(token) + ">");//DEBUG + } + + /** read next token + */ + public void fetchToken() { + if (token == EOF) return; + lastpos = Position.encode(cline, ccol, currentSource.id); + int index = bp; + while(true) { + switch (ch) { + case ' ': + nextch(); + break; + case '\t': + ccol = ((ccol - 1) / tabinc * tabinc) + tabinc; + nextch(); + break; + case CR: + cline++; + ccol = 0; + nextch(); + if (ch == LF) { + ccol = 0; + nextch(); + } + break; + case LF: + case FF: + cline++; + ccol = 0; + nextch(); + break; + default: + pos = Position.encode(cline, ccol, currentSource.id); + index = bp; + switch (ch) { + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': case '$': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + nextch(); + getIdentRest(index); + return; + case '~': case '!': case '@': case '#': case '%': + case '^': case '*': case '+': case '-': case '<': + case '>': case '?': case ':': + case '=': case '&': case '|': + nextch(); + getOperatorRest(index); + return; + case '/': + nextch(); + if (!skipComment()) { + getOperatorRest(index); + return; + } + break; + case '_': + nextch(); + getIdentOrOperatorRest(index); + return; + case '0': + nextch(); + if (ch == 'x' || ch == 'X') { + nextch(); + getNumber(index + 2, 16); + } else + getNumber(index, 8); + return; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + getNumber(index, 10); + return; + case '\"': + nextch(); + litlen = 0; + while (ch != '\"' && ch != CR && ch != LF && ch != SU) + getlitch(); + if (ch == '\"') { + token = STRINGLIT; + name = Name.fromSource(lit, 0, litlen); + nextch(); + } + else + syntaxError("unclosed character literal"); + return; + case '\'': + nextch(); + litlen = 0; + getlitch(); + if (ch == '\'') { + nextch(); + token = CHARLIT; + byte[] ascii = new byte[litlen * 2]; + int alen = SourceRepresentation.source2ascii(lit, 0, litlen, ascii); + if (alen > 0) + intVal = SourceRepresentation.ascii2string(ascii, 0, alen).charAt(0); + else + intVal = 0; + } else + syntaxError("unclosed character literal"); + return; + case '.': + nextch(); + if (('0' <= ch) && (ch <= '9')) getFraction(index); + else token = DOT; + return; + case ';': + nextch(); token = SEMI; + return; + case ',': + nextch(); token = COMMA; + return; + case '(': + nextch(); token = LPAREN; + return; + case '{': + nextch(); token = LBRACE; + return; + case ')': + nextch(); token = RPAREN; + return; + case '}': + nextch(); token = RBRACE; + return; + case '[': + nextch(); token = LBRACKET; + return; + case ']': + nextch(); token = RBRACKET; + return; + case SU: + token = EOF; + currentSource.lines = cline; + return; + default: + nextch(); + syntaxError("illegal character"); + return; + } + } + } + } + + private boolean skipComment() { + if (ch == '/') { + do { + nextch(); + } while ((ch != CR) && (ch != LF) && (ch != SU)); + return true; + } else if (ch == '*') { + int openComments = 1; + while (openComments > 0) { + do { + do { + if (ch == CR) { + cline++; + ccol = 0; + nextch(); + if (ch == LF) { + ccol = 0; + nextch(); + } + } else if (ch == LF) { + cline++; + ccol = 0; + nextch(); + } + else if (ch == '\t') { + ccol = ((ccol - 1) / tabinc * tabinc) + tabinc; + nextch(); + } else if (ch == '/') { + nextch(); + if (ch == '*') { + nextch(); + openComments++; + } + } else { + nextch(); + } + } while ((ch != '*') && (ch != SU)); + while (ch == '*') { + nextch(); + } + } while (ch != '/' && ch != SU); + if (ch == '/') { + nextch(); + openComments--; + } else { + syntaxError("unclosed comment"); + return true; + } + } + return true; + } else { + return false; + } + } + + private void getIdentRest(int index) { + while (true) { + switch (ch) { + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': case '$': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + nextch(); + break; + case '_': + nextch(); + getIdentOrOperatorRest(index); + return; + default: + treatIdent(index, bp); + return; + } + } + } + + private void getOperatorRest(int index) { + while (true) { + switch (ch) { + case '~': case '!': case '@': case '#': case '%': + case '^': case '*': case '+': case '-': case '<': + case '>': case '?': case ':': + case '=': case '&': case '|': + nextch(); + break; + case '/': + int lastbp = bp; + nextch(); + if (skipComment()) { + treatIdent(index, lastbp); + return; + } else { + break; + } + case '_': + nextch(); + getIdentOrOperatorRest(index); + return; + default: + treatIdent(index, bp); + return; + } + } + } + + private void getIdentOrOperatorRest(int index) { + switch (ch) { + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': case '$': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + getIdentRest(index); + return; + case '~': case '!': case '@': case '#': case '%': + case '^': case '*': case '+': case '-': case '<': + case '>': case '?': case ':': + case '=': case '&': case '|': + case '/': + getOperatorRest(index); + return; + case '_': + nextch(); + getIdentOrOperatorRest(index); + return; + default: + treatIdent(index, bp); + return; + } + } + + void treatIdent(int start, int end) { + name = Name.fromAscii(buf, start, end - start); + if (name.index <= maxKey) + token = key[name.index]; + else + token = IDENTIFIER; + } + + /** generate an error at the given position + */ + void syntaxError(int pos, String msg) { + unit.error(pos, msg); + token = ERROR; + errpos = pos; + } + + /** generate an error at the current token position + */ + void syntaxError(String msg) { + syntaxError(pos, msg); + } + + /** append characteter to "lit" buffer + */ + protected void putch(byte c) { + if (litlen == lit.length) { + byte[] newlit = new byte[lit.length * 2]; + System.arraycopy(lit, 0, newlit, 0, lit.length); + lit = newlit; + } + lit[litlen++] = c; + } + + /** return true iff next 6 characters are a valid unicode sequence: + */ + protected boolean isUnicode() { + return + (bp + 6) < buf.length && + (buf[bp] == '\\') && + (buf[bp+1] == 'u') && + (SourceRepresentation.digit2int(buf[bp+2], 16) >= 0) && + (SourceRepresentation.digit2int(buf[bp+3], 16) >= 0) && + (SourceRepresentation.digit2int(buf[bp+4], 16) >= 0) && + (SourceRepresentation.digit2int(buf[bp+5], 16) >= 0); + } + + /** read next character in character or string literal: + */ + protected void getlitch() { + if (ch == '\\') { + if (isUnicode()) { + putch(ch); nextch(); + putch(ch); nextch(); + putch(ch); nextch(); + putch(ch); nextch(); + putch(ch); nextch(); + putch(ch); nextch(); + } else { + nextch(); + if ('0' <= ch && ch <= '7') { + byte leadch = ch; + int oct = SourceRepresentation.digit2int(ch, 8); + nextch(); + if ('0' <= ch && ch <= '7') { + oct = oct * 8 + SourceRepresentation.digit2int(ch, 8); + nextch(); + if (leadch <= '3' && '0' <= ch && ch <= '7') { + oct = oct * 8 + SourceRepresentation.digit2int(ch, 8); + nextch(); + } + } + putch((byte)oct); + } else if (ch != SU) { + switch (ch) { + case 'b': case 't': case 'n': + case 'f': case 'r': case '\"': + case '\'': case '\\': + putch((byte)'\\'); + putch(ch); + break; + default: + syntaxError(Position.encode(cline, ccol, currentSource.id) - 1, "invalid escape character"); + putch(ch); + } + nextch(); + } + } + } else if (ch != SU) { + putch(ch); + nextch(); + } + } + + /** read fractional part of floating point number; + * Then floatVal := buf[index..], converted to a floating point number. + */ + protected void getFraction(int index) { + while (SourceRepresentation.digit2int(ch, 10) >= 0) { + nextch(); + } + token = DOUBLELIT; + if ((ch == 'e') || (ch == 'E')) { + nextch(); + if ((ch == '+') || (ch == '-')) { + byte sign = ch; + nextch(); + if (('0' > ch) || (ch > '9')) { + ch = sign; + bp--; + ccol--; + } + } + while (SourceRepresentation.digit2int(ch, 10) >= 0) { + nextch(); + } + } + double limit = Double.MAX_VALUE; + if ((ch == 'd') || (ch == 'D')) { + nextch(); + } else if ((ch == 'f') || (ch == 'F')) { + token = FLOATLIT; + limit = Float.MAX_VALUE; + nextch(); + } + try { + floatVal = Double.valueOf(new String(buf, index, bp - index)).doubleValue(); + if (floatVal > limit) + syntaxError("floating point number too large"); + } catch (NumberFormatException e) { + syntaxError("malformed floating point number"); + } + } + + /** intVal := buf[index..index+len-1], converted to an integer number. + * base = the base of the number; one of 8, 10, 16. + * max = the maximal number before an overflow. + */ + protected void makeInt (int index, int len, int base, long max) { + intVal = 0; + int divider = (base == 10 ? 1 : 2); + for (int i = 0; i < len; i++) { + int d = SourceRepresentation.digit2int(buf[index + i], base); + if (d < 0) { + syntaxError("malformed integer number"); + return; + } + if (intVal < 0 || + max / (base / divider) < intVal || + max - (d / divider) < (intVal * (base / divider) - 0)) { + syntaxError("integer number too large"); + return; + } + intVal = intVal * base + d; + } + } + + /** read a number, + * and convert buf[index..], setting either intVal or floatVal. + * base = the base of the number; one of 8, 10, 16. + */ + protected void getNumber(int index, int base) { + while (SourceRepresentation.digit2int(ch, base == 8 ? 10 : base) >= 0) { + nextch(); + } + if (base <= 10 && ch == '.') { + nextch(); + if ((ch >= '0') && (ch <= '9')) + getFraction(index); + else { + ch = buf[--bp]; ccol--; + makeInt(index, bp - index, base, Integer.MAX_VALUE); + intVal = (int)intVal; + token = INTLIT; + } + } else if (base <= 10 && + (ch == 'e' || ch == 'E' || + ch == 'f' || ch == 'F' || + ch == 'd' || ch == 'D')) + getFraction(index); + else { + if (ch == 'l' || ch == 'L') { + makeInt(index, bp - index, base, Long.MAX_VALUE); + nextch(); + token = LONGLIT; + } else { + makeInt(index, bp - index, base, Integer.MAX_VALUE); + intVal = (int)intVal; + token = INTLIT; + } + } + } + + public int name2token(Name name) { + if (name.index <= maxKey) + return key[name.index]; + else + return IDENTIFIER; + } + + public String token2string(int token) { + switch (token) { + case IDENTIFIER: + return "identifier"; + case CHARLIT: + return "character literal"; + case INTLIT: + return "integer literal"; + case LONGLIT: + return "long literal"; + case FLOATLIT: + return "float literal"; + case DOUBLELIT: + return "double literal"; + case STRINGLIT: + return "string literal"; + case LPAREN: + return "'('"; + case RPAREN: + return "')'"; + case LBRACE: + return "'{'"; + case RBRACE: + return "'}'"; + case LBRACKET: + return "'['"; + case RBRACKET: + return "']'"; + case EOF: + return "eof"; + case ERROR: + return "something"; + case SEMI: + return "';'"; + case COMMA: + return "','"; + default: + try { + return "'" + tokenName[token].toString() + "'"; + } catch (ArrayIndexOutOfBoundsException e) { + return "'<" + token + ">'"; + } + } + } + + public String toString() { + switch (token) { + case IDENTIFIER: + return "id(" + name + ")"; + case CHARLIT: + return "char(" + intVal + ")"; + case INTLIT: + return "int(" + intVal + ")"; + case LONGLIT: + return "long(" + intVal + ")"; + case FLOATLIT: + return "float(" + floatVal + ")"; + case DOUBLELIT: + return "double(" + floatVal + ")"; + case STRINGLIT: + return "string(" + name + ")"; + case SEMI: + return ";"; + case COMMA: + return ","; + default: + return token2string(token); + } + } + + protected void enterKeyword(String s, int tokenId) { + while (tokenId > tokenName.length) { + Name[] newTokName = new Name[tokenName.length * 2]; + System.arraycopy(tokenName, 0, newTokName, 0, newTokName.length); + tokenName = newTokName; + } + Name n = Name.fromString(s); + tokenName[tokenId] = n; + if (n.index > maxKey) + maxKey = n.index; + if (tokenId >= numToken) + numToken = tokenId + 1; + } + + protected void init() { + initKeywords(); + key = new byte[maxKey+1]; + for (int i = 0; i <= maxKey; i++) + key[i] = IDENTIFIER; + for (byte j = 0; j < numToken; j++) + if (tokenName[j] != null) + key[tokenName[j].index] = j; + } + + protected void initKeywords() { + enterKeyword("if", IF); + enterKeyword("for", FOR); + enterKeyword("else", ELSE); + enterKeyword("this", THIS); + enterKeyword("null", NULL); + enterKeyword("new", NEW); + enterKeyword("with", WITH); + enterKeyword("super", SUPER); + enterKeyword("case", CASE); + enterKeyword("val", VAL); + enterKeyword("abstract", ABSTRACT); + enterKeyword("final", FINAL); + enterKeyword("private", PRIVATE); + enterKeyword("protected", PROTECTED); + enterKeyword("qualified", QUALIFIED); + enterKeyword("override", OVERRIDE); + enterKeyword("var", VAR); + enterKeyword("def", DEF); + enterKeyword("type", TYPE); + enterKeyword("extends", EXTENDS); + enterKeyword("let", LET); + enterKeyword("module", MODULE); + enterKeyword("class",CLASS); + enterKeyword("constr",CONSTR); + enterKeyword("import", IMPORT); + enterKeyword("package", PACKAGE); + enterKeyword(".", DOT); + enterKeyword("_", USCORE); + enterKeyword(":", COLON); + enterKeyword("=", EQUALS); + enterKeyword("=>", ARROW); + enterKeyword("<-", LARROW); + enterKeyword("<:", SUBTYPE); + enterKeyword("yield", YIELD); + enterKeyword("do", DO); + enterKeyword("@", AT); + enterKeyword("#", HASH); + enterKeyword("trait", TRAIT); + enterKeyword("as", AS); + enterKeyword("is", IS); + } +} + + diff --git a/sources/scalac/ast/parser/SourceRepresentation.java b/sources/scalac/ast/parser/SourceRepresentation.java new file mode 100644 index 0000000000..2a20e13fab --- /dev/null +++ b/sources/scalac/ast/parser/SourceRepresentation.java @@ -0,0 +1,205 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id +\* */ + +package scalac.ast.parser; + +public final class SourceRepresentation { + + public static int digit2int(byte ch, int base) { + if ('0' <= ch && ch <= '9' && ch < '0' + base) + return ch - '0'; + else if ('A' <= ch && ch < 'A' + base - 10) + return ch - 'A' + 10; + else if ('a' <= ch && ch < 'a' + base - 10) + return ch - 'a' + 10; + else + return -1; + } + + public static byte int2digit(int x) { + if (x <= 9) + return (byte)(x + '0'); + else + return (byte)(x - 10 + 'A'); + } + +/* the next 4 functions convert between three fundamental name + * representations: + * - string each character 16 bit, + * - source characters outside 0..127 are represented by + * unicode escapes, \ u X X X X + * - ascii characters outside 0..127 are represented by two or three + * byte sequences with high bit set (as in class file format). + */ + +/** convert source bytes in source[offset..offset+len-1] to ascii. + */ + public static int source2ascii(byte source[], int offset, int len, byte ascii[]) { + int j = 0; + int i = 0; + while (i < len) { + if (source[offset + i] == '\\' && i + 1 < len) { + i++; + switch (source[offset + i]) { + case 'n': + ascii[j++] = (byte)'\n'; i++; continue; + case 't': + ascii[j++] = (byte)'\t'; i++; continue; + case 'b': + ascii[j++] = (byte)'\b'; i++; continue; + case 'r': + ascii[j++] = (byte)'\r'; i++; continue; + case 'f': + ascii[j++] = (byte)'\f'; i++; continue; + case 'u': + if (i + 4 < len) { + int code = 0; + int k = 1; + int d = 0; + while (k <= 4 && d >= 0) { + d = digit2int(source[offset + i + k], 16); + code = code * 16 + d; + k++; + } + if (d >= 0) { + if (code <= 0x7F) + ascii[j++] = (byte)code; + else + if (code <= 0x3FF) { + ascii[j++] = (byte)(0xC0 | (code >> 6)); + ascii[j++] = (byte)(0x80 | (code & 0x3F)); + } else { + ascii[j++] = (byte)(0xE0 | (code >> 12)); + ascii[j++] = (byte)(0x80 | + ((code >> 6) & 0x3F)); + ascii[j++] = (byte)(0x80 | (code & 0x3F)); + } + i = i + 5; + continue; + } + } + } + } + byte b = source[offset + i++]; + if (b >= 0) + ascii[j++] = b; + else { + ascii[j++] = (byte)(0xC0 | ((b >> 6) & 0x3)); + ascii[j++] = (byte)(0x80 | (b & 0x3F)); + } + } + return j; + } + +/** convert ascii bytes in ascii[offset..offset+len-1] to a string + */ + public static String ascii2string(byte ascii[], int offset, int len) { + char cs[] = new char[len]; + int i = offset; + int j = 0; + len += offset; + while (i < len) { + int b = ascii[i++] & 0xFF; + if (b >= 0xE0) { + b = ((b & 0x0F) << 12) | (ascii[i++] & 0x3F) << 6; + b = b | (ascii[i++] & 0x3F); + } + else + if (b >= 0xC0) + b = ((b & 0x1F) << 6) | (ascii[i++] & 0x3F); + cs[j++] = (char)b; + } + return new String(cs, 0, j); + } + +/** convert string to array of source bytes + */ + public static byte[] string2source(String s) { + byte[] source = new byte[s.length() * 6]; + int j = 0; + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + switch (ch) { + case '\n': + source[j++] = (byte)'\\'; + source[j++] = (byte)'n'; + break; + case '\t': + source[j++] = (byte)'\\'; + source[j++] = (byte)'t'; + break; + case '\b': + source[j++] = (byte)'\\'; + source[j++] = (byte)'b'; + break; + case '\r': + source[j++] = (byte)'\\'; + source[j++] = (byte)'r'; + break; + case '\f': + source[j++] = (byte)'\\'; + source[j++] = (byte)'f'; + break; + case '\"': + source[j++] = (byte)'\\'; + source[j++] = (byte)'\"'; + break; + case '\'': + source[j++] = (byte)'\\'; + source[j++] = (byte)'\''; + break; + case '\\': + source[j++] = (byte)'\\'; + source[j++] = (byte)'\\'; + break; + default: + if ((' ' <= ch) && (ch <= 127)) + source[j++] = (byte)ch; + else { + source[j++] = (byte)'\\'; + source[j++] = (byte)'u'; + source[j++] = int2digit((ch >> 12) & 0xF); + source[j++] = int2digit((ch >> 8) & 0xF); + source[j++] = int2digit((ch >> 4) & 0xF); + source[j++] = int2digit(ch & 0xF); + } + } + } + byte[] res = new byte[j]; + System.arraycopy(source, 0, res, 0, j); + return res; + } + +/** convert string to array of ascii bytes + */ + public static byte[] string2ascii(String s) { + byte[] source = string2source(s); + byte[] ascii = new byte[source.length * 2]; + int alen = source2ascii(source, 0, source.length, ascii); + byte[] res = new byte[alen]; + System.arraycopy(ascii, 0, res, 0, alen); + return res; + } + +/** escape all characters outside 32..127 in string s + */ + public static String escape(String s) { + try { + return new String(string2source(s), "8859_1"); + } catch (java.io.UnsupportedEncodingException e) { + throw new InternalError(e.getMessage()); + } + } + +/** escape character c, if outside 32..127. + */ + public static String escape(char c) { + char[] s = {c}; + return escape(new String(s)); + } +} diff --git a/sources/scalac/ast/parser/Sourcefile.java b/sources/scalac/ast/parser/Sourcefile.java new file mode 100644 index 0000000000..91277f9ac8 --- /dev/null +++ b/sources/scalac/ast/parser/Sourcefile.java @@ -0,0 +1,304 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast.parser; + +import java.io.*; +import java.util.Hashtable; +import scalac.util.AbstractFile; +import scalac.util.Name; +import scalac.util.Position; + + +/** This class represents a single scala source file. It provides + * functionality to read the file and to output error messages on + * a given line and column. Error messages are logged to + * decouple the time where an error message is issued from the + * time where the error messages are displayed. + * + * @author Matthias Zenger + * @version 1.0 + */ +public class Sourcefile { + + /** the id management + */ + public static int numIds = 1; + public static String[] files = new String[]{"console", null, null, null}; + public static Sourcefile[] sources = new Sourcefile[]{null, null, null, null}; + public int id; + + /** the filename + */ + public final boolean console; + protected String filename; + public String shortname; + public String pathname; + + /** the encoding of the file + */ + protected String encoding; + + /** a log of all errors generated so far; used to avoid printing an + * error message more than once + */ + protected Hashtable recorded = new Hashtable(); + + /** the buffer containing the file that is currently translated + */ + protected byte[] buf = null; + + /** the last error position + */ + protected int lastLine = 0; + protected int lastPos = 0; + protected int lineEnd = 0; + protected int newPos = 0; + + /** constants used for source parsing + */ + final static byte LF = 0xA; + final static byte FF = 0xC; + final static byte CR = 0xD; + final static byte SU = 0x1A; + + /** set col to NO_COLUMN, if the printLine method should not mark + * the column + */ + final static int NO_COLUMN = -1; + + /** number of lines and bytes (not used internally) + */ + public int lines; // set externally + public int bytes; + + /** prompt after error? + */ + public boolean prompt; + + /** constructors + */ + public Sourcefile(String filename, boolean console) throws IOException, FileNotFoundException { + this.console = console; + if (filename == null) { + this.filename = "(sourcefile not available)"; + this.shortname = "?"; + this.pathname = "?"; + buf = new byte[]{SU}; + } else { + File f = new File(filename); + this.filename = filename; + this.shortname = f.getName(); + this.pathname = f.getAbsoluteFile().getParentFile(). + getCanonicalPath(); + fillBuffer(new FileInputStream(f)); + } + if (numIds == files.length) { + String[] newfiles = new String[numIds * 2]; + System.arraycopy(files, 0, newfiles, 0, numIds); + files = newfiles; + Sourcefile[] newsources = new Sourcefile[numIds * 2]; + System.arraycopy(sources, 0, newsources, 0, numIds); + sources = newsources; + } + sources[numIds] = this; + files[id = numIds++] = shortname; + } + + public Sourcefile(AbstractFile abs) throws IOException, FileNotFoundException { + this.console = false; + if (filename == null) { + this.filename = "(sourcefile not available)"; + this.shortname = "?"; + this.pathname = "?"; + buf = new byte[]{SU}; + } else { + this.filename = abs.getPath(); + this.shortname = abs.getName(); + this.pathname = abs.getPath(); + fillBuffer(abs.getInputStream()); + } + if (numIds == files.length) { + String[] newfiles = new String[numIds * 2]; + System.arraycopy(files, 0, newfiles, 0, numIds); + files = newfiles; + Sourcefile[] newsources = new Sourcefile[numIds * 2]; + System.arraycopy(sources, 0, newsources, 0, numIds); + sources = newsources; + } + sources[numIds] = this; + files[id = numIds++] = shortname; + } + + public Sourcefile(byte[] input, boolean console) { + this.console = console; + if (input == null) { + this.filename = "(sourcefile not available)"; + this.shortname = "?"; + this.pathname = "?"; + buf = new byte[]{SU}; + } else { + this.filename = "console"; + this.shortname = "console"; + this.pathname = "console"; + buf = new byte[input.length + 2]; + System.arraycopy(input, 0, buf, 0, input.length); + buf[input.length] = Scanner.LF; + buf[input.length + 1] = SU; + } + sources[0] = this; + id = 0; + } + + /** fill the buffer using the InputStream + */ + private void fillBuffer(InputStream in) throws IOException { + try { + buf = new byte[(bytes = in.available()) + 1]; + if (in.read(buf) != (buf.length - 1)) + throw new IOException(); + in.close(); + buf[buf.length - 1] = SU; + } catch (IOException e) { + throw new IOException("cannot read '" + filename + "'"); + } + } + + /** return filename as a string + */ + public String toString() { + return filename; + } + + /** return filename as a name + */ + public Name getName() { + return Name.fromString(filename); + } + + /** return the shortname without the suffix + */ + public String getShortnameWithoutSuffix() { + int idx = shortname.lastIndexOf('.'); + if (idx < 0) + return shortname; + else + return shortname.substring(0, idx); + } + + /** return the source buffer of this file + */ + public byte[] getBuffer() { + return buf; + } + + /** number of logged entries + */ + public int logged() { + return recorded.size(); + } + + /** is there already an entry at position 'pos' + */ + public boolean isLogged(int pos) { + return (recorded.get(new Integer(pos)) != null); + } + + /** enter entry into log table + */ + public void log(int pos, String message) { + recorded.put(new Integer(pos), message); + } + + /** set encoding of the file + */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** return true if there is an entry for this position, + * otherwise return false and enter message into log + */ + public boolean testAndSetLog(int pos, String message) { + if (!isLogged(pos)) { + log(pos, message); + return false; + } + return true; + } + + /** get error message with line from sourcefile + */ + public String getMessage(int pos, String message) { + if (pos == Position.NOPOS) + return filename + ": " + message; + else { + int fileId = Position.file(pos); + String filename = files[fileId]; + int line = Position.line(pos); + int col = Position.column(pos); + String main = filename + ":" + line + ": " + message; + if ((fileId > 0) && + (fileId < numIds) && + (sources[fileId] != null)) + return main + '\n' + sources[fileId].getLine(line, col); + else + return main; + //else + // System.out.println("(source file not available anymore)"); + } + } + + /** get source line + */ + public String getLine(int line, int col) { + int pos = 0; + if (lastLine > line) + lastLine = 0; + else + pos = newPos; + while ((pos < buf.length) && (lastLine < line)) + { + lastPos = pos; + while ((pos < buf.length) && (buf[pos] != CR) && + (buf[pos] != LF) && (buf[pos] != FF)) + pos++; + lineEnd = pos; + if (pos < buf.length) + pos++; + if ((pos < buf.length) && (buf[pos-1] == CR) && (buf[pos] == LF)) + pos++; + lastLine++; + } + newPos = pos; + try + { + String errline = (encoding != null) ? + new String(buf, lastPos, lineEnd - lastPos, encoding) : + new String(buf, lastPos, lineEnd - lastPos); + if (col != NO_COLUMN) + { + byte[] ptr = new byte[col]; + for (int i = col - 2; i >= 0; i--) + ptr[i] = (byte)' '; + ptr[col - 1] = (byte)'^'; + return errline + '\n' + new String(ptr); + } else + return errline; + } catch (UnsupportedEncodingException e) { + throw new InternalError(e.getMessage()); + } + } + + /** release all sourcefile objects + */ + public static void flushSources() { + for (int i = 0; i < sources.length; i++) + sources[i] = null; + } +} diff --git a/sources/scalac/ast/parser/TokenData.java b/sources/scalac/ast/parser/TokenData.java new file mode 100644 index 0000000000..d6bcac6c1c --- /dev/null +++ b/sources/scalac/ast/parser/TokenData.java @@ -0,0 +1,44 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast.parser; + +import scalac.util.Name; + +/** A class for representing a token's data. + * + * @author Matthias Zenger + * @version 1.0 + */ +public class TokenData implements Tokens { + + /** the next token + */ + public int token = EMPTY; + + /** the token's position. pos = line << Position.LINESHIFT + col + */ + public int pos = 0; + + /** the name of an identifier or token + */ + public Name name; + + /** the value of a number + */ + public long intVal; + public double floatVal; + + public void copyFrom(TokenData td) { + this.token = td.token; + this.pos = td.pos; + this.name = td.name; + this.intVal = td.intVal; + this.floatVal = td.floatVal; + } +} diff --git a/sources/scalac/ast/parser/Tokens.java b/sources/scalac/ast/parser/Tokens.java new file mode 100644 index 0000000000..6c3bef6a55 --- /dev/null +++ b/sources/scalac/ast/parser/Tokens.java @@ -0,0 +1,84 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.ast.parser; + +public interface Tokens { + byte EMPTY = -3, + UNDEF = -2, + ERROR = -1, + EOF = 0, + + /* literals */ + CHARLIT = 1, + INTLIT = 2, + LONGLIT = 3, + FLOATLIT = 4, + DOUBLELIT = 5, + STRINGLIT = 6, + + /* identifier */ + IDENTIFIER = 10, + + /* keywords */ + IF = 20, + FOR = 21, + ELSE = 22, + THIS = 23, + NULL = 24, + NEW = 25, + WITH = 26, + SUPER = 27, + CASE = 28, + CASECLASS = 29, + VAL = 30, + ABSTRACT = 31, + FINAL = 32, + PRIVATE = 33, + PROTECTED = 34, + QUALIFIED = 35, + OVERRIDE = 36, + VAR = 37, + DEF = 38, + TYPE = 39, + EXTENDS = 40, + LET = 41, + MODULE = 43, + CLASS = 44, + CONSTR = 45, + IMPORT = 46, + PACKAGE = 47, + AS = 48, + IS = 49, + YIELD = 50, + DO = 51, + TRAIT = 52, + + /* special symbols */ + COMMA = 61, + SEMI = 62, + DOT = 63, + USCORE = 64, + COLON = 65, + EQUALS = 66, + LARROW = 57, + ARROW = 68, + SUBTYPE = 69, + AT = 70, + HASH = 71, + + /* parenthesis */ + LPAREN = 90, + RPAREN = 91, + LBRACKET = 92, + RBRACKET = 93, + LBRACE = 94, + RBRACE = 95; +} + + diff --git a/sources/scalac/ast/printer/HTMLTreePrinter.java b/sources/scalac/ast/printer/HTMLTreePrinter.java new file mode 100644 index 0000000000..8dbd34f2a0 --- /dev/null +++ b/sources/scalac/ast/printer/HTMLTreePrinter.java @@ -0,0 +1,173 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + +package scalac.ast.printer; + +import scalac.Unit; +import scalac.symtab.Symbol; + +import java.io.OutputStream; +import java.io.PrintWriter; +import java.lang.Math; +import java.util.HashMap; + +/** + * HTML pretty printer for Scala abstract syntax trees. + * + * @author Michel Schinz + * @version 1.0 + */ + +public class HTMLTreePrinter extends TextTreePrinter { + protected int outSectionLevel = 1; + protected boolean started = false; + + public HTMLTreePrinter(OutputStream stream) { + super(stream); + } + + public void begin() { + assert !started; + + super.begin(); + out.println(""); + out.println(""); + out.println(""); + out.println(""); + out.println(""); + out.println("Scala tree"); + out.println(""); + out.println(""); + + started = true; + } + + public void end() { + assert started; + + out.println(""); + out.println(""); + super.end(); + + started = false; + } + + public void beginSection(int level, String title) { + outSectionLevel = Math.min(level, 4); + beginSection1(outSectionLevel, title); + } + + protected void beginSection1(int level, String title) { + if (level == 1) + out.println("
"); + String tag = "h" + level; + startTag(tag); + print(Text.Simple(title)); + endTag(tag); + } + + protected void startTag(String tag) { + out.print('<'); out.print(tag); out.print('>'); + } + + protected void startTag(String tag, String attr1, String val1) { + out.print('<'); + out.print(tag); + out.print(' '); + out.print(attr1); + out.print("=\""); + out.print(val1); + out.print("\">"); + } + + protected void endTag(String tag) { + out.print(""); + } + + protected void startSpan(String cls) { + startTag("span", "class", cls); + } + + protected void endSpan() { + endTag("span"); + } + + protected void printString(String str) { + StringBuffer buf = null; + int strLen = str.length(); + + for (int i = 0; i < strLen; ++i) { + String entity; + char c = str.charAt(i); + switch (c) { + case '<': entity = "lt"; break; + case '>': entity = "gt"; break; + case '&': entity = "amp"; break; + default: entity = null; break; + } + if (entity != null) { + out.print('&'); + out.print(entity); + out.print(';'); + } else + out.print(c); + } + } + + protected static HashMap/**/ symAnchors = new HashMap(); + protected String symbolAnchor(Symbol sym, SymbolUsage usage) { + Integer anchorId = (Integer)symAnchors.get(sym); + if (anchorId == null) { + anchorId = new Integer(symAnchors.size()); + symAnchors.put(sym, anchorId); + } + if (usage == SymbolUsage.Definition) + return anchorId.toString(); + else + return "#" + anchorId.toString(); + } + + protected void print(Text text) { + switch (text) { + case Keyword(String name): + startSpan("kw"); + printString(name); + endSpan(); + break; + case Literal(String str): + startSpan("lit"); + printString(str); + endSpan(); + break; + case Identifier(Symbol symbol, String name, SymbolUsage usage): + boolean defined = (usage == SymbolUsage.Definition); + if (defined) startSpan("idDef"); + if (symbol != null) { + String attr = (defined ? "name" : "href"); + startTag("a", attr, symbolAnchor(symbol, usage)); + } + printString(name); + if (symbol != null) + endTag("a"); + if (defined) endSpan(); + break; + default: + super.print(text); + } + } + + protected void printUnitHeader(Unit unit) { + beginSection1(outSectionLevel + 1, unit.source.toString()); + startTag("pre"); + } + + protected void printUnitFooter(Unit unit) { + endTag("pre"); + } +} diff --git a/sources/scalac/ast/printer/TextTreePrinter.java b/sources/scalac/ast/printer/TextTreePrinter.java new file mode 100644 index 0000000000..c5138d025f --- /dev/null +++ b/sources/scalac/ast/printer/TextTreePrinter.java @@ -0,0 +1,683 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +\* */ + +// $Id$ + +package scalac.ast.printer; + +import scalac.ast.*; +import scalac.symtab.*; +import scalac.util.Debug; +import scalac.Global; +import scalac.Unit; +import scalac.util.Name; + +import java.io.*; +import java.util.*; + +/** + * Text pretty printer for Scala abstract syntax trees. + * + * @author Michel Schinz, Matthias Zenger + * @version 1.0 + */ +public class TextTreePrinter implements TreePrinter { + protected PrintWriter out; + + protected int indent = 0; + protected final int INDENT_STEP = 2; + protected final String INDENT_STRING = + " "; + protected final int MAX_INDENT = INDENT_STRING.length(); + + public TextTreePrinter(OutputStream stream) { + out = new PrintWriter(stream); + } + + public TextTreePrinter() { + this(System.out); + } + + public void begin() { } + + public void end() { + out.flush(); + } + + public void flush() { + out.flush(); + } + + public TreePrinter print(String str) { + out.print(str); + return this; + } + + public TreePrinter println() { + out.println(); + return this; + } + + public void beginSection(int level, String title) { + out.println("[[" + title + "]]"); + out.flush(); + } + + protected void indent() { + indent += Math.min(MAX_INDENT, INDENT_STEP); + } + + protected void undent() { + indent -= Math.max(0, INDENT_STEP); + } + + protected void printString(String str) { + out.print(str); + } + + protected void printNewLine() { + out.println(); + if (indent > 0) + out.write(INDENT_STRING, 0, indent); + } + + public static class SymbolUsage { + public case Definition; + public case Use; + } + + public static class Text { + public case None; + public case Space; + public case Newline; + public case Simple(String str); + public case Literal(String str); + public case Keyword(String name); + public case Identifier(Symbol symbol, String name, SymbolUsage usage); + public case Sequence(Text[] elements); + } + + protected void print(Text text) { + switch (text) { + case None : break; + case Space : printString(" "); break; + case Newline : printNewLine(); break; + case Simple(String str) : printString(str); break; + case Literal(String str) : printString(str); break; + case Keyword(String name) : printString(name); break; + case Identifier(Symbol sym, String name, _) : + printString(name); + if (sym != null && Global.instance.uniqid) + printString("#" + Global.instance.uniqueID.id(sym)); + break; + case Sequence(Text[] elements) : print(elements); break; + } + } + + protected void print(Text[] texts) { + for (int i = 0; i < texts.length; ++i) + print(texts[i]); + } + + protected static final Text KW_ABSTRACT = Text.Keyword("abstract"); + protected static final Text KW_CASE = Text.Keyword("case"); + protected static final Text KW_CLASS = Text.Keyword("class"); + protected static final Text KW_CONSTR = Text.Keyword("constr"); + protected static final Text KW_DEF = Text.Keyword("def"); + protected static final Text KW_DO = Text.Keyword("do"); + protected static final Text KW_ELSE = Text.Keyword("else"); + protected static final Text KW_EXTENDS = Text.Keyword("extends"); + protected static final Text KW_FINAL = Text.Keyword("final"); + protected static final Text KW_FOR = Text.Keyword("for"); + protected static final Text KW_IF = Text.Keyword("if"); + protected static final Text KW_IMPORT = Text.Keyword("import"); + protected static final Text KW_INTERFACE = Text.Keyword("interface"); + protected static final Text KW_LET = Text.Keyword("let"); + protected static final Text KW_MODULE = Text.Keyword("module"); + protected static final Text KW_NEW = Text.Keyword("new"); + protected static final Text KW_NULL = Text.Keyword("null"); + protected static final Text KW_OUTER = Text.Keyword("outer"); + protected static final Text KW_OVERRIDE = Text.Keyword("override"); + protected static final Text KW_PACKAGE = Text.Keyword("package"); + protected static final Text KW_PRIVATE = Text.Keyword("private"); + protected static final Text KW_PROTECTED = Text.Keyword("protected"); + protected static final Text KW_QUALIFIED = Text.Keyword("qualified"); + protected static final Text KW_STATIC = Text.Keyword("static"); + protected static final Text KW_SUPER = Text.Keyword("super"); + protected static final Text KW_THIS = Text.Keyword("this"); + protected static final Text KW_TYPE = Text.Keyword("type"); + protected static final Text KW_VAL = Text.Keyword("val"); + protected static final Text KW_VAR = Text.Keyword("var"); + protected static final Text KW_WITH = Text.Keyword("with"); + protected static final Text KW_YIELD = Text.Keyword("yield"); + + protected static final Text TXT_ERROR = Text.Simple(""); + protected static final Text TXT_UNKNOWN = Text.Simple(""); + protected static final Text TXT_NULL = Text.Simple(""); + protected static final Text TXT_MODULE_COMMENT + = Text.Simple("/*module*/ "); + protected static final Text TXT_EMPTY = Text.Simple(""); + + protected static final Text TXT_QUOTE = Text.Simple("\""); + protected static final Text TXT_PLUS = Text.Simple("+"); + protected static final Text TXT_COLON = Text.Simple(":"); + protected static final Text TXT_SEMICOLON = Text.Simple(";"); + protected static final Text TXT_DOT = Text.Simple("."); + protected static final Text TXT_COMMA = Text.Simple(","); + protected static final Text TXT_EQUAL = Text.Simple("="); + protected static final Text TXT_SUBTYPE = Text.Simple("<:"); + protected static final Text TXT_AT = Text.Simple("@"); + protected static final Text TXT_HASH = Text.Simple("#"); + protected static final Text TXT_RIGHT_ARROW = Text.Simple("=>"); + protected static final Text TXT_LEFT_PAREN = Text.Simple("("); + protected static final Text TXT_RIGHT_PAREN = Text.Simple(")"); + protected static final Text TXT_LEFT_BRACE = Text.Simple("{"); + protected static final Text TXT_RIGHT_BRACE = Text.Simple("}"); + protected static final Text TXT_LEFT_BRACKET = Text.Simple("["); + protected static final Text TXT_RIGHT_BRACKET = Text.Simple("]"); + + protected static final Text TXT_WITH_BLOCK_BEGIN = + Text.Sequence(new Text[] { + Text.Space, KW_WITH, Text.Space, TXT_LEFT_BRACE, Text.Newline + }); + protected static final Text TXT_WITH_SP = + Text.Sequence(new Text[]{ Text.Space, KW_WITH, Text.Space }); + protected static final Text TXT_BLOCK_BEGIN = + Text.Sequence(new Text[]{ TXT_LEFT_BRACE, Text.Newline }); + protected static final Text TXT_BLOCK_END = + Text.Sequence(new Text[]{ Text.Newline, TXT_RIGHT_BRACE }); + protected static final Text TXT_BLOCK_SEP = + Text.Sequence(new Text[]{ TXT_SEMICOLON, Text.Newline }); + protected static final Text TXT_COMMA_SP = + Text.Sequence(new Text[]{ TXT_COMMA, Text.Space }); + protected static final Text TXT_ELSE_NL = + Text.Sequence(new Text[]{ KW_ELSE, Text.Newline }); + + public void print(Unit unit) { + printUnitHeader(unit); + if (unit.body != null) { + for (int i = 0; i < unit.body.length; ++i) { + print(unit.body[i]); + print(TXT_BLOCK_SEP); + } + } else + print(TXT_NULL); + printUnitFooter(unit); + + out.flush(); + } + + protected void printUnitHeader(Unit unit) { + print(Text.Simple("// Scala source: " + unit.source + "\n")); + } + + protected void printUnitFooter(Unit unit) { + print(Text.Newline); + } + + public TreePrinter print(Tree tree) { + switch (tree) { + case Bad(): + print(TXT_ERROR); + break; + + case Empty: + print(TXT_EMPTY); + break; + + case ClassDef(int mods, // : + Name name, + Tree.TypeDef[] tparams, + Tree.ValDef[][] vparams, + Tree tpe, + Tree.Template impl): + printModifiers(mods); + print((mods & Modifiers.INTERFACE) != 0 + ? KW_INTERFACE + : KW_CLASS); + print(Text.Space); + printSymbolDefinition(tree.symbol(), name); + printParams(tparams); + printParams(vparams); + printOpt(TXT_COLON, tpe, false); + printTemplate(KW_EXTENDS, impl, true); + break; + + case PackageDef(Tree packaged, Tree.Template impl): + print(KW_PACKAGE); + print(Text.Space); + print(packaged); + print(Text.Space); + printTemplate(KW_WITH, impl, true); + break; + + case ModuleDef(int mods, // : + Name name, + Tree tpe, + Tree.Template impl): + printModifiers(mods); + print(KW_MODULE); + print(Text.Space); + printSymbolDefinition(tree.symbol(), name); + printOpt(TXT_COLON, tpe, false); + printTemplate(KW_EXTENDS, impl, true); + break; + + case ValDef(int mods, Name name, Tree tpe, Tree rhs): + printModifiers(mods); + if ((mods & Modifiers.MUTABLE) != 0) print(KW_VAR); + else { + if ((mods & Modifiers.MODUL) != 0) print(TXT_MODULE_COMMENT); + print(KW_VAL); + } + print(Text.Space); + printSymbolDefinition(tree.symbol(), name); + printOpt(TXT_COLON, tpe, false); + printOpt(TXT_EQUAL, rhs, true); + break; + + case PatDef(int mods, Tree pat, Tree rhs): + printModifiers(mods); + print(KW_VAL); + print(Text.Space); + print(pat); + printOpt(TXT_EQUAL, rhs, true); + break; + + case DefDef(int mods, + Name name, + Tree.TypeDef[] tparams, + Tree.ValDef[][] vparams, + Tree tpe, + Tree rhs): + printModifiers(mods); + if (name.isConstrName()) print(KW_CONSTR); else print(KW_DEF); + print(Text.Space); + printSymbolDefinition(tree.symbol(), name); + printParams(tparams); + printParams(vparams); + printOpt(TXT_COLON, tpe, false); + printOpt(TXT_EQUAL, rhs, true); + break; + + case TypeDef(int mods, + Name name, + Tree.TypeDef[] tparams, + Tree rhs): + printModifiers(mods); + print(KW_TYPE); + print(Text.Space); + printSymbolDefinition(tree.symbol(), name); + printParams(tparams); + if ((mods & Modifiers.ABSTRACT) != 0) printOpt(TXT_SUBTYPE, rhs, true); + else printOpt(TXT_EQUAL, rhs, true); + break; + + case Import(Tree expr, Name[] selectors): + print(KW_IMPORT); + print(Text.Space); + print(expr); + print(TXT_LEFT_BRACE); + for (int i = 0; i < selectors.length; i = i + 2) { + if (i > 0) print(TXT_COMMA_SP); + print(selectors[i].toString()); + if (i + 1 < selectors.length && selectors[i] != selectors[i+1]) { + print(TXT_RIGHT_ARROW); + print(selectors[i+1].toString()); + } + } + print(TXT_RIGHT_BRACE); + break; + + case CaseDef(Tree pat, Tree guard, Tree body): + print(KW_CASE); + print(Text.Space); + print(pat); + printOpt(KW_IF, guard, true); + print(Text.Space); + print(TXT_RIGHT_ARROW); + print(Text.Space); + print(body); + break; + + case LabelDef(Tree[] params, Tree rhs): + assert tree.symbol() != null; + printSymbolDefinition(tree.symbol(), null); + printArray(params, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP); + print(rhs); + break; + + case Block(Tree[] stats): + printArray(stats, TXT_BLOCK_BEGIN, TXT_BLOCK_END, TXT_BLOCK_SEP); + break; + + case Tuple(Tree[] trees): + printArray(trees, TXT_LEFT_BRACKET, TXT_RIGHT_BRACKET, TXT_COMMA_SP); + break; + + case Visitor(Tree.CaseDef[] cases): + printArray(cases, TXT_BLOCK_BEGIN, TXT_BLOCK_END, Text.Newline); + break; + + case Function(Tree.ValDef[] vparams, Tree body): + print(TXT_LEFT_BRACE); + printParams(vparams); + print(Text.Space); + print(TXT_RIGHT_ARROW); + print(Text.Space); + print(body); + print(TXT_RIGHT_BRACE); + break; + + case Assign(Tree lhs, Tree rhs): + print(lhs); + print(Text.Space); + print(TXT_EQUAL); + print(Text.Space); + print(rhs); + break; + + case If(Tree cond, Tree thenp, Tree elsep): + print(KW_IF); + print(Text.Space); + print(TXT_LEFT_PAREN); + print(cond); + print(TXT_RIGHT_PAREN); + indent(); print(Text.Newline); + print(thenp); + undent(); print(Text.Newline); + indent(); printOpt(TXT_ELSE_NL, elsep, false); undent(); + printType(tree); + break; + + case New(Tree.Template templ): + printTemplate(KW_NEW, templ, false); + printType(tree); + break; + + case Typed(Tree expr, Tree tpe): + print(TXT_LEFT_PAREN); + print(expr); + print(TXT_RIGHT_PAREN); + print(Text.Space); + print(TXT_COLON); + print(Text.Space); + print(tpe); + printType(tree); + break; + + case TypeApply(Tree fun, Tree[] targs): + print(fun); + print(TXT_AT); + printArray(targs, TXT_LEFT_BRACKET, TXT_RIGHT_BRACKET, TXT_COMMA_SP); + printType(tree); + break; + + case Apply(Tree fun, Tree[] vargs): + print(fun); + printArray(vargs, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP); + printType(tree); + break; + + case Super(Tree tpe): + if (tpe != Tree.Empty) + print(TXT_LEFT_PAREN); + + print(KW_SUPER); + + if (tpe != Tree.Empty) { + print(Text.Space); + print(TXT_COLON); + print(Text.Space); + print(tpe); + print(TXT_RIGHT_PAREN); + } + printType(tree); + break; + + case This(Tree qualifier): + if (qualifier != Tree.Empty) { + print(qualifier); + print(TXT_DOT); + } + print(KW_THIS); + printType(tree); + break; + + case Select(Tree qualifier, Name name): + print(qualifier); + print(TXT_DOT); + printSymbolUse(tree.symbol(), name); + printType(tree); + break; + + case Ident(Name name): + printSymbolUse(tree.symbol(), name); + printType(tree); + break; + + case Literal(Object obj): + String str; + if (obj instanceof String) + str = "\"" + obj + "\""; + else + str = String.valueOf(obj); + print(Text.Literal(str)); + printType(tree); + break; + + case SingletonType(Tree ref): + print(ref); + print(TXT_DOT); print(KW_TYPE); + break; + + case SelectFromType(Tree qualifier, Name selector): + print(qualifier); + print(Text.Space); print(TXT_HASH); print(Text.Space); + printSymbolUse(tree.symbol(), selector); + break; + + case FunType(Tree[] argtpes, Tree restpe): + printArray(argtpes, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP); + print(TXT_RIGHT_ARROW); + print(restpe); + break; + + case CompoundType(Tree[] baseTypes, Tree[] refinements): + printArray(baseTypes, Text.None, Text.None, TXT_WITH_SP); + printArray(refinements, TXT_WITH_BLOCK_BEGIN, TXT_BLOCK_END, Text.Newline); + break; + + case TupleType(Tree[] types): + printArray(types, TXT_LEFT_BRACKET, TXT_RIGHT_BRACKET, TXT_COMMA_SP); + break; + + case AppliedType(Tree tpe, Tree[] args): + print(tpe); + indent(); + print(TXT_LEFT_BRACKET); + for (int i = 0; i < args.length; ++i) { + if (i > 0) print(TXT_COMMA_SP); + print(args[i]); + } + undent(); + print(TXT_RIGHT_BRACKET); + break; + + case CovariantType(Tree tpe): + print(TXT_PLUS); + print(tpe); + break; + + case Template(Tree[] parents, Tree[] body): + Debug.abort("unexpected case", tree); + break; + + default: + print(TXT_UNKNOWN); + break; + } + return this; + } + + // Printing helpers + + protected void printArray(Tree[] trees, Text open, Text close, Text sep) { + indent(); + print(open); + for (int i = 0; i < trees.length; ++i) { + if (i > 0) print(sep); + print(trees[i]); + } + undent(); + print(close); + } + + protected void printOpt(Text prefix, Tree tree, boolean spaceBefore) { + if (tree != Tree.Empty) { + if (spaceBefore) + print(Text.Space); + print(prefix); + print(Text.Space); + print(tree); + } + } + + // Printing of symbols + + protected String symbolString(Symbol symbol, Name name) { + if (symbol != null) + return symbol.name.toString(); + else + return name.toString(); + } + + protected void printSymbolDefinition(Symbol symbol, Name name) { + print(Text.Identifier(symbol, + symbolString(symbol, name), + SymbolUsage.Definition)); + } + + protected void printSymbolUse(Symbol symbol, Name name) { + print(Text.Identifier(symbol, + symbolString(symbol, name), + SymbolUsage.Use)); + } + + // Printing of trees + + protected void printType(Tree tree) { + if (Global.instance.printtypes) { + print(TXT_LEFT_BRACE); + if (tree.type != null) + print(Text.Simple(tree.type.toString())); + else + print(TXT_NULL); + print(TXT_RIGHT_BRACE); + } + } + + protected void printModifiers(int flags) { + if ((flags & Modifiers.ABSTRACT) != 0) { + print(KW_ABSTRACT); + print(Text.Space); + } + if ((flags & Modifiers.FINAL) != 0) { + print(KW_FINAL); + print(Text.Space); + } + if ((flags & Modifiers.PRIVATE) != 0) { + print(KW_PRIVATE); + print(Text.Space); + } + if ((flags & Modifiers.PROTECTED) != 0) { + print(KW_PROTECTED); + print(Text.Space); + } + if ((flags & Modifiers.QUALIFIED) != 0) { + print(KW_QUALIFIED); + print(Text.Space); + } + if ((flags & Modifiers.OVERRIDE) != 0) { + print(KW_OVERRIDE); + print(Text.Space); + } + if ((flags & Modifiers.CASE) != 0) { + print(KW_CASE); + print(Text.Space); + } + if ((flags & Modifiers.DEF) != 0) { + print(KW_DEF); + print(Text.Space); + } + if ((flags & Modifiers.STATIC) != 0) { + print(KW_STATIC); + print(Text.Space); + } + } + + protected void printTemplate(Text prefix, + Tree.Template templ, + boolean spaceBefore) { + if (! (templ.parents.length == 0 + || (templ.parents.length == 1 + && templ.parents[0] == Tree.Empty))) { + if (spaceBefore) + print(Text.Space); + print(prefix); + print(Text.Space); + printArray(templ.parents, Text.None, Text.None, TXT_WITH_SP); + } + + if (templ.body.length > 0) + printArray(templ.body, TXT_WITH_BLOCK_BEGIN, TXT_BLOCK_END, TXT_BLOCK_SEP); + } + + protected void printParams(Tree.TypeDef[] tparams) { + if (tparams.length > 0) { + print(TXT_LEFT_BRACKET); + for (int i = 0; i < tparams.length; i++) { + if (i > 0) print(TXT_COMMA_SP); + printParam(tparams[i]); + } + print(TXT_RIGHT_BRACKET); + } + } + + protected void printParams(Tree.ValDef[][] vparamss) { + for (int i = 0; i < vparamss.length; ++i) + printParams(vparamss[i]); + } + + protected void printParams(Tree.ValDef[] vparams) { + print(TXT_LEFT_PAREN); + for (int i = 0; i < vparams.length; ++i) { + if (i > 0) print(TXT_COMMA_SP); + printParam(vparams[i]); + } + print(TXT_RIGHT_PAREN); + } + + protected void printParam(Tree tree) { + switch (tree) { + case TypeDef(int mods, Name name, _, Tree bound): + printModifiers(mods); + printSymbolDefinition(tree.symbol(), name); + printOpt(KW_EXTENDS, bound, true); + break; + + case ValDef(int mods, Name name, Tree tpe, Tree.Empty): + printModifiers(mods); + printSymbolDefinition(tree.symbol(), name); + printOpt(TXT_COLON, tpe, false); + break; + + default: + Debug.abort("bad parameter: " + tree); + } + } +} diff --git a/sources/scalac/ast/printer/TreePrinter.java b/sources/scalac/ast/printer/TreePrinter.java new file mode 100644 index 0000000000..059b335c72 --- /dev/null +++ b/sources/scalac/ast/printer/TreePrinter.java @@ -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(); +} diff --git a/sources/scalac/checkers/CheckOwners.java b/sources/scalac/checkers/CheckOwners.java new file mode 100644 index 0000000000..f23bcb4d7e --- /dev/null +++ b/sources/scalac/checkers/CheckOwners.java @@ -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 + } + } +} diff --git a/sources/scalac/checkers/CheckSymbols.java b/sources/scalac/checkers/CheckSymbols.java new file mode 100644 index 0000000000..ab1a76ae2d --- /dev/null +++ b/sources/scalac/checkers/CheckSymbols.java @@ -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"); + } +} diff --git a/sources/scalac/checkers/CheckTypes.java b/sources/scalac/checkers/CheckTypes.java new file mode 100644 index 0000000000..cfe2bd656d --- /dev/null +++ b/sources/scalac/checkers/CheckTypes.java @@ -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"); + } +} diff --git a/sources/scalac/checkers/Checker.java b/sources/scalac/checkers/Checker.java new file mode 100644 index 0000000000..ae52a5b1f6 --- /dev/null +++ b/sources/scalac/checkers/Checker.java @@ -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); + } +} diff --git a/sources/scalac/symtab/Definitions.java b/sources/scalac/symtab/Definitions.java new file mode 100644 index 0000000000..6d67edac42 --- /dev/null +++ b/sources/scalac/symtab/Definitions.java @@ -0,0 +1,421 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** ** +** $Id$ +\* */ + +package scalac.symtab; + +import scalac.*; +import scalac.util.*; +import scalac.symtab.classfile.*; +import Type.*; + +public class Definitions { + + /** the root module + */ + public final Symbol ROOT; + public final Symbol ROOT_CLASS; + public final Type ROOT_TYPE; + + /** the scala module + */ + public final Symbol SCALA; + public final Symbol SCALA_CLASS; + public final Type SCALA_TYPE; + + /** the java module + */ + public final Symbol JAVA; + public final Symbol JAVA_CLASS; + public final Type JAVA_TYPE; + + /** the java.lang module + */ + public final Symbol JAVALANG; + public final Symbol JAVALANG_CLASS; + public final Type JAVALANG_TYPE; + + /** the scala.runtime module + */ + public final Symbol SCALARUNTIME; + public final Symbol SCALARUNTIME_CLASS; + public final Type SCALARUNTIME_TYPE; + + /** the null value + */ + public final Symbol NULL; + + /** the scala.Any class + */ + public final Symbol ANY_CLASS; + public final Type ANY_TYPE; + + /** some methods of the scala.Any class + */ + public final Symbol MATCH; + public final Symbol IS; + public final Symbol AS; + public final Symbol EQEQ; + public final Symbol BANGEQ; + public final Symbol TOSTRING; + public final Symbol HASHCODE; + + /** a method of class java.lang.Throwable + */ + public final Symbol THROW; + + /** the scala.AnyVal class + */ + public final Symbol ANYVAL_CLASS; + public final Type ANYVAL_TYPE; + + /** the scala.AnyRef class + */ + public final Symbol ANYREF_CLASS; + public final Type ANYREF_TYPE; + + /** the java.lang.Object class + */ + public final Symbol JAVA_OBJECT_CLASS; + public final Type JAVA_OBJECT_TYPE; + + /** the scala.Object class + */ + public final Symbol OBJECT_CLASS; + public final Type OBJECT_TYPE; + + /** the primitive types + */ + public final Symbol BYTE_CLASS; + public final Type BYTE_TYPE; + public final Symbol SHORT_CLASS; + public final Type SHORT_TYPE; + public final Symbol CHAR_CLASS; + public final Type CHAR_TYPE; + public final Symbol INT_CLASS; + public final Type INT_TYPE; + public final Symbol LONG_CLASS; + public final Type LONG_TYPE; + public final Symbol FLOAT_CLASS; + public final Type FLOAT_TYPE; + public final Symbol DOUBLE_CLASS; + public final Type DOUBLE_TYPE; + public final Symbol BOOLEAN_CLASS; + public final Type BOOLEAN_TYPE; + public final Symbol UNIT_CLASS; + public final Type UNIT_TYPE; + + /** the array class + */ + public final Symbol ARRAY_CLASS; + + /** types from java.lang + */ + public final Symbol JAVA_STRING_CLASS; + public final Type JAVA_STRING_TYPE; + public final Symbol JAVA_THROWABLE_CLASS; + public final Type JAVA_THROWABLE_TYPE; + + /** types from scala + */ + public final Symbol STRING_CLASS; + public final Type STRING_TYPE; + + /** string concatenation pseudo-methods of classes scala.Any and + * java.lang.String + */ + //public final Symbol ANY_PLUS_STRING; + public final Symbol STRING_PLUS_ANY; + + /** members of class Boolean + */ + private Symbol TRUE; + private Symbol FALSE; + private Symbol BARBAR; + private Symbol AMPAMP; + + public Symbol TRUE () { loadBooleanMembers(); return TRUE ; } + public Symbol FALSE () { loadBooleanMembers(); return FALSE ; } + public Symbol BARBAR() { loadBooleanMembers(); return BARBAR; } + public Symbol AMPAMP() { loadBooleanMembers(); return AMPAMP; } + + public Definitions(Global global) { + // a hack to make definitions accessible earlier to other + // components + global.definitions = this; + PackageParser pparser = new PackageParser(global); + + // this is the root value; all top-level functions, + // modules etc. are a member of this value + ROOT = TermSymbol.newJavaPackageModule( + Names.EMPTY, Symbol.NONE, pparser); + ROOT_CLASS = ROOT.moduleClass(); + // this is a prefix for all types inside of the anonymous package + ROOT_TYPE = ROOT_CLASS.thisType(); + + // the scala module + SCALA = getModule(Names.scala); + // the scala class + SCALA_CLASS = SCALA.moduleClass(); + // the scala package as a prefix + SCALA_TYPE = Type.singleType(ROOT_TYPE, SCALA); + + // the java module + JAVA = getModule(Names.java); + // the java class + JAVA_CLASS = JAVA.moduleClass(); + // the java package as a prefix + JAVA_TYPE = Type.singleType(ROOT_TYPE, JAVA); + + // the java.lang module + JAVALANG = getModule(Names.java_lang); + // the java.lang class + JAVALANG_CLASS = JAVALANG.moduleClass(); + // the java.lang package as a prefix + JAVALANG_TYPE = Type.singleType(JAVA_TYPE, JAVALANG); + + // the scala.runtime module + SCALARUNTIME = getModule(Names.scala_runtime); + // the scala.runtime class + SCALARUNTIME_CLASS = SCALARUNTIME.moduleClass(); + // the scala.runtime package as a prefix + SCALARUNTIME_TYPE = Type.singleType(SCALA_TYPE, SCALARUNTIME); + + // the scala.ANY classs + ANY_CLASS = new ClassSymbol( + Position.NOPOS, Names.Any.toTypeName(), SCALA_CLASS, Modifiers.JAVA); + SCALA_CLASS.members().enter(ANY_CLASS); + ANY_TYPE = monoType(ANY_CLASS); + ANY_CLASS.setInfo(Type.compoundType(Type.EMPTY_ARRAY, new Scope(), ANY_CLASS)); + ANY_CLASS.constructor().setInfo( + Type.PolyType(Symbol.EMPTY_ARRAY, ANY_TYPE)); + + // the java.lang.OBJECT class + JAVA_OBJECT_CLASS = getClass(Names.java_lang_Object); + JAVA_OBJECT_TYPE = monoType(JAVA_OBJECT_CLASS); + JAVA_OBJECT_CLASS.setInfo(pparser.classCompletion); + + // the scala.ANYREF class + ANYREF_CLASS = new TypeSymbol( + Kinds.ALIAS, Position.NOPOS, Names.AnyRef.toTypeName(), + SCALA_CLASS, Modifiers.JAVA) + .setInfo(JAVA_OBJECT_TYPE); + ANYREF_CLASS.constructor().setInfo( + Type.PolyType(Symbol.EMPTY_ARRAY, Type.NoType)); + + ANYREF_TYPE = monoType(ANYREF_CLASS); + SCALA.members().enter(ANYREF_CLASS); + + // the scala.OBJECT class + OBJECT_CLASS = getClass(Names.scala_Object); + OBJECT_TYPE = monoType(OBJECT_CLASS); + + // the scala.ANYVAL class + ANYVAL_CLASS = getClass(Names.scala_AnyVal); + ANYVAL_TYPE = monoType(ANYVAL_CLASS); + + // the primitive types + DOUBLE_CLASS = getClass(Names.scala_Double); + DOUBLE_TYPE = monoType(DOUBLE_CLASS); + FLOAT_CLASS = getClass(Names.scala_Float); + FLOAT_TYPE = monoType(FLOAT_CLASS); + LONG_CLASS = getClass(Names.scala_Long); + LONG_TYPE = monoType(LONG_CLASS); + INT_CLASS = getClass(Names.scala_Int); + INT_TYPE = monoType(INT_CLASS); + CHAR_CLASS = getClass(Names.scala_Char); + CHAR_TYPE = monoType(CHAR_CLASS); + SHORT_CLASS = getClass(Names.scala_Short); + SHORT_TYPE = monoType(SHORT_CLASS); + BYTE_CLASS = getClass(Names.scala_Byte); + BYTE_TYPE = monoType(BYTE_CLASS); + BOOLEAN_CLASS = getClass(Names.scala_Boolean); + BOOLEAN_TYPE = monoType(BOOLEAN_CLASS); + UNIT_CLASS = getClass(Names.scala_Unit); + UNIT_TYPE = monoType(UNIT_CLASS); + + // the array class + ARRAY_CLASS = getClass(Names.scala_Array); + + // add members to java.lang.Throwable + JAVA_THROWABLE_CLASS = getClass(Names.java_lang_Throwable); + JAVA_THROWABLE_TYPE = monoType(JAVA_THROWABLE_CLASS); + THROW = new TermSymbol( + Position.NOPOS, Names.throw_, JAVA_THROWABLE_CLASS, Modifiers.FINAL); + Symbol tvar = newTypeParameter(THROW, ANY_TYPE); + THROW.setInfo(Type.PolyType(new Symbol[]{tvar}, tvar.type())); + JAVA_THROWABLE_CLASS.members().enter(THROW); + + // add the java.lang.String class to the scala package + JAVA_STRING_CLASS = getClass(Names.java_lang_String); + JAVA_STRING_TYPE = monoType(JAVA_STRING_CLASS); + STRING_CLASS = new TypeSymbol( + Kinds.ALIAS, Position.NOPOS, Names.String.toTypeName(), SCALA_CLASS, 0) + .setInfo(JAVA_STRING_TYPE); + STRING_CLASS.constructor().setInfo( + Type.PolyType(Symbol.EMPTY_ARRAY, Type.NoType)); + STRING_TYPE = monoType(STRING_CLASS); + SCALA.members().enter(STRING_CLASS); + + /* + ANY_PLUS_STRING = new TermSymbol( + Position.NOPOS, Names.PLUS, ANY_CLASS, Modifiers.FINAL); + ANY_PLUS_STRING.setInfo( + Type.MethodType( + new Symbol[]{newParameter(ANY_PLUS_STRING, STRING_TYPE)}, + STRING_TYPE)); + ANY_CLASS.members().enter(ANY_PLUS_STRING); + */ + + STRING_PLUS_ANY = new TermSymbol( + Position.NOPOS, Names.PLUS, STRING_CLASS, Modifiers.FINAL); + STRING_PLUS_ANY.setInfo( + Type.MethodType( + new Symbol[]{newParameter(STRING_PLUS_ANY, ANY_TYPE)}, + STRING_TYPE)); + STRING_CLASS.members().enter(STRING_PLUS_ANY); + + // add members to class scala.Any + MATCH = new TermSymbol( + Position.NOPOS, Names.match, ANY_CLASS, Modifiers.FINAL); + MATCH.setInfo( + Type.MethodType( + new Symbol[]{newParameter(MATCH, OBJECT_TYPE)}, + OBJECT_TYPE)); + ANY_CLASS.members().enter(MATCH); + + AS = new TermSymbol( + Position.NOPOS, Names.as, ANY_CLASS, Modifiers.FINAL); + tvar = newTypeParameter(AS, ANY_TYPE); + AS.setInfo(Type.PolyType(new Symbol[]{tvar}, tvar.type())); + ANY_CLASS.members().enter(AS); + + IS = new TermSymbol( + Position.NOPOS, Names.is, ANY_CLASS, Modifiers.FINAL); + IS.setInfo(Type.PolyType(new Symbol[]{newTypeParameter(IS, ANY_TYPE)}, + BOOLEAN_TYPE)); + ANY_CLASS.members().enter(IS); + + EQEQ = new TermSymbol( + Position.NOPOS, Names.EQEQ, ANY_CLASS, 0); + EQEQ.setInfo(Type.MethodType(new Symbol[]{newParameter(EQEQ, ANY_TYPE)}, + BOOLEAN_TYPE)); + ANY_CLASS.members().enter(EQEQ); + + BANGEQ = new TermSymbol( + Position.NOPOS, Names.BANGEQ, ANY_CLASS, 0); + BANGEQ.setInfo(Type.MethodType(new Symbol[]{newParameter(BANGEQ, ANY_TYPE)}, + BOOLEAN_TYPE)); + ANY_CLASS.members().enter(BANGEQ); + + TOSTRING = new TermSymbol( + Position.NOPOS, Names.toString, ANY_CLASS, 0); + TOSTRING.setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, STRING_TYPE)); + ANY_CLASS.members().enter(TOSTRING); + + HASHCODE = new TermSymbol( + Position.NOPOS, Names.hashCode, ANY_CLASS, 0); + HASHCODE.setInfo(Type.MethodType(Symbol.EMPTY_ARRAY, INT_TYPE)); + ANY_CLASS.members().enter(HASHCODE); + + // add a null value to the root scope + NULL = new TermSymbol( + Position.NOPOS, Names.null_, ROOT_CLASS, 0); + tvar = newTypeParameter(NULL, ANYREF_TYPE); + NULL.setInfo(Type.PolyType(new Symbol[]{tvar}, tvar.type())); + ROOT.members().enter(NULL); + } + + private Symbol newParameter(Symbol owner, Type tp) { + return new TermSymbol(Position.NOPOS, Name.fromString("v"), owner, Modifiers.PARAM) + .setInfo(tp); + } + + private Symbol newTypeParameter(Symbol owner, Type bound) { + return new TypeSymbol( + Kinds.TYPE, Position.NOPOS, Name.fromString("T").toTypeName(), owner, Modifiers.PARAM) + .setInfo(bound); + } + + public Symbol getModule(Name fullname) { + Scope scope = ROOT_CLASS.members(); + int i = 0; + int j = fullname.pos((byte)'.', i); + while (j < fullname.length()) { + scope = scope.lookup(fullname.subName(i, j)).members(); + i = j + 1; + j = fullname.pos((byte)'.', i); + } + Symbol sym = scope.lookup(fullname.subName(i, fullname.length())); + if (!sym.isModule()) { + switch (sym.type()) { + case OverloadedType(Symbol[] alts, Type[] alttypes): + for (int k = 0; k < alts.length; k++) + if ((sym = alts[k]).isModule()) break; + } + } + assert sym.isModule() : "no module '" + fullname + "'"; + return sym; + } + + public Symbol getClass(Name fullname) { + Scope scope = ROOT_CLASS.members(); + int i = 0; + int j = fullname.pos((byte)'.', i); + while (j < fullname.length()) { + scope = scope.lookup(fullname.subName(i, j)).members(); + i = j + 1; + j = fullname.pos((byte)'.', i); + } + Symbol sym = scope.lookup(fullname.subName(i, fullname.length()).toTypeName()); + assert sym.kind != Kinds.NONE : "no class '" + fullname + "'"; + return sym; + } + + public Type getType(Name fullname) { + return getClass(fullname).type(); + } + + public Type monoType(Symbol c) { + return Type.TypeRef(c.owner().thisType(), c, Type.EMPTY_ARRAY); + } + + public Type getJavaType(Name fullname) { + return monoType(getClass(fullname)); + } + + private void loadBooleanMembers() { + if (TRUE != null) return; + Symbol booleanStatics = getModule(Names.scala_Boolean); + TRUE = booleanStatics.members().lookup(Names.True); + FALSE = booleanStatics.members().lookup(Names.False); + BARBAR = BOOLEAN_TYPE.lookup(Names.BARBAR); + AMPAMP = BOOLEAN_TYPE.lookup(Names.AMPAMP); + } + + public Type arrayType(Type elemtpe) { + return Type.appliedType(monoType(ARRAY_CLASS), new Type[]{elemtpe}); + } + + public Type functionType(Type[] argtps, Type restp) { + Type[] argtps1 = new Type[argtps.length + 1]; + System.arraycopy(argtps, 0, argtps1, 0, argtps.length); + argtps1[argtps.length] = Type.covarType(restp); + return Type.appliedType( + getType(Name.fromString("scala.Function" + argtps.length)), + argtps1); + } + + public Type tupleType(Type[] args) { + assert args.length > 0; + Type[] args1 = new Type[args.length]; + for (int i = 0; i < args.length; i++) + args1[i] = Type.covarType(args[i]); + return Type.appliedType( + getType(Name.fromString("scala.Tuple" + args.length)), args1); + } +} diff --git a/sources/scalac/symtab/Kinds.java b/sources/scalac/symtab/Kinds.java new file mode 100644 index 0000000000..8902ff4699 --- /dev/null +++ b/sources/scalac/symtab/Kinds.java @@ -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; +} diff --git a/sources/scalac/symtab/Modifiers.java b/sources/scalac/symtab/Modifiers.java new file mode 100644 index 0000000000..3fc119419e --- /dev/null +++ b/sources/scalac/symtab/Modifiers.java @@ -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)); + } + } +} diff --git a/sources/scalac/symtab/NameMangler.java b/sources/scalac/symtab/NameMangler.java new file mode 100644 index 0000000000..30de8193d0 --- /dev/null +++ b/sources/scalac/symtab/NameMangler.java @@ -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/*>*/ 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)); + } +} diff --git a/sources/scalac/symtab/Scope.java b/sources/scalac/symtab/Scope.java new file mode 100644 index 0000000000..3bd22f51ed --- /dev/null +++ b/sources/scalac/symtab/Scope.java @@ -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(); +} + diff --git a/sources/scalac/symtab/SourceCompleter.java b/sources/scalac/symtab/SourceCompleter.java new file mode 100644 index 0000000000..1656f2029f --- /dev/null +++ b/sources/scalac/symtab/SourceCompleter.java @@ -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; + } + } +} diff --git a/sources/scalac/symtab/SymSet.java b/sources/scalac/symtab/SymSet.java new file mode 100644 index 0000000000..f72b9764f5 --- /dev/null +++ b/sources/scalac/symtab/SymSet.java @@ -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(); +} diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java new file mode 100644 index 0000000000..f13192848b --- /dev/null +++ b/sources/scalac/symtab/Symbol.java @@ -0,0 +1,1291 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +** +** $Id$ +\* */ + +//todo check significance of JAVA flag. + +package scalac.symtab; + +import scalac.ApplicationError; +import scalac.Global; +import scalac.PhaseDescriptor; +import scalac.util.ArrayApply; +import scalac.util.Name; +import scalac.util.Names; +import scalac.util.NameTransformer; +import scalac.util.Position; +import scalac.util.Debug; +import scalac.symtab.classfile.*; + + +public abstract class Symbol implements Modifiers, Kinds { + + /** An empty symbol array */ + public static final Symbol[] EMPTY_ARRAY = new Symbol[0]; + + /** An empty array of symbol arrays */ + public static final Symbol[][] EMPTY_ARRAY_ARRAY = new Symbol[0][]; + + /** The error symbol */ + public static final ErrorSymbol ERROR = new ErrorSymbol(); + + /** The absent symbol */ + public static final NoSymbol NONE = new NoSymbol(); + +// Fields ------------------------------------------------------------- + + /** The kind of the symbol */ + public int kind; + + /** The position of the symbol */ + public int pos; + + /** The name of the symbol */ + public Name name; + + /** The modifiers of the symbol */ + public int flags; + + /** The owner of the symbol */ + private Symbol owner; + + /** The infos of the symbol */ + private TypeIntervalList infos = TypeIntervalList.EMPTY; + +// Constructors ----------------------------------------------------------- + + /** Generic symbol constructor */ + public Symbol(int kind, int pos, Name name, Symbol owner, int flags) { + assert (!isTerm() || !name.isTypeName()) && (!isType() || name.isTypeName()); + + this.kind = kind; + this.pos = pos; + this.name = name; + this.owner = owner; + this.flags = flags & ~(INITIALIZED | LOCKED); // safety first + } + + /** Return a fresh symbol with the same fields as this one. + */ + public abstract Symbol cloneSymbol(); + + /** copy all fields to `sym' + */ + public void copyTo(Symbol sym) { + sym.kind = kind; + sym.pos = pos; + sym.name = name; + sym.flags = flags; + sym.owner = owner; + sym.infos = infos; + } + +// Setters --------------------------------------------------------------- + + /** Set the mangled name of this Symbol */ + public Symbol setMangledName(Name name) { + throw new ApplicationError("illegal operation on " + getClass()); + } + + /** Set owner */ + public Symbol setOwner(Symbol owner) { + this.owner = owner; + return this; + } + + /** Set information, except if symbol is both initialized and locked. + */ + public Symbol setInfo(Type info) { + return setInfo(info, currentPhaseId()); + } + + public Symbol setInfo(Type info, int limit) { + if ((flags & (INITIALIZED | LOCKED)) != (INITIALIZED | LOCKED)) { + if (infos == TypeIntervalList.EMPTY) + infos = new TypeIntervalList(TypeIntervalList.EMPTY); + infos.limit = limit; + infos.info = info; + } + return this; + } + + /** Set type -- this is an alias for setInfo(Type info) */ + public Symbol setType(Type info) { return setInfo(info); } + + public Symbol updateInfo(Type info) { + // Global.instance.currentPhase.setInfo(this, info); + if (infos.limit <= Global.instance.currentPhase.id) { + infos = new TypeIntervalList(infos); + infos.limit = Global.instance.currentPhase.id + 1; + } else { + assert infos.limit == Global.instance.currentPhase.id + 1 : this; + } + infos.info = info; + return this; + } + +// Symbol classification ---------------------------------------------------- + + /** Does this symbol denote a type? */ + public final boolean isType() { + return kind == TYPE || kind == CLASS || kind == ALIAS; + } + + /** Does this symbol denote a term? */ + public final boolean isTerm() { + return kind == VAL; + } + + /** Does this symbol denote a value? */ + public final boolean isValue() { + return kind == VAL && !(isModule() && isJava()) && !isPackage(); + } + + /** Does this symbol denote a variable? */ + public final boolean isVariable() { + return kind == VAL && (flags & MUTABLE) != 0; + } + + /** Does this symbol denote a method? + */ + public final boolean isInitializedMethod() { + if (infos.limit < 0) return false; + switch (rawInfo()) { + case MethodType(_, _): + case PolyType(_, _): return true; + default: return false; + } + } + + public final boolean isMethod() { + initialize(); + return isInitializedMethod(); + } + + /* Does this symbol denote an anonymous class? */ + public final boolean isAnonymousClass() { + return kind == CLASS && + (name == Names.EMPTY.toTypeName() || + name == Names.ANON_CLASS_NAME.toTypeName()); + } + + /** Does this symbol denote the root class or root module? + */ + public final boolean isRoot() { + return this.moduleClass() == Global.instance.definitions.ROOT_CLASS; + } + + /** Does this symbol denote something loaded from a Java class? */ + public final boolean isJava() { + return (flags & JAVA) != 0; + } + + /** Does this symbol denote a Java package? */ + public final boolean isPackage() { + return (flags & PACKAGE) != 0; + } + + /** Does this symbol denote a module? */ + public final boolean isModule() { + return kind == VAL && (flags & MODUL) != 0; + } + + /** Does this symbol denote a module? */ + public final boolean isModuleClass() { + return kind == CLASS && (flags & MODUL) != 0; + } + + /** Does this symbol denote a module? */ + public final boolean isClass() { + return kind == CLASS; + } + + /** Does this symbol denote a case class? + */ + public final boolean isCaseClass() { + return kind == CLASS && (flags & CASE) != 0; + } + + /** Does this symbol denote a uniform (i.e. parameterless) class? */ + public final boolean isTrait() { + return kind == CLASS && (flags & TRAIT) != 0; + } + + /** Does this class symbol denote a compound type symbol? + */ + public final boolean isCompoundSym() { + return name == Names.COMPOUND_NAME.toTypeName(); + } + + /** Does this symbol denote an interface? */ + public final boolean isInterface() { + return (flags & INTERFACE) != 0; + } + + /** Does this symbol denote a static member? */ + public final boolean isStatic() { + return (flags & STATIC) != 0; + } + + /** Is this symbol locally defined? I.e. not a member of a class or module */ + public final boolean isLocal() { + return owner.kind == VAL && !owner.isPrimaryConstructor(); + } + + /** Is this symbol a parameter? Includes type parameters of methods. + */ + public final boolean isParameter() { + return (flags & PARAM) != 0; + } + + /** Is this symbol a def parameter? + */ + public final boolean isDefParameter() { + return (flags & (PARAM | DEF)) == (PARAM | DEF); + } + + /** Is this class locally defined? + * A class is local, if + * - it is anonymous, or + * - its owner is a value + * - it is defined within a local class + */ + public final boolean isLocalClass() { + return kind == CLASS && + !isPackage() && + (name == Names.EMPTY.toTypeName() || + owner.isValue() || + owner.isLocalClass()); + } + + /** Is this symbol a constructor? */ + public final boolean isConstructor() { + return name.isConstrName(); + } + + /** Is this symbol the primary constructor of a type? */ + public final boolean isPrimaryConstructor() { + return isConstructor() && this == constructorClass().constructor(); + } + + public boolean isGenerated() { + return name.pos((byte)'$') < name.length(); + } + + /** Symbol was preloaded from package + */ + public boolean isPreloaded() { + return owner.isPackage() && pos == Position.NOPOS; + } + +// Symbol names ---------------------------------------------------------------- + + /** Get the fully qualified name of this Symbol + * (this is always a normal name, never a type name) + */ + public Name fullName() { + return name.toTermName(); + } + + /** Get the mangled name of this Symbol + * (this is always a normal name, never a type name) + */ + public Name mangledName() { + return name.toTermName(); + } + + /** Get the fully qualified mangled name of this Symbol */ + public Name mangledFullName() { + return fullName().replace((byte)'.', (byte)'$'); + } + +// Acess to related symbols ----------------------------------------------------- + + /** Get type parameters */ + public Symbol[] typeParams() { + return EMPTY_ARRAY; + } + + /** Get primary constructor of class */ + public Symbol constructor() { + return NONE; + } + + /** Get module associated with class */ + public Symbol module() { + return NONE; + } + + /** Get owner */ + public Symbol owner() { + return owner; + } + + /** Get owner, but if owner is primary constructor of a class, + * get class symbol instead. This is useful for type parameters + * and value parameters in classes which have the primary constructor + * as owner. + */ + public Symbol classOwner() { + Symbol owner = owner(); + Symbol clazz = owner.constructorClass(); + if (clazz.constructor() == owner) return clazz; + else return owner; + } + + /** The next enclosing class */ + public Symbol enclClass() { + return owner().enclClass(); + } + + /** The top-level class enclosing `sym' + */ + Symbol enclToplevelClass() { + Symbol sym = this; + while (sym.kind == VAL || + (sym.kind == CLASS && !sym.owner().isPackage())) { + sym = sym.owner(); + } + return sym; + } + + /* If this is a constructor, return the class it constructs. + * Otherwise return the symbol itself. + */ + public Symbol constructorClass() { + return this; + } + + /* If this is a module, return its class. + * Otherwise return the symbol itself. + */ + public Symbol moduleClass() { + return this; + } + + /** The symbol accessed by this accessor function. + */ + public Symbol accessed() { + assert (flags & ACCESSOR) != 0; + Name name1 = name; + if (name1.endsWith(Names._EQ)) + name1 = name1.subName(0, name1.length() - Names._EQ.length()); + return owner.info().lookup(Name.fromString(name1 + "$")); + } + + /** The members of this class or module symbol + */ + public Scope members() { + return info().members(); + } + +// Symbol types -------------------------------------------------------------- + + /** Was symbol's type updated during phase `id'? + */ + public boolean isUpdated(int id) { + return infos.limit >= id; + } + + /** the current phase id, or the id after analysis, whichever is larger. + */ + int currentPhaseId() { + int id = Global.instance.currentPhase.id; + if (id > Global.instance.POST_ANALYZER_PHASE_ID) + id = Global.instance.POST_ANALYZER_PHASE_ID; + return id; + } + + /** Is this symbol initialized? */ + public final boolean isInitialized() { + return (flags & INITIALIZED) != 0; + } + + /** Initialize the symbol */ + public final Symbol initialize() { + info(); + return this; + } + + /** Get info; This is: + * for a term symbol, its type + * for a type variable, its bound + * for a type alias, its right-hand side + * for a class symbol, the compound type consisting of + * its baseclasses and members. + */ + public Type info() { + if ((flags & INITIALIZED) == 0) { + int id = currentPhaseId(); + Type info = rawInfoAt(id); + assert info != null : this; + + if ((flags & LOCKED) != 0) { + setInfo(Type.ErrorType); + flags |= INITIALIZED; + throw new CyclicReference(this, info); + } + flags |= LOCKED; + //System.out.println("completing " + this);//DEBUG + info.complete(this); + flags = flags & ~LOCKED; + if (info instanceof SourceCompleter && (flags & SNDTIME) == 0) { + flags |= SNDTIME; + return info(); + } else { + assert !(rawInfoAt(id) instanceof Type.LazyType) : this; + flags |= INITIALIZED; + } + //System.out.println("done: " + this);//DEBUG + } + return rawInfoAt(Global.instance.currentPhase.id); + } + + /** Get info at phase #id + */ + public Type infoAt(int id) { + info(); + return rawInfoAt(id); + } + + /** get info at phase #id, without forcing lazy types. + */ + private Type rawInfoAt(int id) { + int nextid = infos.limit; + assert infos != TypeIntervalList.EMPTY : this; + if (nextid < id) { + do { + Type newInfo = + Global.instance.phases[nextid].transformInfo(this, infos.info); + if (newInfo != infos.info) { + infos = new TypeIntervalList(infos); + infos.info = newInfo; + } + nextid++; + infos.limit = nextid; + } while (nextid < id); + return infos.info; + } else { + TypeIntervalList infos1 = infos; + while (infos1.prev.limit >= id) { + infos1 = infos1.prev; + } + return infos1.info; + } + } + + public Type rawInfo() { + return rawInfoAt(Global.instance.currentPhase.id); + } + + /** The type of a symbol is: + * for a type symbol, the type corresponding to the symbol itself + * for a term symbol, its usual type + */ + public Type type() { + return info(); + } + + /** The type at phase #id + */ + public Type typeAt(int id) { + return infoAt(id); + } + + /** The types of these symbols as an array. + */ + static public Type[] type(Symbol[] syms) { + Type[] tps = new Type[syms.length]; + for (int i = 0; i < syms.length; i++) + tps[i] = syms[i].type(); + return tps; + } + + /** Get this.type corresponding to this symbol + */ + public Type thisType() { + return Type.localThisType; + } + + public Type typeOfThis() { + return Type.localThisType; + } + + /** A total ordering between symbols that refines the class + * inheritance graph (i.e. subclass.isLess(superclass) always holds). + */ + public boolean isLess(Symbol that) { + if (this == that) return false; + int diff; + if (this.isType()) { + if (that.isType()) { + diff = this.closure().length - that.closure().length; + if (diff > 0) return true; + if (diff < 0) return false; + } else { + return true; + } + } else if (that.isType()) { + return false; + } + + diff = that.mangledName().index - this.mangledName().index; + if (diff > 0) return true; + if (diff < 0) return false; + + diff = that.mangledFullName().index - this.mangledFullName().index; + if (diff > 0) return true; + if (diff < 0) return false; + + throw new ApplicationError( + "Giving up: can't order two incarnations of class " + + this.mangledFullName()); + } + + /** Return the symbol's type itself followed by all its direct and indirect + * base types, sorted by isLess(). Overridden for class symbols. + */ + public Type[] closure() { + return info().closure(); + } + + /** Return position of `c' in the closure of this type; -1 if not there. + */ + public int closurePos(Symbol c) { + if (this == c) return 0; + if (c.isCompoundSym()) return -1; + Type[] closure = closure(); + int lo = 0; + int hi = closure.length - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + Symbol clsym = closure[mid].symbol(); + if (c == clsym) return mid; + else if (c.isLess(clsym)) hi = mid - 1; + else if (clsym.isLess(c)) lo = mid + 1; + else throw new ApplicationError(); + } + return -1; + } + + Type baseType(Symbol sym) { + int i = closurePos(sym); + if (i >= 0) return closure()[i]; + else return Type.NoType; + } + + /** Is this class a subclass of `c'? I.e. does it have a type instance + * of `c' as indirect base class? + */ + public boolean isSubClass(Symbol c) { + return this == c || c.kind == Kinds.ERROR || closurePos(c) >= 0; + } + +// ToString ------------------------------------------------------------------- + + /** String representation of symbol's simple name. + * Translates expansions of operators back to operator symbol. E.g. + * $eq => =. + */ + public String nameString() { + return NameTransformer.decode(name).toString(); + } + + /** String representation of symbol's full name. + * Translates expansions of operators back to operator symbol. E.g. + * $eq => =. + */ + public String fullNameString() { + return NameTransformer.decode(fullName()).toString(); + } + + public String idString() { + if (Global.instance.uniqid && + (kind == TYPE || Global.instance.debug)) + return "#" + Global.instance.uniqueID.id(this); + else return ""; + } + + /** String representation, including symbol's kind + * e.g., "class Foo", "function Bar". + */ + public String toString() { + if (isRoot()) return ""; + if (isAnonymousClass()) return "