+ SQL literals\n~ simplifed SPARQL parser
authorEric Prud'hommeaux <bertails@w3.org>
Wed, 30 Dec 2009 21:16:35 -0500
changeset 93 605ea99957be
parent 92 4d637705cfb5
child 94 641948632f5f
+ SQL literals\n~ simplifed SPARQL parser
src/main/scala/SPARQL.scala
src/main/scala/SQL.scala
src/test/scala/SQLTest.scala
src/test/scala/SparqlTest.scala
--- a/src/main/scala/SPARQL.scala	Wed Dec 30 11:57:13 2009 -0500
+++ b/src/main/scala/SPARQL.scala	Wed Dec 30 21:16:35 2009 -0500
@@ -17,7 +17,6 @@
 
 sealed abstract class GraphPattern
 case class TriplesBlock(triplepatterns:List[TriplePattern]) extends GraphPattern
-case class EmptyGraphPattern() extends GraphPattern
 case class TableConjunction(gps:List[GraphPattern]) extends GraphPattern
 case class TableDisjunction(gps:List[GraphPattern]) extends GraphPattern
 case class TableFilter(gp:GraphPattern, expr:SparqlExpression) extends GraphPattern
@@ -96,24 +95,35 @@
     "{" ~ opt(triplesblock) ~ rep(graphpatternnottriplesORfilter ~ opt(triplesblock)) ~ "}" ^^
     {
       case "{"~tbOPT~gpntORf_tbOPT~"}" => {
-	var init = tbOPT match {
-	  case Some(x) => x
-	  case _ => EmptyGraphPattern()
-	}
+
+// case class TriplesBlock(triplepatterns:List[TriplePattern]) extends GraphPattern
+// case class TableConjunction(gps:List[GraphPattern]) extends GraphPattern
+// case class TableDisjunction(gps:List[GraphPattern]) extends GraphPattern
+// case class TableFilter(gp:GraphPattern, expr:SparqlExpression) extends GraphPattern
+// case class OptionalGraphPattern(gp:GraphPattern) extends GraphPattern
+// case class GraphGraphPattern(gp:GraphPattern) extends GraphPattern
+
 	// println("groupgraphpattern: " + tbOPT + " " + gpntORf_tbOPT)
-	gpntORf_tbOPT.foldLeft(init)((gp, lentry) => lentry match {
-	  case ~(TableFilter(null, expr), None) => TableFilter(gp, expr)
-	  case ~(TriplesBlock(triples), None) => gp match {
-	    case EmptyGraphPattern() => TriplesBlock(triples)
-	    case TriplesBlock(triples2) => TableConjunction(List(gp, TriplesBlock(triples2)))
-	  }
-	  case ~(TableDisjunction(list), None) => gp match {
-	    case EmptyGraphPattern() => TableDisjunction(list)
-	    case x => TableConjunction(List(gp, TableDisjunction(list)))
-	  }
-	  case ~(OptionalGraphPattern(gp2), None) => TableConjunction(List(gp, OptionalGraphPattern(gp2)))
+	val init:Option[GraphPattern] = tbOPT
+	gpntORf_tbOPT.foldLeft(init)((gp, lentry) => {//println("match: " + (gp, lentry))
+(gp, lentry) match {
+	  case (Some(TriplesBlock(l)), ~(TableFilter(null, expr), None                 )) => Some(TableFilter(TriplesBlock(l), expr))
+	  case (None,                  ~(TableFilter(null, expr), Some(TriplesBlock(r)))) => Some(TableFilter(TriplesBlock(r), expr))
+	  case (Some(TriplesBlock(l)), ~(TableFilter(null, expr), Some(TriplesBlock(r)))) => Some(TableFilter(TriplesBlock(l ++ r), expr))
+	  case (Some(TableFilter(TriplesBlock(l), SparqlExpression(lexp))), ~(TableFilter(null, SparqlExpression(expr)), Some(TriplesBlock(r)))) => Some(TableFilter(TriplesBlock(l ++ r), SparqlExpression(lexp ++ expr)))
+
+	  // case (None,     ~(TableConjunction(gps), None    )) => TableConjunction(gps)
+	  // case (Some(gp), ~(TableConjunction(gps), None    )) => TableConjunction(List(List(gp) ++ gps))
+	  // case (None,     ~(TableConjunction(gps), Some(tb))) => TableConjunction(List(gps ++ List(tb)))
+	  // case (Some(gp), ~(TableConjunction(gps), Some(tb))) => TableConjunction(List(List(gp) ++ gps ++ List(tb)))
+
+	  case (None,     ~(x, None    )) => Some(x                                )
+	  case (Some(gp), ~(x, None    )) => Some(TableConjunction(List(gp, x    )))
+	  case (None,     ~(x, Some(tb))) => Some(TableConjunction(List(    x, tb)))
+	  case (Some(gp), ~(x, Some(tb))) => Some(TableConjunction(List(gp, x, tb)))
+
 	  case x => error("found " + x)
-	})
+	}}).get
       }
     }
   )
--- a/src/main/scala/SQL.scala	Wed Dec 30 11:57:13 2009 -0500
+++ b/src/main/scala/SQL.scala	Wed Dec 30 21:16:35 2009 -0500
@@ -1,6 +1,16 @@
 package w3c.sw
 
 import scala.util.parsing.combinator._
