diff --git a/k-distribution/tests/builtins/collections/test-set2list-2.col.out b/k-distribution/tests/builtins/collections/test-set2list-2.col.out
index e698f880343..ff7f12e8d9b 100644
--- a/k-distribution/tests/builtins/collections/test-set2list-2.col.out
+++ b/k-distribution/tests/builtins/collections/test-set2list-2.col.out
@@ -1,6 +1,6 @@
- ListItem ( 4 )
- ListItem ( 3 )
+ ListItem ( 1 )
ListItem ( 2 )
- ListItem ( 1 ) ~> .
+ ListItem ( 3 )
+ ListItem ( 4 ) ~> .
diff --git a/k-distribution/tests/builtins/collections/test-set2list-3.col.out b/k-distribution/tests/builtins/collections/test-set2list-3.col.out
index 42af7fc9c87..af1ebe42178 100644
--- a/k-distribution/tests/builtins/collections/test-set2list-3.col.out
+++ b/k-distribution/tests/builtins/collections/test-set2list-3.col.out
@@ -1,5 +1,5 @@
- ListItem ( 4 )
+ ListItem ( 1 )
ListItem ( 3 )
- ListItem ( 1 ) ~> .
+ ListItem ( 4 ) ~> .
diff --git a/kore/src/main/scala/org/kframework/attributes/Att.scala b/kore/src/main/scala/org/kframework/attributes/Att.scala
index f882997bd1e..d3c3685d33f 100644
--- a/kore/src/main/scala/org/kframework/attributes/Att.scala
+++ b/kore/src/main/scala/org/kframework/attributes/Att.scala
@@ -414,6 +414,11 @@ object Att {
val attMap = union.groupBy({ case ((name, _), _) => name})
Att(union.filter { key => attMap(key._1._1).size == 1 }.toMap)
}
+
+ implicit val ord: Ordering[Att] = {
+ import scala.math.Ordering.Implicits._
+ Ordering.by[Att, Seq[(String, String, String)]](att => att.att.iterator.map(k => (k._1._1.key, k._1._2, k._2.toString)).toSeq.sorted)
+ }
}
trait AttributesToString {
diff --git a/kore/src/main/scala/org/kframework/definition/outer.scala b/kore/src/main/scala/org/kframework/definition/outer.scala
index 127bb54694c..6931bc8914b 100644
--- a/kore/src/main/scala/org/kframework/definition/outer.scala
+++ b/kore/src/main/scala/org/kframework/definition/outer.scala
@@ -414,18 +414,66 @@ trait Sentence extends HasLocation with HasAtt with AttValue {
def label: Optional[String] = att.getOptional(Att.LABEL)
}
+object Sentence {
+ implicit val ord = new Ordering[Sentence] {
+ def compare(a: Sentence, b: Sentence): Int = {
+ (a, b) match {
+ case (c:SyntaxSort, d:SyntaxSort) => Ordering[SyntaxSort].compare(c, d)
+ case (c:SortSynonym, d:SortSynonym) => Ordering[SortSynonym].compare(c, d)
+ case (c:SyntaxLexical, d:SyntaxLexical) => Ordering[SyntaxLexical].compare(c, d)
+ case (c:Production, d:Production) => Ordering[Production].compare(c, d)
+ case (c:SyntaxAssociativity, d:SyntaxAssociativity) => Ordering[SyntaxAssociativity].compare(c, d)
+ case (c:SyntaxPriority, d:SyntaxPriority) => Ordering[SyntaxPriority].compare(c, d)
+ case (c:ContextAlias, d:ContextAlias) => Ordering[ContextAlias].compare(c, d)
+ case (c:Context, d:Context) => Ordering[Context].compare(c, d)
+ case (c:Rule, d:Rule) => Ordering[Rule].compare(c, d)
+ case (c:Claim, d:Claim) => Ordering[Claim].compare(c, d)
+ case (_:SyntaxSort, _) => -1
+ case (_, _:SyntaxSort) => 1
+ case (_:SortSynonym, _) => -1
+ case (_, _:SortSynonym) => 1
+ case (_:SyntaxLexical, _) => -1
+ case (_, _:SyntaxLexical) => 1
+ case (_:Production, _) => -1
+ case (_, _:Production) => 1
+ case (_:SyntaxAssociativity, _) => -1
+ case (_, _:SyntaxAssociativity) => 1
+ case (_:SyntaxPriority, _) => -1
+ case (_, _:SyntaxPriority) => 1
+ case (_:ContextAlias, _) => -1
+ case (_, _:ContextAlias) => 1
+ case (_:Context, _) => -1
+ case (_, _:Context) => 1
+ case (_:Rule, _) => -1
+ case (_, _:Rule) => 1
+ case (_:Claim, _) => -1
+ case (_, _:Claim) => 1
+ case (_, _) => throw KEMException.internalError("Cannot order these sentences:\n" + a.toString() + "\n" + b.toString())
+ }
+ }
+ }
+}
+
// deprecated
case class Context(body: K, requires: K, att: Att = Att.empty) extends Sentence with OuterKORE with ContextToString {
override val isSyntax = false
override val isNonSyntax = true
override def withAtt(att: Att) = Context(body, requires, att)
}
+object Context {
+ implicit val ord: Ordering[Context] = Ordering.by[Context, (K, K, Att)](s => (s.body, s.requires, s.att))
+}
case class ContextAlias(body: K, requires: K, att: Att = Att.empty) extends Sentence with OuterKORE with ContextAliasToString {
override val isSyntax = true
override val isNonSyntax = false
override def withAtt(att: Att) = ContextAlias(body, requires, att)
}
+object ContextAlias {
+ implicit val ord: Ordering[ContextAlias] = {
+ Ordering.by[ContextAlias, (K, K, Att)](s => (s.body, s.requires, s.att))
+ }
+}
abstract class RuleOrClaim extends Sentence {
def body: K
@@ -441,6 +489,11 @@ case class Claim(body: K, requires: K, ensures: K, att: Att = Att.empty) extends
override def newInstance(body: K, requires: K, ensures: K, att: Att = Att.empty): Claim =
Claim(body, requires, ensures, att)
}
+object Claim {
+ implicit val ord: Ordering[Claim] = {
+ Ordering.by[Claim, (K, K, K, Att)](s => (s.body, s.requires, s.ensures, s.att))
+ }
+}
case class Rule(body: K, requires: K, ensures: K, att: Att = Att.empty) extends RuleOrClaim with RuleToString with OuterKORE {
override def withAtt(att: Att): Rule = Rule(body, requires, ensures, att)
@@ -449,18 +502,8 @@ case class Rule(body: K, requires: K, ensures: K, att: Att = Att.empty) extends
}
object Rule {
- implicit val ord: Ordering[Rule] = new Ordering[Rule] {
- def compare(a: Rule, b: Rule): Int = {
- val c1 = Ordering[K].compare(a.body, b.body)
- if (c1 == 0) {
- val c2 = Ordering[K].compare(a.requires, b.requires)
- if (c2 == 0) {
- Ordering[K].compare(a.ensures, b.ensures)
- }
- c2
- }
- c1
- }
+ implicit val ord: Ordering[Rule] = {
+ Ordering.by[Rule, (K, K, K, Att)](r => (r.body, r.requires, r.ensures, r.att))
}
}
@@ -474,6 +517,12 @@ case class SyntaxPriority(priorities: Seq[Set[Tag]], att: Att = Att.empty)
override val isNonSyntax = false
override def withAtt(att: Att) = SyntaxPriority(priorities, att)
}
+object SyntaxPriority {
+ implicit val ord: Ordering[SyntaxPriority] = {
+ import scala.math.Ordering.Implicits._
+ Ordering.by[SyntaxPriority, (Seq[Seq[Tag]], Att)](s => (s.priorities.map(_.toSeq.sorted), s.att))
+ }
+}
case class SyntaxAssociativity(
assoc: Associativity,
@@ -484,9 +533,19 @@ case class SyntaxAssociativity(
override val isNonSyntax = false
override def withAtt(att: Att) = SyntaxAssociativity(assoc, tags, att)
}
+object SyntaxAssociativity {
+ implicit val ord: Ordering[SyntaxAssociativity] = {
+ import scala.math.Ordering.Implicits._
+ Ordering.by[SyntaxAssociativity, (Associativity, Seq[Tag], Att)](s => (s.assoc, s.tags.toSeq.sorted, s.att))
+ }
+}
case class Tag(name: String) extends TagToString with OuterKORE
+object Tag {
+ implicit val ord: Ordering[Tag] = Ordering.by[Tag, String](_.name)
+}
+
//trait Production {
// def sort: Sort
// def att: Att
@@ -503,6 +562,13 @@ case class SyntaxSort(params: Seq[Sort], sort: Sort, att: Att = Att.empty) exten
override val isNonSyntax = false
override def withAtt(att: Att) = SyntaxSort(params, sort, att)
}
+object SyntaxSort {
+ implicit val ord: Ordering[SyntaxSort] = {
+ import scala.math.Ordering.Implicits._
+ Ordering.by[SyntaxSort, (Seq[String], String, Att)](s => (s.params.map(_.name), s.sort.name, s.att))
+ }
+}
+
case class SortSynonym(newSort: Sort, oldSort: Sort, att: Att = Att.empty) extends Sentence
with SortSynonymToString with OuterKORE {
@@ -510,6 +576,12 @@ case class SortSynonym(newSort: Sort, oldSort: Sort, att: Att = Att.empty) exten
override val isNonSyntax = false
override def withAtt(att: Att) = SortSynonym(newSort, oldSort, att)
}
+object SortSynonym {
+ implicit val ord: Ordering[SortSynonym] = {
+ Ordering.by[SortSynonym, (String, String, Att)](s => (s.newSort.name, s.oldSort.name, s.att))
+ }
+}
+
case class SyntaxLexical(name: String, regex: String, att: Att = Att.empty) extends Sentence
with SyntaxLexicalToString with OuterKORE {
@@ -517,6 +589,11 @@ case class SyntaxLexical(name: String, regex: String, att: Att = Att.empty) exte
override val isNonSyntax = false
override def withAtt(att: Att) = SyntaxLexical(name, regex, att)
}
+object SyntaxLexical {
+ implicit val ord: Ordering[SyntaxLexical] = {
+ Ordering.by[SyntaxLexical, (String, String, Att)](s => (s.name, s.regex, s.att))
+ }
+}
case class Production(klabel: Option[KLabel], params: Seq[Sort], sort: Sort, items: Seq[ProductionItem], att: Att)
extends Sentence with ProductionToString {
@@ -638,10 +715,8 @@ case class Production(klabel: Option[KLabel], params: Seq[Sort], sort: Sort, ite
}
object Production {
- implicit val ord: Ordering[Production] = new Ordering[Production] {
- def compare(a: Production, b: Production): Int = {
- Ordering[Option[String]].compare(a.klabel.map(_.name), b.klabel.map(_.name))
- }
+ implicit val ord: Ordering[Production] = {
+ Ordering.by[Production, (Option[String], Att)](s => (s.klabel.map(_.name), s.att))
}
def apply(klabel: KLabel, params: Seq[Sort], sort: Sort, items: Seq[ProductionItem], att: Att = Att.empty): Production = {
diff --git a/kore/src/test/scala/org/kframework/definition/OuterTest.scala b/kore/src/test/scala/org/kframework/definition/OuterTest.scala
index c42cb6fa5d8..54e9beb0399 100644
--- a/kore/src/test/scala/org/kframework/definition/OuterTest.scala
+++ b/kore/src/test/scala/org/kframework/definition/OuterTest.scala
@@ -4,6 +4,7 @@ package org.kframework.definition
import org.junit.{Assert, Test}
import org.kframework.attributes.Att
+import org.kframework.kore.ADT.KToken
import org.kframework.kore.KORE.Sort
import org.kframework.kore.KORE.KLabel
@@ -90,4 +91,153 @@ class OuterTest {
val prod2 = Production(Some(KLabel("foo")), Seq(), Sort("Foo"), Seq(), Att.empty.add(Att.KLABEL, "bar"))
Assert.assertNotEquals(prod1, prod2)
}
+
+ // Create multiple versions of this sentence with attributes added
+ def toSentenceAttList(sentence: Sentence): List[Sentence] = {
+ val att1 = Att.empty.add(Att.ASSOC).add(Att.BAG)
+ val att2 = Att.empty.add(Att.ASSOC).add(Att.CELL)
+ val att3 = Att.empty.add(Att.BAG).add(Att.CELL)
+ val att4 = Att.empty.add(Att.BAG).add(Att.HOOK, "A")
+ val att5 = Att.empty.add(Att.BAG).add(Att.HOOK, "B")
+ val att6 = Att.empty.add(Att.BAG).add(Att.LABEL, "A")
+ val att7 = Att.empty.add(Att.BAG).add(Att.LABEL, "B")
+ val att8 = Att.empty.add(Att.HOOK, "A").add(Att.LABEL, "B")
+ val att9 = Att.empty.add(Att.HOOK, "B").add(Att.LABEL, "A")
+ val sentenceWithAtt1 = sentence.withAtt(att1)
+ val sentenceWithAtt2 = sentence.withAtt(att2)
+ val sentenceWithAtt3 = sentence.withAtt(att3)
+ val sentenceWithAtt4 = sentence.withAtt(att4)
+ val sentenceWithAtt5 = sentence.withAtt(att5)
+ val sentenceWithAtt6 = sentence.withAtt(att6)
+ val sentenceWithAtt7 = sentence.withAtt(att7)
+ val sentenceWithAtt8 = sentence.withAtt(att8)
+ val sentenceWithAtt9 = sentence.withAtt(att9)
+
+ List(sentenceWithAtt1,
+ sentenceWithAtt2,
+ sentenceWithAtt3,
+ sentenceWithAtt4,
+ sentenceWithAtt5,
+ sentenceWithAtt6,
+ sentenceWithAtt7,
+ sentenceWithAtt8,
+ sentenceWithAtt9)
+ }
+
+ // Asserts that S1 < S2 < ... < Sn
+ // Likewise, Sn > ... > S2 > S1
+ // And Sx = Sx
+ def checkOrdering(sentences: List[Sentence]): Unit = {
+ val ord = Ordering[Sentence]
+ for (remaining <- sentences.tails.filter(_.nonEmpty)) {
+ val head = remaining.head
+ Assert.assertTrue(ord.compare(head, head) == 0)
+ for (sentence <- remaining.tail) {
+ Assert.assertTrue(ord.compare(head, sentence) < 0)
+ Assert.assertTrue(ord.compare(sentence, head) > 0)
+ }
+ }
+ }
+
+ @Test def sentenceOrdering(): Unit = {
+ val sortA = Sort("A")
+ val sortB = Sort("B")
+ val sortC = Sort("C")
+
+ val ktokenA = KToken("A", sortA)
+ val ktokenB = KToken("B", sortA)
+ val ktokenC = KToken("C", sortA)
+
+ val tagA = Tag("A")
+ val tagB = Tag("B")
+ val tagC = Tag("C")
+
+ val syntaxSort1 = SyntaxSort(Seq(sortA, sortC), sortA)
+ val syntaxSort2 = SyntaxSort(Seq(sortA, sortC), sortB)
+ val syntaxSort3 = SyntaxSort(Seq(sortB, sortC), sortA)
+
+ val synonym1 = SortSynonym(sortA, sortA)
+ val synonym2 = SortSynonym(sortA, sortB)
+ val synonym3 = SortSynonym(sortB, sortC)
+
+ val lexical1 = SyntaxLexical("A", "A")
+ val lexical2 = SyntaxLexical("A", "B")
+ val lexical3 = SyntaxLexical("B", "A")
+
+ val production1 = Production(Seq(), sortA, Seq(), Att.empty)
+ val production2 = Production(KLabel("A"), Seq(), sortA, Seq(), Att.empty)
+ val production3 = Production(KLabel("B"), Seq(), sortA, Seq(), Att.empty)
+
+ val syntaxAssoc1 = SyntaxAssociativity(Associativity.Left, Set(tagA))
+ val syntaxAssoc2 = SyntaxAssociativity(Associativity.Left, Set(tagB))
+ val syntaxAssoc3 = SyntaxAssociativity(Associativity.Right, Set(tagA))
+
+ val syntaxPriority1 = SyntaxPriority(Seq(Set(tagB, tagA)))
+ val syntaxPriority2 = SyntaxPriority(Seq(Set(tagA, tagB, tagC), Set(tagB)))
+ val syntaxPriority3 = SyntaxPriority(Seq(Set(tagA, tagB, tagC), Set(tagC)))
+ val syntaxPriority4 = SyntaxPriority(Seq(Set(tagA, tagC, tagC), Set(tagB)))
+ val syntaxPriority5 = SyntaxPriority(Seq(Set(tagB)))
+
+ val contextAlias1 = ContextAlias(ktokenA, ktokenA)
+ val contextAlias2 = ContextAlias(ktokenA, ktokenB)
+ val contextAlias3 = ContextAlias(ktokenB, ktokenB)
+
+ val context1 = Context(ktokenA, ktokenA)
+ val context2 = Context(ktokenA, ktokenB)
+ val context3 = Context(ktokenB, ktokenA)
+
+ val rule1 = Rule(ktokenA, ktokenA, ktokenA)
+ val rule2 = Rule(ktokenA, ktokenA, ktokenB)
+ val rule3 = Rule(ktokenA, ktokenA, ktokenC)
+ val rule4 = Rule(ktokenA, ktokenB, ktokenA)
+ val rule5 = Rule(ktokenB, ktokenA, ktokenA)
+
+ val claim1 = Claim(ktokenA, ktokenA, ktokenA)
+ val claim2 = Claim(ktokenA, ktokenA, ktokenB)
+ val claim3 = Claim(ktokenA, ktokenA, ktokenC)
+ val claim4 = Claim(ktokenA, ktokenB, ktokenA)
+ val claim5 = Claim(ktokenB, ktokenA, ktokenA)
+
+ val sentenceList = List(
+ syntaxSort1,
+ syntaxSort2,
+ syntaxSort3,
+ synonym1,
+ synonym2,
+ synonym3,
+ lexical1,
+ lexical2,
+ lexical3,
+ production1,
+ production2,
+ production3,
+ syntaxAssoc1,
+ syntaxAssoc2,
+ syntaxAssoc3,
+ syntaxPriority1,
+ syntaxPriority2,
+ syntaxPriority3,
+ syntaxPriority4,
+ syntaxPriority5,
+ contextAlias1,
+ contextAlias2,
+ contextAlias3,
+ context1,
+ context2,
+ context3,
+ rule1,
+ rule2,
+ rule3,
+ rule4,
+ rule5,
+ claim1,
+ claim2,
+ claim3,
+ claim4,
+ claim5)
+
+ val sentenceListWithAtts = sentenceList.flatMap(toSentenceAttList(_))
+
+ checkOrdering(sentenceListWithAtts)
+ }
}