| Paste number 37746: | scala object database |
| Pasted by: | yang |
| When: | 2 years, 3 months ago |
| Share: | Tweet this! | http://paste.lisp.org/+T4I |
| Channel: | None |
| Paste contents: |
import scala.collection.mutable._
/*object Uniq {
var x = 0
def next = {
x = x + 1
x - 1
}
}*/
case class Prop(typ: Type, default: Val, inv: Option[String])
abstract class Type
case class AnyT(t: Iterable[Type]) extends Type
case class SetT(t: Type) extends Type
case class StrT extends Type
case class ObjT(o: Obj) extends Type
// TODO clean up
object ValUtil {
def print(v: Val): String = v match {
case NilV() => "(nil)"
case SetV(s) => s map { x => print(x) } mkString("{ ", ", ", " }")
case StrV(s) => "\"" + s + "\""
case o@Obj() =>
"Obj( " + (o.parents map (.summary) mkString("parents{ ", "; ", " }")) + ";; " + (o.props map { case {name,prop} => name + " = " + printProp(prop) } mkString("props{ ", "; ", " }")) + ";; " + (o.vals map { case {name,value} => name + " = " + printSumm(value) } mkString("vals{ ", "; ", " }")) + " )"
}
def printSumm(v: Val): String = v match {
case NilV() => "(nil)"
case SetV(s) => s map { x => printSumm(x) } mkString("{ ", ", ", " }")
case StrV(s) => "\"" + s + "\""
case o@Obj() => o.summary
}
def printProp(p: Prop) = p match {
case Prop(typ, default, inv) => "Prop(typ: " + typ + ", default: " + printSumm(default) + ", inv: " + inv + ")"
}
}
import ValUtil._
class BadPropException(prop: String) extends Exception
abstract class Val
case class NilV extends Val
case class SetV(s: Set[Val]) extends Val
case class StrV(s: String) extends Val
case class Obj extends Val {
val parents: Set[Obj] = new HashSet()
val children: Set[Obj] = new HashSet()
val props: Map[String,Prop] = new HashMap()
val vals: Map[String,Val] = new HashMap()
// val id = Uniq.next
var isInst = false
override def hashCode = parents.hashCode
override def equals(any: Any) = any match {
case o@Obj() => this eq o
case _ => false
}
def summary = vals("names") match {
case SetV(s) => (s.toList)(0) match {
case StrV(s) => s
}
}
def derives(o: Obj): Boolean = o == this ||
parents.exists { p => o derives p }
//@ modifies: props
def addProp(name: String, typ: Type, default: Val): Unit =
props.update(name, Prop(typ, default, None))
//@ modifies: vals
def setProp(name: String, value: Val): Unit =
vals.update(name, value)
private def getRecur[A](name: String, acc: Obj => Map[String,A]): Option[A] =
acc(this) get name match {
case x@Some(_) => x
case None => {
val x = parents map ( .getRecur(name, acc) ) find { None != }
x match {
case Some(x) => x
case None => None
}
}
}
// gets the value, searching parents for the value or a default value
def getProp(name: String) = {
try { getRecur(name, .vals).get }
catch { case _ => throw new BadPropException(name) }
}
def infoProp(name: String) = {
try { getRecur(name, .props).get }
catch { case _ => throw new BadPropException(name) }
}
//@ invariants
def validate = {
Console.println("validating " + print(this)) // vals("names")))
val check: (Boolean, Any) => Unit = assert
def checkType(value: Val, typ: Type): Boolean =
{value, typ} match {
case {NilV(), _} => true
case {SetV(xs), SetT(t)} => xs forall { x => checkType(x,t) }
case {StrV(s), StrT()} => true
case {o@Obj(), ObjT(p)} => o derives p
case {x, AnyT(ts)} => ts exists { t => checkType(x,t) }
case _ => false
}
def checkRefShapes(value: Val, typ: Type, inv: Option[String]): Boolean =
{value, typ, inv} match {
// TODO hairy - should either restrict the shapes in the Type
// types, or think of changes to the system to allow for more
// expressive types
case {SetV(xs), SetT(ObjT(t)), Some(inv)} => xs forall {
case o@Obj() => o.vals(inv) match {
case SetV(refs) => refs contains this
case _ => false
}
case _ => false
}
case _ => true
}
// instances
check(children.size == 0 || !isInst, "failed instance-test")
// properties: types (for default and set values), bi-directionality
check(props forall {
case {name, prop@Prop(typ, default, inv)} =>
checkType(default, typ) && checkRefShapes(default, typ, inv) && {
// TODO the following is redundant with the value-check further down
// (should keep latter because all values have a prop but not all props have a value)
val optVal = vals get name
optVal == None || {
val value = optVal.get
checkType(value, typ) && checkRefShapes(value, typ, inv)
}}}, "properties don't hold")
// values: check that all the values exist in the props
def checkVal(value: Val, name: String, src: Obj): Boolean = {
Console println("resolving: value " + print(value) + " name " + name + " src " + print(src))
src.props get name match {
// TODO hairy, this is DFS; need to figure out a better way to
// resolve with parent(s), i.e. need to figure out where we're
// inheriting a certain property from
case None => src.parents exists { p => checkVal(value, name, p) }
case Some(Prop(typ, _, _)) => checkType(value, typ)
}
}
check(
vals forall { case {name, value} => checkVal(value, name, this) },
"values inconsistent")
// parent-child
check(children forall (.parents.contains(this)),
"not all children have me as parent")
check(parents forall (.children.contains(this)),
"not all parents have me as child")
}
}
object ObjUtils {
val objs = new HashSet[Obj]
def addRelProp(left: Obj, lname: String, ltyp: Type,
right: Obj, rname: String, rtyp: Type) = {
left.props.update(rname, Prop(SetT(rtyp), mkSetV(), Some(lname)))
right.props.update(lname, Prop(SetT(ltyp), mkSetV(), Some(rname)))
}
def addRel(lname: String, left: Obj, rname: String, right: Obj) = {
def addOneSide(o: Obj, name: String, other: Obj) = {
def getDef(o: Obj): Option[Val] = o.props get name match {
case Some(prop) => Some(prop.default)
case None => getDef( (o.parents find { p => getDef(p) != None }).get )
}
o.vals get name match {
case None => getDef(o).get match {
case SetV(s) => o.vals(name) = mkSetV(s)
case _ => assert(false)
}
}
o.vals get name match {
case Some(x) => x match {
case SetV(s) => s + other
case _ => assert(false)
}
case _ => assert(false)
}
}
addOneSide(left, rname, right)
if (left ne right) addOneSide(right, lname, left)
}
def mkObj(parents: Iterable[Obj]) = {
val obj = Obj
// parent-child
obj.parents ++= parents
parents foreach { p => p.children += obj }
// global set
objs += obj
// return
obj
}
def validateAll = objs foreach (.validate)
def mkSetV(xs: Val*): SetV = mkSetV(xs)
def mkSetV(xs: Iterable[Val]) = {
val set = new HashSet[Val]()
set ++= xs
SetV(set)
}
def getObj(name: String) = objs.find( .getProp("names").asInstanceOf[SetV].s.contains(StrV(name)) ).get
/*
def query(name: String, names: String*): Val = {
val init = objs.find(name==).get
(names foldLeft init) {
value, name => value match {
case obj@Obj() => obj.getProp(name)
case SetV(s) => throw new BadQueryException(
"property " + name + " not found"
)
}
}
}
*/
def dump(any: Any): String = any match {
case NilV() = "NilV()"
case SetV(s) = "SetV(" + dump(s) + ")"
case StrV(s) = "StrV(" + dump(s) + ")"
case s:Set(xs: _*) =
}
/*
def dump(v: Val) = v match {
}
*/
/* def pickleNilV: SPU[NilV] = wrap(
NilV,
(v: Val) => v match { case NilV() => () },
string
)
def pickleSetV: SPU[SetV] = wrap(
SetV,
(v: Val) => v match { case SetV(s) => s },
string
)
def pickleVal: SPU[Val] = data(
(v: Val) => v match {
case NilV() => 0
case SetV(_) => 1
case StrV(_) => 2
case Obj() => 3
},
List(() => pickleNilV,
() => pickleSetV,
() => pickleStrV,
() => pickleObj)
)*/
}
import ObjUtils._
class BadTypeException extends Exception
class BadValueException extends Exception
object ObjUser {
def mkInst(newNames: String*)(srcNames: String*) = {
val obj = mkObj(Set(srcNames map getObj: _*))
obj.setProp("names", mkSetV(newNames map StrV))
obj.isInst = true
obj
}
def prop(objName: String, propName: String, propType: String, default: Option[String]) = {
val obj = getObj(objName)
propType match {
case "string set" => obj.addProp(
propName, SetT(StrT),
default match {
case None => NilV
case Some(s) => SetV(Set(StrV(s)))
}
)
case "string" => obj.addProp(
propName, StrT,
default match {
case None => NilV
case Some(s) => StrV(s)
}
)
case _ => throw new BadTypeException()
}
}
def set(objName: String, propName: String, value: String) = {
val obj = getObj(objName)
val v = obj.infoProp(propName).typ match {
case StrT() => StrV(value)
case SetT(StrT()) => mkSetV(StrV(value))
case _ => throw new BadValueException()
}
obj.setProp(propName, v)
}
def mirror(objName: String, relName: String) = {
val obj = getObj(objName)
addRelProp(obj, relName, ObjT(obj),
obj, relName, ObjT(obj))
}
def setMirror(objName1: String, relName: String, objName2: String) = {
val {obj1, obj2} = {getObj(objName1), getObj(objName2)}
addRel(relName, obj1, relName, obj2)
}
def get(objName: String) = getObj(objName)
def get(objName: String, propName: String) =
getObj(objName).getProp(propName)
}
import ObjUser._
object Main {
def fakeUser = {
mkInst("Yang Zhang")("person")
prop("person", "mobile phones", "string set", None)
prop("person", "websites", "string set", None)
set("Yang Zhang", "mobile phones", "123 456 7890")
set("Yang Zhang", "websites", "http://mysite/")
mkInst("Pawan Deshpande")("person")
// set("Pawan Deshpande", "mobile phone", "234 456 6789")
// set("Pawan Deshpande", "website", "234 456 6789")
mirror("person", "roommates")
setMirror("Yang Zhang", "roommates", "Pawan Deshpande")
Console println printSumm(get("Yang Zhang", "roommates"))
Console println printSumm(get("Yang Zhang", "mobile phones"))
Console println printSumm(get("Yang Zhang", "websites"))
Console println print(get("Yang Zhang"))
}
def main(args: Array[String]): Unit = {
val concept = mkObj(Set())
concept.addProp("names", SetT(StrT), NilV)
concept.setProp("names", mkSetV(StrV("concept")))
val sw = mkObj(Set(concept))
sw setProp("names", mkSetV(StrV("software")))
addRelProp(sw, "platforms", ObjT(sw),
sw, "hosted software", ObjT(sw))
val lisp = mkObj(Set(sw))
lisp.isInst = true
lisp.setProp("names", mkSetV(StrV("Common Lisp")))
val person = mkObj(Set(concept))
person.setProp("names", mkSetV(StrV("person")))
val mccarthy = mkObj(Set(person))
mccarthy.isInst = true
mccarthy.setProp("names", mkSetV(StrV("mccarthy")))
addRelProp(sw, "software", ObjT(sw),
person, "people", ObjT(person))
addRel("software", lisp, "people", mccarthy)
// query("mccarthy", "software", "lisp", "people")
fakeUser
validateAll
Console println "done!"
}
}This paste has no annotations.