2010-08-05 17 views
4

Je le code suivant étant compilé avec scala 2.8.0:Type d'analyseur attendu dans la méthode "|"

import scala.util.parsing.combinator.{syntactical,PackratParsers} 
import syntactical.StandardTokenParsers 

object MyParser extends StandardTokenParsers with PackratParsers{ 
    lexical.reserved ++= Set("int","char","boolean") 

    lazy val primitiveType:PackratParser[PrimitiveType[_]] = primitiveChar | primitiveInt | primitiveBool 

    lazy val primitiveInt:PackratParser[PrimitiveType[Int]] = "int" ^^ { _ => PrimitiveType[Int]() } 

    lazy val primitiveChar:PackratParser[PrimitiveType[Char]] = "char" ^^ { _ => PrimitiveType[Char]() } 

    lazy val primitiveBool:PackratParser[PrimitiveType[Boolean]] = "boolean" ^^ { _ => PrimitiveType[Boolean]() } 
} 

object MyParser2 extends StandardTokenParsers with PackratParsers{ 
    lexical.reserved ++= Set("int","char","boolean") 

    lazy val primitiveType:PackratParser[PrimitiveType[_]] = primitiveChar | primitiveIntOrBool 

    lazy val primitiveIntOrBool:PackratParser[PrimitiveType[_]] = "int" ^^ { _ => PrimitiveType[Int]() } | "boolean" ^^ {_ => PrimitiveType[Boolean]()} 

    lazy val primitiveChar:PackratParser[PrimitiveType[Char]] = "char" ^^ { _ => PrimitiveType[Char]()} 
} 

case class PrimitiveType[T]() 

MyParser1 donne Compiler:

error: inferred type arguments [this.PrimitiveType[_ >: _1 with Boolean <: AnyVal]] do not conform to method |'s type parameter bounds [U >: this.PrimitiveType[_ >: Char with Int <: AnyVal]] 

Je crois qu'il échoue à cause de la | signature de type de méthode, définie comme:

def | [U >: T](q: => Parser[U]): Parser[U] 

Pourquoi U doit-il être un supertype de T? Quelle devrait être la valeur de retour de "primitiveType"?

Répondre

5

Vous devez changer votre dernière ligne dans

case class PrimitiveType[+T]() 

Cela permet PrimitiveType [Int] <: PrimitiveType [AnyVal] qui est nécessaire lorsque vous souhaitez fusionner les résultats de PrimitiveType [Boolean] et PrimitiveType [ Int] parseurs via |.

BTW, je suggère aussi d'écrire

PrimitiveType[AnyVal] 

au lieu de

PrimitiveType[_] 

car cela est plus précis dans votre cas.

+0

Ah, bonne réponse. Je rétracte le mien. –

+0

Merci, bien sûr, cela a résolu mon problème. Cependant, il me manque toujours pourquoi U>: T requis dans | –

+0

@kmels 'U' doit être un supertype de' T' car '|' construit un analyseur composé qui produira 'T' ou' U'. En pratique, donné 'T | S', le compilateur cherchera une * borne supérieure * de 'T' et' S' dans la hiérarchie de type, et appellera ce 'U'. –

3

Il est peut-être préférable de remplacer votre case class PrimitiveType[T] générique par une hiérarchie de classes. Les paramètres de type générique ne sont pas disponibles lors de l'exécution, de sorte que vous ne serez pas en mesure de faire beaucoup avec vos résultats parse ...

Cela vous donne les éléments suivants ( code non testé maintenant testé):

object MyParser extends StandardTokenParsers with PackratParsers{ 
    lexical.reserved ++= Set("int","char","boolean") 

    lazy val primitiveType:Parser[PrimitiveType] = primitiveChar | primitiveInt | primitiveBool 

    lazy val primitiveInt:PackratParser[PrimitiveType] = "int" ^^^ PrimitiveInt 

    lazy val primitiveChar:PackratParser[PrimitiveType] = "char" ^^^ PrimitiveChar 

    lazy val primitiveBool:PackratParser[PrimitiveType] = "boolean" ^^^ PrimitiveBoolean 
} 

sealed trait PrimitiveType 
case object PrimitiveInt extends PrimitiveType 
case object PrimitiveChar extends PrimitiveType 
case object PrimitiveBoolean extends PrimitiveType