SQL parser now generates inhabitants of the right types
authorAlexandre Bertails <bertails@w3.org>
Wed, 09 Dec 2009 19:39:58 -0500
changeset 6 12d498689ec8
parent 5 bd5351122ead
child 7 039d066f884e
SQL parser now generates inhabitants of the right types
src/main/scala/SQL.scala
--- a/src/main/scala/SQL.scala	Wed Dec 09 17:30:06 2009 -0500
+++ b/src/main/scala/SQL.scala	Wed Dec 09 19:39:58 2009 -0500
@@ -5,8 +5,7 @@
 
 import MyParsers._
 
-case class Select(attributelist:AttributeList, tablelist:TableList, expression:Expression)
-
+case class Select(attributelist:AttributeList, tablelist:TableList, expression:Option[Expression])
 case class AttributeList(attributes:List[NamedAttribute])
 case class NamedAttribute(fqattribute:FQAttribute, attribute:Attribute)
 case class FQAttribute(relation:Relation, attribute:Attribute)
@@ -17,34 +16,72 @@
 case class TableAlias(rel:Relation, as:Relation)
 case class Expression(conjuncts:List[PrimaryExpression])
 sealed abstract class PrimaryExpression
-case class PrimaryExpressionEq(l:FQAttribute, r:RValue)
-case class PrimaryExpressionLt(l:FQAttribute, r:RValue)
-case class PrimaryExpressionNotNull(l:FQAttribute)
+case class PrimaryExpressionEq(l:FQAttribute, r:RValue) extends PrimaryExpression
+case class PrimaryExpressionLt(l:FQAttribute, r:RValue) extends PrimaryExpression
+case class PrimaryExpressionNotNull(l:FQAttribute) extends PrimaryExpression
 sealed abstract class RValue
-case class RValueAttr(fqattribute:FQAttribute)
-case class RValueInt(i:Name)
-case class RValueString(i:Name)
-
+case class RValueAttr(fqattribute:FQAttribute) extends RValue
+case class RValueInt(i:Name) extends RValue
+case class RValueString(i:Name) extends RValue
 case class Name(s:String)
 
-
 case class Sql() extends JavaTokenParsers {
 
-  def select = "SELECT" ~ attributelist ~ "FROM" ~ tablelist ~ opt("WHERE" ~ expression)
-  def attributelist = repsep(namedattribute, ",")
-  def namedattribute = fqattribute ~ "AS" ~ attribute
-  def fqattribute = relation ~ "." ~ attribute
-  def attribute = """[a-zA-Z_]\w*""".r
-  def relation = """[a-zA-Z_]\w*""".r
-  def tablelist = tablealias ~ rep("INNER" ~ "JOIN" ~ tablealias ~ "ON" ~ expression)
-  def tablealias = relation ~ "AS" ~ relation
-  def expression = repsep(primaryexpression, "AND")
-  def primaryexpression = (  fqattribute ~ "=" ~ rvalue
-			   | fqattribute ~ "<" ~ rvalue
-			   | fqattribute ~ "IS" ~ "NOT" ~ "NULL" )
-  def rvalue = (  fqattribute
-		| """[0-9]+""".r
-		| "\"[^\"]*\"".r )
+  def select:Parser[Select] =
+    "SELECT" ~ attributelist ~ "FROM" ~ tablelist ~ opt(where) ^^
+    { case "SELECT" ~ attributes ~ "FROM" ~ tables ~ whereexpr =>
+      Select(attributes, tables, whereexpr) }
+
+  def where:Parser[Expression] =
+    "WHERE" ~ expression ^^ { case "WHERE" ~ expression => expression }
+
+  def attributelist:Parser[AttributeList] =
+    repsep(namedattribute, ",") ^^ { AttributeList(_)}
+
+  def namedattribute:Parser[NamedAttribute] =
+    fqattribute ~ "AS" ~ attribute ^^
+    { case fqattribute ~ "AS" ~ attribute =>
+      NamedAttribute(fqattribute, attribute) }
+
+  def fqattribute:Parser[FQAttribute] =
+    relation ~ "." ~ attribute ^^
+    { case relation ~ "." ~ attribute => FQAttribute(relation, attribute) }
+
+  def attribute:Parser[Attribute] =
+    """[a-zA-Z_]\w*""".r ^^ { x => Attribute(Name(x)) }
+
+  def relation:Parser[Relation] =
+    """[a-zA-Z_]\w*""".r ^^ { x => Relation(Name(x)) }
+
+  def tablelist:Parser[TableList] =
+    tablealias ~ rep("INNER" ~ "JOIN" ~ tablealias ~ "ON" ~ expression) ^^
+    { case tablealias ~ repjoins =>
+        val joins:List[Join] = repjoins map { case "INNER"~"JOIN"~tablealias~"ON"~expression => Join(tablealias, expression) }
+        TableList(tablealias, joins)
+    }
+
+  def tablealias:Parser[TableAlias] =
+    relation ~ "AS" ~ relation ^^
+    { case rel1 ~ "AS" ~ rel2 => TableAlias(rel1, rel2) }
+
+  def expression:Parser[Expression] = 
+    repsep(primaryexpression, "AND") ^^ 
+    { Expression(_) }
+
+  def primaryexpression:Parser[PrimaryExpression] = (
+      fqattribute ~ "=" ~ rvalue ^^
+      { case fqattribute ~ "=" ~ rvalue => PrimaryExpressionEq(fqattribute, rvalue) }
+    | fqattribute ~ "<" ~ rvalue ^^
+      { case fqattribute ~ "<" ~ rvalue => PrimaryExpressionLt(fqattribute, rvalue) }
+    | fqattribute ~ "IS" ~ "NOT" ~ "NULL" ^^
+      { case fqattribute ~ "IS" ~ "NOT" ~ "NULL" => PrimaryExpressionNotNull(fqattribute) }
+  )
+
+  def rvalue:Parser[RValue] = (
+      fqattribute ^^ { RValueAttr(_) }
+    | """[0-9]+""".r ^^ { x => RValueInt(Name(x)) }
+    | "\"[^\"]*\"".r  ^^ { x => RValueString(Name(x)) }
+  )
 
 }