+
+object SQLParsers extends RegexParsers {
+
+  val int = """[0-9]+""".r
+  val chars = "\"[^\"]*\"".r
+}
+
+import SQLParsers._
+
+import scala.util.parsing.combinator._
 import java.net.URI
 
 case class Union(disjoints:Set[Select]) {
@@ -13,13 +23,25 @@
   // foo, bar
   override def toString = "SELECT "+(attributes mkString (",\n       "))
 }
-case class NamedAttribute(fqattribute:RelAliasAttribute, attralias:AttrAlias) {
-  override def toString = fqattribute + " AS " + attralias
+case class NamedAttribute(value:RelAliasAttributeORConst, attralias:AttrAlias) {
+  override def toString = value + " AS " + attralias
 }
 //case class RelAttribute(relation:Relation, attribute:Attribute) c.f. ForeignKey
-case class RelAliasAttribute(relalias:RelAlias, attribute:Attribute) {
+sealed abstract class RelAliasAttributeORConst
+case class RelAliasAttribute(relalias:RelAlias, attribute:Attribute) extends RelAliasAttributeORConst {
   override def toString = relalias + "." + attribute
 }
+sealed abstract class Const  extends RelAliasAttributeORConst
+case class ConstNULL() extends Const {
+  override def toString = "NULL"
+}
+case class ConstInt(i:String) extends Const {
+  override def toString = "" + i
+}
+case class ConstChars(s:String) extends Const {
+  override def toString = "\"" + s + "\""
+}
+
 case class Attribute(n:Name) {
   override def toString = n.s /* "'" + n.s + "'" */
 }
@@ -108,14 +130,25 @@
     repsep(namedattribute, ",") ^^ { l => AttributeList(l.toSet) }
 
   def namedattribute:Parser[NamedAttribute] =
-    fqattribute ~ "AS" ~ attralias ^^
-    { case fqattribute ~ "AS" ~ attralias =>
-      NamedAttribute(fqattribute, attralias) }
+    fqattributeORconst ~ "AS" ~ attralias ^^
+    { case fqattributeORconst ~ "AS" ~ attralias =>
+      NamedAttribute(fqattributeORconst, attralias) }
+
+  def fqattributeORconst:Parser[RelAliasAttributeORConst] = (
+      fqattribute ^^ { case fqattribute => fqattribute }
+    | const ^^ { case const => const }
+  )
 
   def fqattribute:Parser[RelAliasAttribute] =
     relalias ~ "." ~ attribute ^^
     { case relalias ~ "." ~ attribute => RelAliasAttribute(relalias, attribute) }
 
+  def const:Parser[Const] = (
+      "NULL" ^^ { case "NULL" => ConstNULL() }
+    | int ^^ { case i => ConstInt(i) }
+    | chars ^^ { case ch => ConstChars(ch) }
+  )
+
   def attribute:Parser[Attribute] =
     """[a-zA-Z_]\w*""".r ^^ { x => Attribute(Name(x)) }
 
--- a/src/test/scala/SQLTest.scala	Wed Dec 30 11:57:13 2009 -0500
+++ b/src/test/scala/SQLTest.scala	Wed Dec 30 21:16:35 2009 -0500
@@ -161,4 +161,23 @@
     assert(expected === (a.parseAll(a.select, e).get))
   }
 
+  test("parse NULL as A_foo") {
+    // AliasedResource(Relation(Name("Employee")),RelAlias(Name("R_emp")))
+    val a = Sql()
+    val e = """
+SELECT R_above.manages AS A_who, NULL AS A_bday
+                FROM Manage AS R_above
+          WHERE R_above.id IS NOT NULL
+"""
+    val expected = Select(AttributeList(Set(NamedAttribute(RelAliasAttribute(RelAlias(Name("R_above")),
+									      Attribute(Name("manages"))),
+							    AttrAlias(Name("A_who"))),
+					     NamedAttribute(ConstNULL(),
+							    AttrAlias(Name("A_bday"))))),
+			  TableList(Set(AliasedResource(Relation(Name("Manage")),RelAlias(Name("R_above"))))),
+			  Expression(Set(
+			    PrimaryExpressionNotNull(RelAliasAttribute(RelAlias(Name("R_above")),Attribute(Name("id")))))))
+    assert(expected === (a.parseAll(a.select, e).get))
+  }
+
 }
--- a/src/test/scala/SparqlTest.scala	Wed Dec 30 11:57:13 2009 -0500
+++ b/src/test/scala/SparqlTest.scala	Wed Dec 30 21:16:35 2009 -0500
@@ -283,15 +283,13 @@
     val tps =
       SparqlSelect(
 	SparqlAttributeList(List(Var("x"))),
-	TableConjunction(List(
-	  EmptyGraphPattern(),
-	  OptionalGraphPattern(
-	    TriplesBlock(
-	      List(
-		TriplePattern(
-		  SVar(Var("x")),
-		  PUri(Stem("http://hr.example/DB"),Rel("Employee"),Attr("manager")),
-		  OVar(Var("y")))))))))
+	OptionalGraphPattern(
+	  TriplesBlock(
+	    List(
+	      TriplePattern(
+		SVar(Var("x")),
+		PUri(Stem("http://hr.example/DB"),Rel("Employee"),Attr("manager")),
+		OVar(Var("y")))))))
     assert(tps === a.parseAll(a.select, e).get)
   }