From 00048f2901012137789f0af5ff5d733a581fc90e Mon Sep 17 00:00:00 2001 From: buraq Date: Tue, 18 May 2004 10:42:03 +0000 Subject: case classes implement trait scala.CaseClass --- sources/meta/scalac/ast/Tree.java | 2 +- sources/scala/CaseClass.scala | 26 ++++++++++++++ sources/scala/tools/scalac/ast/parser/Parser.scala | 13 +++++-- .../tools/scalac/typechecker/DeSugarize.scala | 2 +- sources/scalac/typechecker/RefCheck.java | 41 ++++++++++++++++++++-- sources/scalac/util/Names.java | 4 +++ 6 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 sources/scala/CaseClass.scala (limited to 'sources') diff --git a/sources/meta/scalac/ast/Tree.java b/sources/meta/scalac/ast/Tree.java index 8df7d2221d..bb59069140 100644 --- a/sources/meta/scalac/ast/Tree.java +++ b/sources/meta/scalac/ast/Tree.java @@ -276,7 +276,7 @@ public class Tree { n_Switch. setDescription("Switch"). - setRange(Phase.TRANSMATCH, Phase.END). + setRange(Phase.REFCHECK, Phase.END). addField(t_TermTree, "test"). addField(t_ints, "tags"). addField(t_TermTrees, "bodies"). diff --git a/sources/scala/CaseClass.scala b/sources/scala/CaseClass.scala new file mode 100644 index 0000000000..2e6306138b --- /dev/null +++ b/sources/scala/CaseClass.scala @@ -0,0 +1,26 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2003, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +** $Id$ +\* */ + +package scala; + +/** defines an access function for instances of case classes. + * + * @author Burak Emir + */ +trait CaseClass { + + /** for a case class A(x1,...,xk), returns x_i for 1<= i <= k, null otherwise + */ + def selectElement(n:int):Any = null; + + /** for a case class A(x1,...,xk), returns k + */ + def numberOfElements(): int = 0; + +} diff --git a/sources/scala/tools/scalac/ast/parser/Parser.scala b/sources/scala/tools/scalac/ast/parser/Parser.scala index 09e07f7312..6f4df2bd00 100644 --- a/sources/scala/tools/scalac/ast/parser/Parser.scala +++ b/sources/scala/tools/scalac/ast/parser/Parser.scala @@ -257,6 +257,10 @@ class Parser(unit: Unit) { make.Apply( pos, scalaDot(pos, Names.ScalaObject.toTypeName()), Tree.EMPTY_ARRAY); + def caseClassConstr(pos: int): Tree = + make.Apply( + pos, scalaDot(pos, Names.CaseClass.toTypeName()), Tree.EMPTY_ARRAY); + /** Create tree for for-comprehension or * where mapName and flatmapName are chosen * corresponding to whether this is a for-do or a for-yield. @@ -1859,7 +1863,7 @@ class Parser(unit: Unit) { paramClauseOpt())); } while (s.token == COMMA); val thistpe = simpleTypedOpt(); - val template = classTemplate(); + val template = classTemplate( mods ); val ts = new myTreeList(); lhs foreach { case Tuple4(p, n, tp, vp) => ts.append( @@ -1879,7 +1883,7 @@ class Parser(unit: Unit) { lhs.append(Pair(s.pos, ident())); } while (s.token == COMMA); val thistpe = simpleTypedOpt(); - val template = classTemplate(); + val template = classTemplate( mods ); val ts = new myTreeList(); lhs foreach { case Pair(p, n) => ts.append( @@ -1892,7 +1896,7 @@ class Parser(unit: Unit) { /** ClassTemplate ::= [`extends' Constr] {`with' Constr} [TemplateBody] */ - def classTemplate(): Tree$Template = { + def classTemplate( mods:int ): Tree$Template = { val pos = s.pos; val parents = new myTreeList(); if (s.token == EXTENDS) { @@ -1902,6 +1906,9 @@ class Parser(unit: Unit) { parents.append(scalaAnyRefConstr(pos)); } parents.append(scalaObjectConstr(pos)); + if( (mods & Modifiers.CASE) != 0 ) { + parents.append(caseClassConstr(pos)); + } if (s.token == WITH) { s.nextToken(); template(parents) diff --git a/sources/scala/tools/scalac/typechecker/DeSugarize.scala b/sources/scala/tools/scalac/typechecker/DeSugarize.scala index ae21fac622..11cd558573 100644 --- a/sources/scala/tools/scalac/typechecker/DeSugarize.scala +++ b/sources/scala/tools/scalac/typechecker/DeSugarize.scala @@ -609,7 +609,7 @@ class DeSugarize(make: TreeFactory, copy: TreeCopier, gen: TreeGen, infer: scala .setSymbol(vparam.symbol()))); } - /** add case constructor, defintiions value and access functions. + /** add case constructor, definitions value and access functions. */ def addCaseElements(body: Array[Tree], vparams: Array[Tree$ValDef]): Array[Tree] = { val stats: TreeList = new TreeList(); diff --git a/sources/scalac/typechecker/RefCheck.java b/sources/scalac/typechecker/RefCheck.java index a96a21fd0a..455bcd3f15 100644 --- a/sources/scalac/typechecker/RefCheck.java +++ b/sources/scalac/typechecker/RefCheck.java @@ -29,8 +29,9 @@ import Tree.*; * It preforms the following transformations. * * - Local modules are replaced by variables and classes - * - toString, equals, and hashCode methods are added to case classes, unless - * they are defined in the class or a baseclass different from java.lang.Object + * - equals, and hashCode, selectElement and toString methods are added to + * case classes, unless they are defined in the class or a baseclass + * different from java.lang.Object * - Calls to case factory methods are replaced by new's. * - Type nodes are replaced by TypeTerm nodes. * - Eliminate constant definitions @@ -687,6 +688,39 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { return gen.DefDef(toStringSym, body); } + private Tree selectElementMethod( ClassSymbol clazz ) { + Symbol seSym = clazz.newMethod( clazz.pos, OVERRIDE, Names.selectElement ); + Symbol seParam = seSym.newVParam( + clazz.pos, 0, Names.n, defs.INT_TYPE()); + seSym.setInfo( + Type.MethodType( new Symbol[]{ seParam }, defs.ANY_TYPE() )); + clazz.info().members().enter( seSym ); + Tree[] fields = caseFields( clazz ); + Tree body; + if( fields.length > 0) { // switch< n > + int tags[] = new int[ fields.length ]; + int i = 0; while( i < fields.length ) { tags[i] = ++i; }; + body = gen.Switch( gen.mkLocalRef( clazz.pos, seParam ), + tags, + fields, + gen.mkNullLit( clazz.pos ), + defs.ANY_TYPE() ); + } + else + body = gen.mkNullLit( clazz.pos ); + return gen.DefDef(seSym, body); + } + + private Tree numberOfElementsMethod( ClassSymbol clazz ) { + Symbol seSym = clazz.newMethod( clazz.pos, OVERRIDE, Names.numberOfElements ); + seSym.setInfo( + Type.MethodType( Symbol.EMPTY_ARRAY, defs.INT_TYPE() )); + clazz.info().members().enter( seSym ); + Tree[] fields = caseFields( clazz ); + return gen.DefDef(seSym, gen.mkIntLit( clazz.pos, fields.length )); + } + + private Tree equalsMethod(ClassSymbol clazz) { Symbol equalsSym = clazz.newMethod(clazz.pos, OVERRIDE, Names.equals); Symbol equalsParam = equalsSym.newVParam( @@ -823,6 +857,9 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { ts.append(equalsMethod(clazz)); if (!hasImplementation(clazz, Names.hashCode)) ts.append(hashCodeMethod(clazz)); + + ts.append(selectElementMethod(clazz)); + ts.append(numberOfElementsMethod(clazz)); ts.append(tagMethod(clazz)); if (ts.length() > 0) { Tree[] stats1 = new Tree[stats.length + ts.length()]; diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java index 87858f395c..619ddf5b07 100644 --- a/sources/scalac/util/Names.java +++ b/sources/scalac/util/Names.java @@ -106,6 +106,7 @@ public class Names { public static final Name AnyRef = Name.fromString("AnyRef"); public static final Name Array = Name.fromString("Array"); public static final Name Byte = Name.fromString("Byte"); + public static final Name CaseClass = Name.fromString("CaseClass"); public static final Name Catch = Name.fromString("Catch"); public static final Name Char = Name.fromString("Char"); public static final Name Boolean = Name.fromString("Boolean"); @@ -164,9 +165,11 @@ public class Names { public static final Name length = Name.fromString("length"); public static final Name match = Name.fromString("match"); public static final Name map = Name.fromString("map"); + public static final Name n = Name.fromString("n"); public static final Name nobinding = Name.fromString("nobinding"); public static final Name next = Name.fromString("next"); public static final Name newArray = Name.fromString("newArray"); + public static final Name numberOfElements = Name.fromString("numberOfElements"); public static final Name null_ = Name.fromString("null"); public static final Name predef = Name.fromString("predef"); public static final Name print = Name.fromString("print"); @@ -176,6 +179,7 @@ public class Names { public static final Name synchronized_ = Name.fromString("synchronized"); public static final Name eq = Name.fromString("eq"); public static final Name equals = Name.fromString("equals"); + public static final Name selectElement = Name.fromString("selectElement"); public static final Name tail = Name.fromString("tail"); public static final Name toString = Name.fromString("toString"); public static final Name that = Name.fromString("that"); -- cgit v1.2.3