Commit 13f32f76 authored by Christian Müller's avatar Christian Müller

add type inference

parent a6dfb491
...@@ -39,7 +39,7 @@ object ExampleWorkflows extends LazyLogging { ...@@ -39,7 +39,7 @@ object ExampleWorkflows extends LazyLogging {
logger.error(s"Parsing of $f unsuccessful: $spec") logger.error(s"Parsing of $f unsuccessful: $spec")
None None
} else { } else {
if (!spec.get.checkSanity()) { if (!spec.get.isSane()) {
logger.error(s"Sanity check of $f failed. Skipping file.") logger.error(s"Sanity check of $f failed. Skipping file.")
None None
} else { } else {
...@@ -60,7 +60,7 @@ object ExampleWorkflows extends LazyLogging { ...@@ -60,7 +60,7 @@ object ExampleWorkflows extends LazyLogging {
logger.error(s"Parsing of $f unsuccessful: $spec") logger.error(s"Parsing of $f unsuccessful: $spec")
name -> None name -> None
} else { } else {
if (!spec.get.checkSanity()) { if (!spec.get.isSane()) {
logger.error(s"Sanity check of $f failed. Skipping file.") logger.error(s"Sanity check of $f failed. Skipping file.")
name -> None name -> None
} else { } else {
......
...@@ -44,7 +44,7 @@ object InvariantCLI extends App with LazyLogging { ...@@ -44,7 +44,7 @@ object InvariantCLI extends App with LazyLogging {
logger.error(s"Parsing of $file unsuccessful: $spec") logger.error(s"Parsing of $file unsuccessful: $spec")
None None
} else { } else {
if (!spec.get.checkSanity()) { if (!spec.get.isSane()) {
logger.error(s"Sanity check of $file failed. Skipping file.") logger.error(s"Sanity check of $file failed. Skipping file.")
None None
} else { } else {
......
...@@ -33,7 +33,7 @@ object LTLCLI extends App with LazyLogging { ...@@ -33,7 +33,7 @@ object LTLCLI extends App with LazyLogging {
logger.error(s"Parsing of $file unsuccessful: $spec") logger.error(s"Parsing of $file unsuccessful: $spec")
None None
} else { } else {
if (!spec.get.checkSanity()) { if (!spec.get.isSane()) {
logger.error(s"Sanity check of $file failed. Skipping file.") logger.error(s"Sanity check of $file failed. Skipping file.")
None None
} else { } else {
......
...@@ -3,6 +3,7 @@ package de.tum.niwo.blocks; ...@@ -3,6 +3,7 @@ package de.tum.niwo.blocks;
import de.tum.niwo.Utils import de.tum.niwo.Utils
import de.tum.niwo.foltl.FOLTL._ import de.tum.niwo.foltl.FOLTL._
import de.tum.niwo.foltl.Properties import de.tum.niwo.foltl.Properties
import de.tum.niwo.parser.ParserUtils
case class Signature(as: Set[Fun], constas: Set[Fun], bs: Set[Fun], preds: Set[Fun], constants: Set[Var]) case class Signature(as: Set[Fun], constas: Set[Fun], bs: Set[Fun], preds: Set[Fun], constants: Set[Var])
object Signature { object Signature {
...@@ -11,6 +12,15 @@ object Signature { ...@@ -11,6 +12,15 @@ object Signature {
case class TransitionSystem(sig: Signature, steps: List[TSBlock]) { case class TransitionSystem(sig: Signature, steps: List[TSBlock]) {
override def toString: String = steps.mkString("\n") override def toString: String = steps.mkString("\n")
def isSane() = {
// check that the steps fit the signature
val uses = ParserUtils.allpredicates(steps)
val sanesteps = ParserUtils.checkSig(uses)
true
}
} }
object TransitionSystem { object TransitionSystem {
val EMPTY = TransitionSystem(Signature.EMPTY, List()) val EMPTY = TransitionSystem(Signature.EMPTY, List())
...@@ -36,29 +46,24 @@ object InvariantSpec { ...@@ -36,29 +46,24 @@ object InvariantSpec {
} }
abstract class Statement { abstract class Statement {
type This >: this.type <: Statement
def guard: Formula def guard: Formula
def fun: String def fun: String
def tuple: List[Var] def tuple: List[Var]
def update(guard: Formula = guard, fun: String = fun, tuple: List[Var] = tuple): This def update(guard: Formula = guard, fun: String = fun, tuple: List[Var] = tuple): this.type
lazy val freeVars: Set[Var] = guard.freeVars ++ tuple lazy val freeVars: Set[Var] = guard.freeVars ++ tuple
} }
case class Add(guard: Formula, fun: String, tuple: List[Var]) extends Statement { case class Add(guard: Formula, fun: String, tuple: List[Var]) extends Statement {
type This = Add
override def toString: String = guard + " → " + fun + " += " + tuple.mkString("(", ",", ")") + ";" override def toString: String = guard + " → " + fun + " += " + tuple.mkString("(", ",", ")") + ";"
override def update(guard: Formula = guard, fun: String = fun, tuple: List[Var] = tuple) = Add(guard, fun, tuple) override def update(guard: Formula = guard, fun: String = fun, tuple: List[Var] = tuple) = Add(guard, fun, tuple)
} }
case class Remove(guard: Formula, fun: String, tuple: List[Var]) extends Statement { case class Remove(guard: Formula, fun: String, tuple: List[Var]) extends Statement {
type This = Remove
override def toString: String = guard + " → " + fun + " -= " + tuple.mkString("(", ",", ")") + ";" override def toString: String = guard + " → " + fun + " -= " + tuple.mkString("(", ",", ")") + ";"
override def update(guard: Formula = guard, fun: String = fun, tuple: List[Var] = tuple) = Remove(guard, fun, tuple) override def update(guard: Formula = guard, fun: String = fun, tuple: List[Var] = tuple) = Remove(guard, fun, tuple)
} }
case class SetStmt(guard:Formula, fun:String, tuple: List[Var]) extends Statement { case class SetStmt(guard:Formula, fun:String, tuple: List[Var]) extends Statement {
type This = SetStmt
override def toString: String = guard + " → " + fun + " := " + tuple.mkString("(", ",", ")") + ";" override def toString: String = guard + " → " + fun + " := " + tuple.mkString("(", ",", ")") + ";"
override def update(guard: Formula = guard, fun: String = fun, tuple: List[Var] = tuple) = SetStmt(guard, fun, tuple) override def update(guard: Formula = guard, fun: String = fun, tuple: List[Var] = tuple) = SetStmt(guard, fun, tuple)
} }
......
...@@ -35,7 +35,7 @@ case class NISpec(w: Workflow, declass: Map[String, (List[Var], Formula)], axiom ...@@ -35,7 +35,7 @@ case class NISpec(w: Workflow, declass: Map[String, (List[Var], Formula)], axiom
// TODO: How to check for more constants? // TODO: How to check for more constants?
} }
def checkSanity(): Boolean = { def isSane(): Boolean = {
var sane = true var sane = true
// TODO: check all types // TODO: check all types
......
...@@ -3,28 +3,47 @@ package de.tum.niwo.parser ...@@ -3,28 +3,47 @@ package de.tum.niwo.parser
import com.typesafe.scalalogging.LazyLogging import com.typesafe.scalalogging.LazyLogging
import de.tum.niwo.blocks._ import de.tum.niwo.blocks._
import de.tum.niwo.foltl.FOLTL._ import de.tum.niwo.foltl.FOLTL._
import de.tum.niwo.parser.WorkflowParser.inferType
import scala.util.parsing.combinator.{PackratParsers, RegexParsers} import scala.util.parsing.combinator.{PackratParsers, RegexParsers}
trait ParserUtils extends LazyLogging { object ParserUtils extends LazyLogging {
def checkSig(preds: List[Fun]) = { def checkSig(sig:Signature, preds: List[Fun]) = {
val sigtypes = (sig.constas ++ sig.as ++ sig.bs ++ sig.preds) map
(f => f.name -> f.params.map(_.typ)) toMap
val consttypes = sig.constants.map(c => c.name -> c.typ).toMap
// Filter to just the first // Filter to just the first
val grouped = preds groupBy (_.name) val grouped = preds groupBy (_.name)
// Check arities // Check arities and types
val checks = for ((k, list) <- grouped) yield { val checks = for ((k, list) <- grouped) yield {
val sizes = list map (_.params.size) val sigtype = sigtypes(k)
// all equal val variables = list.map(_.params)
(k, sizes.distinct.size == 1) val types = variables.map(_.map(_.typ))
} val checkTypes = types.forall(_ == sigtype)
if (!checkTypes) {
logger.error(s"Predicate $k appears with conflicting arities or types")
}
val invalidConstants = for (
list <- variables;
v <- list
if consttypes.isDefinedAt(v.name)
if consttypes(v.name) != v.typ
) yield {
v
}
for ((k, valid) <- checks) { if (invalidConstants.nonEmpty) {
if (!valid) { logger.error(s"Constant use with wrong type found: $invalidConstants")
logger.error(s"Predicate $k appears with conflicting arities")
} }
// all equal
(k, checkTypes && invalidConstants.isEmpty)
} }
// all valid? // all valid?
...@@ -78,12 +97,7 @@ trait ParserUtils extends LazyLogging { ...@@ -78,12 +97,7 @@ trait ParserUtils extends LazyLogging {
}) })
val newtup = stmt.tuple.map (inferType(typemap, _)) val newtup = stmt.tuple.map (inferType(typemap, _))
// TODO this could be improved stmt.update(newguard, stmt.fun, newtup)
stmt match {
case s:Add => Add(newguard, stmt.fun, newtup)
case s:Remove => Remove(newguard, stmt.fun, newtup)
case s:SetStmt => SetStmt(newguard, stmt.fun, newtup)
}
} }
// TS Type inference // TS Type inference
...@@ -91,24 +105,6 @@ trait ParserUtils extends LazyLogging { ...@@ -91,24 +105,6 @@ trait ParserUtils extends LazyLogging {
typedpreds.map(v => v.name -> v.params.map(_.typ)).toMap typedpreds.map(v => v.name -> v.params.map(_.typ)).toMap
} }
def mapStatements(block:Block, pf:T => T) = {
block match {
case sim:SimpleBlock => {
val newsteps = sim.steps.map(pf(_))
sim.update(newsteps)
}
case l:Loop => {
val newsteps = l.steps.map(inferTypeFromSig(sig, _))
l.update(newsteps)
}
case c:NondetChoice => {
val left = c.left.map(inferTypeFromSig(sig, _))
val right = c.right.map(inferTypeFromSig(sig, _))
c.update(left, right)
}
}
}
def inferTypeFromSig[B <: Block](sig:Signature, block:B): B = { def inferTypeFromSig[B <: Block](sig:Signature, block:B): B = {
block match { block match {
case sim:SimpleBlock => { case sim:SimpleBlock => {
......
...@@ -3,12 +3,12 @@ package de.tum.niwo.parser ...@@ -3,12 +3,12 @@ package de.tum.niwo.parser
import com.typesafe.scalalogging.LazyLogging import com.typesafe.scalalogging.LazyLogging
import de.tum.niwo.blocks._ import de.tum.niwo.blocks._
import de.tum.niwo.foltl.FOLTL._ import de.tum.niwo.foltl.FOLTL._
import de.tum.niwo.parser.WorkflowParser.{SPEC, parseAll} import ParserUtils._
import scala.util.parsing.combinator.{PackratParsers, RegexParsers} import scala.util.parsing.combinator.{PackratParsers, RegexParsers}
object TransitionSystemParser extends RegexParsers object TransitionSystemParser extends RegexParsers
with PackratParsers with FormulaParser with ParserUtils with LazyLogging { with PackratParsers with FormulaParser with LazyLogging {
private def BLOCKLIST:Parser[List[TSBlock]] = (BLOCK | LOOP | NDCHOICE)+ private def BLOCKLIST:Parser[List[TSBlock]] = (BLOCK | LOOP | NDCHOICE)+
private def LOOP: Parser[TSLoop] = "loop" ~> "{" ~> BLOCKLIST <~ "}" ^^ (bs => TSLoop(bs)) private def LOOP: Parser[TSLoop] = "loop" ~> "{" ~> BLOCKLIST <~ "}" ^^ (bs => TSLoop(bs))
...@@ -42,11 +42,17 @@ object TransitionSystemParser extends RegexParsers ...@@ -42,11 +42,17 @@ object TransitionSystemParser extends RegexParsers
("Signature" ~> SIG) ~ ("Signature" ~> SIG) ~
("Transition System" ~> BLOCKLIST) ~ ("Transition System" ~> BLOCKLIST) ~
(("Axioms" ~> repsep(TERM, ","))?) ~ (("Axioms" ~> repsep(TERM, ","))?) ~
("Invariant" ~> repsep(TERM, ",")) ^^ { ("Invariant" ~> repsep(TERM, ",")) ^? {
case sig ~ ts ~ axioms ~ invariants => { case sig ~ blocks ~ axioms ~ invariants if {
val infered = blocks.map(ParserUtils.inferTypeFromSig(sig, _))
val predicates = allpredicates(infered)
checkSig(sig, predicates)
} => {
val axiomlist = if (axioms.isDefined) axioms.get else List() val axiomlist = if (axioms.isDefined) axioms.get else List()
val infered = blocks.map(ParserUtils.inferTypeFromSig(sig, _))
val ts = TransitionSystem(sig, infered)
InvariantSpec( InvariantSpec(
TransitionSystem(sig, ts), And.make(axiomlist), And.make(invariants) ts, And.make(axiomlist), And.make(invariants)
) )
} }
} }
......
...@@ -3,6 +3,7 @@ package de.tum.niwo.parser ...@@ -3,6 +3,7 @@ package de.tum.niwo.parser
import com.typesafe.scalalogging.LazyLogging import com.typesafe.scalalogging.LazyLogging
import de.tum.niwo.blocks._ import de.tum.niwo.blocks._
import de.tum.niwo.foltl.FOLTL._ import de.tum.niwo.foltl.FOLTL._
import ParserUtils._
import scala.util.parsing.combinator._ import scala.util.parsing.combinator._
...@@ -42,8 +43,10 @@ object WorkflowParser extends RegexParsers with PackratParsers with ParserUtils ...@@ -42,8 +43,10 @@ object WorkflowParser extends RegexParsers with PackratParsers with ParserUtils
distinct && unbound.isEmpty distinct && unbound.isEmpty
} }
private def ADD: Parser[Add] = TERM ~ ("→" | "->") ~ VAR ~ "+=" ~ TUPLE ^^ { case guard ~ _ ~ fun ~ _ ~ tup => Add(guard, fun.name, tup) } private def ADD: Parser[Add] = TERM ~ ("→" | "->") ~ VAR ~ "+=" ~ TUPLE ^^ {
private def REM: Parser[Remove] = TERM ~ ("→" | "->") ~ VAR ~ "-=" ~ TUPLE ^^ { case guard ~ _ ~ fun ~ _ ~ tup => Remove(guard, fun.name, tup) } case guard ~ _ ~ fun ~ _ ~ tup => Add(guard, fun.name, tup) }
private def REM: Parser[Remove] = TERM ~ ("→" | "->") ~ VAR ~ "-=" ~ TUPLE ^^ {
case guard ~ _ ~ fun ~ _ ~ tup => Remove(guard, fun.name, tup) }
private def STMT: Parser[Statement] = ADD | REM private def STMT: Parser[Statement] = ADD | REM
...@@ -69,9 +72,16 @@ object WorkflowParser extends RegexParsers with PackratParsers with ParserUtils ...@@ -69,9 +72,16 @@ object WorkflowParser extends RegexParsers with PackratParsers with ParserUtils
private def BLOCKLIST: Parser[List[WFBlock]] = (BLOCK | LOOP | NDCHOICE)+ private def BLOCKLIST: Parser[List[WFBlock]] = (BLOCK | LOOP | NDCHOICE)+
private def WORKFLOW: Parser[Workflow] = BLOCKLIST ^? { private def WORKFLOW: Parser[Workflow] = BLOCKLIST ^? {
case blocks if checkSig(allpredicates(blocks)) => { case blocks if {
val choiceblocks = addChoicePredicates(blocks) val choiceblocks = addChoicePredicates(blocks)
Workflow(buildSig(allpredicates(choiceblocks)), choiceblocks) val predicates = allpredicates(choiceblocks)
val sig = buildSig(predicates)
checkSig(sig, predicates)
} => {
val choiceblocks = addChoicePredicates(blocks)
val predicates = allpredicates(choiceblocks)
val sig = buildSig(predicates)
Workflow(sig, choiceblocks)
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment