summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2003-12-02 10:25:23 +0000
committerMartin Odersky <odersky@gmail.com>2003-12-02 10:25:23 +0000
commit3a4e72367ec151c5d8379af408bf72c594f8605d (patch)
tree4e86b89b62c4b6850ae9b0f435fa1aae1cd0b428
parent142bcb34f745cca56542a0f7f334cbc3b91d033d (diff)
downloadscala-3a4e72367ec151c5d8379af408bf72c594f8605d.tar.gz
scala-3a4e72367ec151c5d8379af408bf72c594f8605d.tar.bz2
scala-3a4e72367ec151c5d8379af408bf72c594f8605d.zip
*** empty log message ***
-rw-r--r--doc/reference/ScalaReference.tex13
-rw-r--r--sources/scala/List.scala20
-rw-r--r--sources/scala/tools/scalac/ast/parser/Scanner.scala33
-rw-r--r--sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala6
-rw-r--r--sources/scala/tools/scalac/typechecker/Infer.scala28
-rw-r--r--sources/scalac/ast/parser/Scanner.java28
-rw-r--r--sources/scalac/typechecker/Infer.java19
7 files changed, 92 insertions, 55 deletions
diff --git a/doc/reference/ScalaReference.tex b/doc/reference/ScalaReference.tex
index 3be6c66636..fa5a795b65 100644
--- a/doc/reference/ScalaReference.tex
+++ b/doc/reference/ScalaReference.tex
@@ -123,7 +123,7 @@ constructed from symbols in the following character sets:
upper case letters ~\lstinline@`A' | $\ldots$ | `Z' | `$\Dollar$' | `_'@.
\item Digits ~\lstinline@`0' | $\ldots$ | `9'@.
\item Parentheses ~\lstinline@`(' | `)' | `[' | `]' | `{' | `}'@.
-\item Delimiter characters ~\lstinline@`\' | `'' | `"' | `.' | `;' | `,'@.
+\item Delimiter characters ~\lstinline@``' | `'' | `"' | `.' | `;' | `,'@.
\item Operator characters. These include all printable ASCII characters
which are in none of the sets above.
\end{enumerate}
@@ -139,7 +139,7 @@ varid ::= lower {letter $|$ digit} [`_' [id]]
id ::= upper {letter $|$ digit} [`_' [id]]
| varid
| op
- | `\' stringLit
+ | ``'string chars``'
\end{lstlisting}
There are three ways to form an identifier. First, an identifier can
@@ -149,11 +149,10 @@ character followed by an arbitrary sequence of special characters. In
the first case, the identifier prefix may be immediately followed by
an underscore `\lstinline@_@' character and another string of
characters that by themselves make up an identifier. Finally, an
-identifier may also start with an escape character \lstinline@`\'@
-which is followed by an arbitrary string in apostrophes (host systems
-may impose some restrictions on which strings are legal for
-identifiers). As usual, a longest match rule applies. For instance,
-the string
+identifier may also be formed by an arbitrary string between
+backquotes (host systems may impose some restrictions on which strings
+are legal for identifiers). As usual, a longest match rule
+applies. For instance, the string
\begin{lstlisting}
big_bob++=z3
diff --git a/sources/scala/List.scala b/sources/scala/List.scala
index 135a998000..6ff50e2052 100644
--- a/sources/scala/List.scala
+++ b/sources/scala/List.scala
@@ -438,9 +438,7 @@ trait List[+a] extends Seq[a] {
/** Combines the elements of this list together using the binary
* operator <code>op</code>, from left to right, and starting with
- * the value <code>z</code>. Similar to <code>fold</code> but with
- * a different order of the arguments, allowing to use nice constructions like
- * <code>(z foldLeft l) { ... }</code>.
+ * the value <code>z</code>.
* @return <code>op(... (op(op(z,a0),a1) ...), an)</code> if the list
* is <code>[a0, a1, ..., an]</code>.
*/
@@ -449,13 +447,27 @@ trait List[+a] extends Seq[a] {
case x :: xs => xs.foldLeft[b](f(z, x))(f)
};
+ /** Combines the elements of this list together using the binary
+ * operator <code>op</code>, from rigth to left, and starting with
+ * the value <code>z</code>.
+ * @return <code>a0 op (... op (an op z)...)</code> if the list
+ * is <code>[a0, a1, ..., an]</code>.
+ */
def foldRight[b](z: b)(f: (a, b) => b): b = match {
case Nil => z
case x :: xs => f(x, xs.foldRight(z)(f))
};
+ /** Similar to <code>foldLeft</code> but can be used as
+ * an operator with the order of list and zero arguments reversed.
+ * That is, <code>z /: xs</code> is the same as <code>xs foldLeft z</code>
+ */
def /:[b](z: b)(f: (b, a) => b): b = foldLeft(z)(f);
- def :/[b](z: b)(f: (a, b) => b): b = foldRight(z)(f);
+
+ /** An alias for <code>foldRight</code>.
+ * That is, <code>xs :\ z</code> is the same as <code>xs foldRight z</code>
+ */
+ def :\[b](z: b)(f: (a, b) => b): b = foldRight(z)(f);
def reduceLeft[b >: a](f: (b, b) => b): b = this match {
case Nil => error("Nil.reduceLeft")
diff --git a/sources/scala/tools/scalac/ast/parser/Scanner.scala b/sources/scala/tools/scalac/ast/parser/Scanner.scala
index dac8c8eada..f890a0a6f6 100644
--- a/sources/scala/tools/scalac/ast/parser/Scanner.scala
+++ b/sources/scala/tools/scalac/ast/parser/Scanner.scala
@@ -199,19 +199,11 @@ class Scanner(_unit: Unit) extends TokenData {
return;
case '~' | '!' | '@' | '#' | '%' |
'^' | '*' | '+' | '-' | '<' |
- '>' | '?' | ':' |
- '=' | '&' | '|' =>
+ '>' | '?' | ':' | '=' | '&' |
+ '|' | '\\' =>
nextch();
getOperatorRest(index);
return;
- case '\\' =>
- nextch();
- if (ch == '"') { //"
- getStringLit();
- token = IDENTIFIER;
- } else
- syntaxError(pos, "illegal character");
- return;
case '/' =>
nextch();
if (!skipComment()) {
@@ -231,8 +223,12 @@ class Scanner(_unit: Unit) extends TokenData {
'5' | '6' | '7' | '8' | '9' =>
getNumber(index, 10);
return;
+ case '`' => //" scala-mode: need to understand literals
+ getStringLit('`');
+ token = IDENTIFIER;
+ return;
case '\"' => //" scala-mode: need to understand literals
- getStringLit();
+ getStringLit('\"');
return;
case '\'' =>
nextch();
@@ -407,8 +403,9 @@ class Scanner(_unit: Unit) extends TokenData {
while (true) {
ch match {
case '~' | '!' | '@' | '#' | '%' |
- '^' | '*' | '+' | '-' | '<' |
- '>' | '?' | ':' | '=' | '&' | '|' =>
+ '^' | '*' | '+' | '-' | '<' |
+ '>' | '?' | ':' | '=' | '&' |
+ '|' | '\\' =>
nextch();
case '/' =>
val lastbp = bp;
@@ -443,20 +440,20 @@ class Scanner(_unit: Unit) extends TokenData {
getIdentRest(index);
case '~' | '!' | '@' | '#' | '%' |
'^' | '*' | '+' | '-' | '<' |
- '>' | '?' | ':' |
- '=' | '&' | '|' | '/' =>
+ '>' | '?' | ':' | '=' | '&' |
+ '|' | '\\' | '/' =>
getOperatorRest(index);
case _ =>
treatIdent(index, bp);
}
}
- private def getStringLit(): unit = {
+ private def getStringLit(delimiter: char): unit = {
nextch();
litlen = 0;
- while (ch != '\"'/*"*/ && ch != CR && ch != LF && ch != SU)
+ while (ch != delimiter && ch != CR && ch != LF && ch != SU)
getlitch();
- if (ch == '\"'/*"*/) {
+ if (ch == delimiter) {
token = STRINGLIT;
name = Name.fromSource(lit, 0, litlen);
nextch();
diff --git a/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala b/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala
index 14d2fb3d0f..fe74bd5022 100644
--- a/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala
+++ b/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala
@@ -438,7 +438,7 @@ class TextTreePrinter(_out: PrintWriter, autoFlush: boolean) with TreePrinter {
case Tree$Apply(fun, vargs) =>
if (fun.isInstanceOf[Tree$TypeTerm])
- print(fun.\"type"/*"*/.resultType().symbol().fullName().toString());
+ print(fun.`type`.resultType().symbol().fullName().toString());
else
print(fun);
printArray(vargs, TXT_LEFT_PAREN, TXT_RIGHT_PAREN, TXT_COMMA_SP);
@@ -485,7 +485,7 @@ class TextTreePrinter(_out: PrintWriter, autoFlush: boolean) with TreePrinter {
printType(tree);
case Tree$TypeTerm() =>
- print(tree.\"type"/*"*/.toString());
+ print(tree.`type`.toString());
case Tree$SingletonType(ref) =>
print(ref);
@@ -562,7 +562,7 @@ class TextTreePrinter(_out: PrintWriter, autoFlush: boolean) with TreePrinter {
protected def printType(tree: Tree): unit =
if (scalac_Global.instance.printtypes) {
print(TXT_LEFT_BRACE);
- print(if (tree.\"type"/*"*/ != null) Simple(tree.\"type"/*"*/.toString())
+ print(if (tree.`type` != null) Simple(tree.`type`.toString())
else TXT_NULL);
print(TXT_RIGHT_BRACE);
}
diff --git a/sources/scala/tools/scalac/typechecker/Infer.scala b/sources/scala/tools/scalac/typechecker/Infer.scala
index 11214aec1e..8aee281d26 100644
--- a/sources/scala/tools/scalac/typechecker/Infer.scala
+++ b/sources/scala/tools/scalac/typechecker/Infer.scala
@@ -436,7 +436,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) {
/** Automatically perform the following conversions on expression types:
* A method type becomes the corresponding function type.
- * A nullary method type becomes its result type.
+ * A nullary metAhod type becomes its result type.
*/
private def normalize(tp: Type): Type = tp match {
case Type$MethodType(params, restype) =>
@@ -450,8 +450,28 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) {
/** Is normalized type `tp' a subtype of prototype `pt'?
*/
- def isCompatible(tp: Type, pt: Type): boolean =
- normalize(tp).isSubType(pt);
+ def isCompatible(tp: Type, pt: Type): boolean = {
+ val tp1 = normalize(tp);
+ if (tp1.isSubType(pt)) true
+ else {
+ val coerceMeth: Symbol = tp1.lookup(Names.coerce);
+ if (coerceMeth.kind == NONE) false
+ else tp1.memberType(coerceMeth) match {
+ case Type$PolyType(tparams, restype) if tparams.length == 0 =>
+ restype.isSubType(pt)
+ case _ =>
+ false
+ }
+ }
+ }
+
+ def isCompatible(tps: Array[Type], pts: Array[Type]): boolean = {
+ { var i = 0; while (i < tps.length) {
+ if (!isCompatible(tps(i), pts(i))) return false;
+ i = i + 1
+ }}
+ true
+ }
/** Type arguments mapped to `scala.All' are taken to be uninstantiated.
* Map all those type arguments to their corresponding type parameters
@@ -768,7 +788,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) {
val formals: Array[Type] = formalTypes(params, argtypes.length);
isCompatible(restpe, pt) &&
formals.length == argtypes.length &&
- Type.isSubType(argtypes, formals);
+ isCompatible(argtypes, formals)
case Type$PolyType(tparams, Type$MethodType(params, restpe)) =>
try {
val targs: Array[Type] = methTypeArgs(
diff --git a/sources/scalac/ast/parser/Scanner.java b/sources/scalac/ast/parser/Scanner.java
index ae8a9ba187..8e0f57a2fb 100644
--- a/sources/scalac/ast/parser/Scanner.java
+++ b/sources/scalac/ast/parser/Scanner.java
@@ -221,21 +221,11 @@ public class Scanner extends TokenData {
return;
case '~': case '!': case '@': case '#': case '%':
case '^': case '*': case '+': case '-': case '<':
- case '>': case '?': case ':':
+ case '>': case '?': case ':': case '\\':
case '=': case '&': case '|':
nextch();
getOperatorRest(index);
return;
- case '\\':
- nextch();
- if (ch == '"') {
- getStringLit();
- token = IDENTIFIER;
- } else {
- syntaxError(pos, "illegal character");
- }
- return;
-
case '/':
nextch();
if (!skipComment()) {
@@ -259,8 +249,12 @@ public class Scanner extends TokenData {
case '5': case '6': case '7': case '8': case '9':
getNumber(index, 10);
return;
+ case '`':
+ getStringLit('`');
+ token = IDENTIFIER;
+ return;
case '\"':
- getStringLit();
+ getStringLit('\"');
return;
case '\'':
nextch();
@@ -438,7 +432,7 @@ public class Scanner extends TokenData {
switch (ch) {
case '~': case '!': case '@': case '#': case '%':
case '^': case '*': case '+': case '-': case '<':
- case '>': case '?': case ':':
+ case '>': case '?': case ':': case '\\':
case '=': case '&': case '|':
nextch();
break;
@@ -482,7 +476,7 @@ public class Scanner extends TokenData {
return;
case '~': case '!': case '@': case '#': case '%':
case '^': case '*': case '+': case '-': case '<':
- case '>': case '?': case ':':
+ case '>': case '?': case ':': case '\\':
case '=': case '&': case '|':
case '/':
getOperatorRest(index);
@@ -497,12 +491,12 @@ public class Scanner extends TokenData {
}
}
- private void getStringLit() {
+ private void getStringLit(char delimiter) {
nextch();
litlen = 0;
- while (ch != '\"' && ch != CR && ch != LF && ch != SU)
+ while (ch != delimiter && ch != CR && ch != LF && ch != SU)
getlitch();
- if (ch == '\"') {
+ if (ch == delimiter) {
token = STRINGLIT;
name = Name.fromSource(lit, 0, litlen);
nextch();
diff --git a/sources/scalac/typechecker/Infer.java b/sources/scalac/typechecker/Infer.java
index b2b38ef2da..715b6d0f07 100644
--- a/sources/scalac/typechecker/Infer.java
+++ b/sources/scalac/typechecker/Infer.java
@@ -579,7 +579,22 @@ public class Infer implements Modifiers, Kinds {
/** Is normalized type `tp' a subtype of prototype `pt'?
*/
public boolean isCompatible(Type tp, Type pt) {
- return normalize(tp).isSubType(pt);
+ Type tp1 = normalize(tp);
+ if (tp1.isSubType(pt)) return true;
+ Symbol coerceMeth = tp1.lookup(Names.coerce);
+ if (coerceMeth.kind == NONE) return false;
+ switch (tp1.memberType(coerceMeth)) {
+ case PolyType(Symbol[] tparams, Type restype):
+ if (tparams.length == 0)
+ return restype.isSubType(pt);
+ }
+ return false;
+ }
+
+ public boolean isCompatible(Type[] tps, Type[] pts) {
+ for (int i = 0; i < tps.length; i++)
+ if (!isCompatible(tps[i], pts[i])) return false;
+ return true;
}
/** Type arguments mapped to `scala.All' are taken to be uninstantiated.
@@ -886,7 +901,7 @@ public class Infer implements Modifiers, Kinds {
return
isCompatible(restpe, pt) &&
formals.length == argtypes.length &&
- Type.isSubType(argtypes, formals);
+ isCompatible(argtypes, formals);
case PolyType(Symbol[] tparams, MethodType(Symbol[] params, Type restpe)):
try {
Type[] targs = methTypeArgs(