Skip to content

Commit dafe4ec

Browse files
author
Dwight Guth
authored
Add pattern matching support for list random access patterns (#1143)
This is not rigorously tested, nor is it likely to be in the near future because the code it was written to support ended up not being worth merging. However, it is broadly useful code that may find value in the future, so I would like to get it merged. It also includes a few fixes to python scripts in the repo that had gone slightly stale.
1 parent 9d21e4d commit dafe4ec

File tree

21 files changed

+2666
-113
lines changed

21 files changed

+2666
-113
lines changed

debug/kgdb.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ def __init__(self, val, cat, sortName):
359359
self.used_var_names = set()
360360
self.long_int = gdb.lookup_type("long int")
361361
self.bool_ptr = gdb.lookup_type("bool").pointer()
362+
self.char_ptr = gdb.lookup_type("unsigned char").pointer()
362363
self.unsigned_char = gdb.lookup_type("unsigned char")
363364
self.string_ptr = gdb.lookup_type("string").pointer()
364365
self.stringbuffer_ptr = gdb.lookup_type("stringbuffer").pointer()
@@ -483,6 +484,20 @@ def appendInt(self, val, sort):
483484
self.appendLimbs(size, val.dereference()['_mp_d'])
484485
self.result += "\")"
485486

487+
def appendMInt(self, val, width, sort):
488+
self.result += "\\dv{" + sort + "}(\""
489+
self.appendLE(val.cast(self.char_ptr), width)
490+
self.result += "\")"
491+
492+
def appendLE(self, ptr, size):
493+
accum = 0
494+
for i in range(size-1,-1,-1):
495+
accum <<= 8
496+
byte = int(ptr[i])
497+
accum |= byte
498+
self.result += str(accum)
499+
self.result += "p" + str(size * 8)
500+
486501
def appendList(self, val, sort):
487502
length = val.dereference()['impl_']['size']
488503
if length == 0:
@@ -632,6 +647,14 @@ def append(self, subject, isVar, sort):
632647
self.result += "\\dv{" + sort + "}(\"" + string + "\")"
633648
elif cat == @STRINGBUFFER_LAYOUT@:
634649
self.appendStringBuffer(arg.cast(self.stringbuffer_ptr_ptr).dereference(), sort)
650+
elif cat == @MINT_LAYOUT@ + 32:
651+
self.appendMInt(arg, 4, sort)
652+
elif cat == @MINT_LAYOUT@ + 64:
653+
self.appendMInt(arg, 8, sort)
654+
elif cat == @MINT_LAYOUT@ + 160:
655+
self.appendMInt(arg, 20, sort)
656+
elif cat == @MINT_LAYOUT@ + 256:
657+
self.appendMInt(arg, 32, sort)
635658
else:
636659
raise ValueError()
637660
if i != nargs - 1:

matching/src/main/java/org/kframework/backend/llvm/matching/MatchingException.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import java.util.Optional;
66

7-
public final class MatchingException extends Throwable {
7+
public final class MatchingException extends RuntimeException {
88
public enum Type {
99
USELESS_RULE,
1010
NON_EXHAUSTIVE_MATCH,

matching/src/main/scala/org/kframework/backend/llvm/matching/Constructor.scala

Lines changed: 126 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -35,62 +35,89 @@ case class NonEmpty() extends Constructor {
3535
override lazy val hashCode: Int = scala.runtime.ScalaRunTime._hashCode(this)
3636
}
3737

38-
case class HasKey(isSet: Boolean, element: SymbolOrAlias, key: Option[Pattern[Option[Occurrence]]])
39-
extends Constructor {
38+
case class HasKey(
39+
cat: SortCategory,
40+
element: SymbolOrAlias,
41+
key: Option[Pattern[Option[Occurrence]]]
42+
) extends Constructor {
4043
def name = "1"
4144
def isBest(pat: Pattern[Option[Occurrence]]): Boolean = key.isDefined && pat == key.get
4245
def expand(f: Fringe): Option[immutable.Seq[Fringe]] = {
4346
val sorts = f.symlib.signatures(element)._1
4447
key match {
4548
case None =>
46-
if (isSet) {
47-
Some(
48-
immutable.Seq(
49-
Fringe(f.symlib, sorts.head, Choice(f.occurrence), isExact = false),
50-
Fringe(f.symlib, f.sort, ChoiceRem(f.occurrence), isExact = false)
49+
cat match {
50+
case SetS() =>
51+
Some(
52+
immutable.Seq(
53+
Fringe(f.symlib, sorts.head, Choice(f.occurrence), isExact = false),
54+
Fringe(f.symlib, f.sort, ChoiceRem(f.occurrence), isExact = false)
55+
)
56+
)
57+
case MapS() =>
58+
Some(
59+
immutable.Seq(
60+
Fringe(f.symlib, sorts.head, Choice(f.occurrence), isExact = false),
61+
Fringe(f.symlib, sorts(1), ChoiceValue(f.occurrence), isExact = false),
62+
Fringe(f.symlib, f.sort, ChoiceRem(f.occurrence), isExact = false)
63+
)
5164
)
52-
)
53-
} else {
54-
Some(
55-
immutable.Seq(
56-
Fringe(f.symlib, sorts.head, Choice(f.occurrence), isExact = false),
57-
Fringe(f.symlib, sorts(1), ChoiceValue(f.occurrence), isExact = false),
58-
Fringe(f.symlib, f.sort, ChoiceRem(f.occurrence), isExact = false)
65+
case ListS() =>
66+
Some(
67+
immutable.Seq(
68+
Fringe(f.symlib, sorts(1), Choice(f.occurrence), isExact = false),
69+
Fringe(f.symlib, sorts(2), ChoiceValue(f.occurrence), isExact = false),
70+
Fringe(f.symlib, f.sort, ChoiceRem(f.occurrence), isExact = false)
71+
)
5972
)
60-
)
73+
case _ => ???
6174
}
6275
case Some(k) =>
63-
if (isSet) {
64-
Some(immutable.Seq(Fringe(f.symlib, f.sort, Rem(k, f.occurrence), isExact = false), f))
65-
} else {
66-
Some(
67-
immutable.Seq(
68-
Fringe(f.symlib, sorts(1), Value(k, f.occurrence), isExact = false),
69-
Fringe(f.symlib, f.sort, Rem(k, f.occurrence), isExact = false),
70-
f
76+
cat match {
77+
case SetS() =>
78+
Some(immutable.Seq(Fringe(f.symlib, f.sort, Rem(k, f.occurrence), isExact = false), f))
79+
case MapS() =>
80+
Some(
81+
immutable.Seq(
82+
Fringe(f.symlib, sorts(1), Value(k, f.occurrence), isExact = false),
83+
Fringe(f.symlib, f.sort, Rem(k, f.occurrence), isExact = false),
84+
f
85+
)
86+
)
87+
case ListS() =>
88+
Some(
89+
immutable.Seq(
90+
Fringe(f.symlib, sorts(2), Value(k, f.occurrence), isExact = false),
91+
Fringe(f.symlib, f.sort, f.occurrence, isExact = false),
92+
f
93+
)
7194
)
72-
)
95+
case _ => ???
7396
}
7497
}
7598
}
7699
def contract(f: Fringe, children: immutable.Seq[Pattern[String]]): Pattern[String] = {
77100
val child = children.last
78101
var key: Pattern[String] = null
79102
var value: Pattern[String] = null
80-
assert((isSet && children.size == 2) || (!isSet && children.size == 3))
103+
assert((cat == SetS() && children.size == 2) || (cat != SetS() && children.size == 3))
81104
if (this.key.isEmpty) {
82-
if (isSet) {
83-
key = children.head
84-
} else {
85-
key = children.head
86-
value = children(1)
105+
cat match {
106+
case SetS() =>
107+
key = children.head
108+
case MapS() =>
109+
key = children.head
110+
value = children(1)
111+
case _ => ???
87112
}
88113
} else {
89-
if (isSet) {
90-
key = this.key.get.decanonicalize
91-
} else {
92-
key = this.key.get.decanonicalize
93-
value = children.head
114+
cat match {
115+
case SetS() =>
116+
key = this.key.get.decanonicalize
117+
case ListS() | MapS() =>
118+
key = this.key.get.decanonicalize
119+
value = children.head
120+
case _ => ???
94121
}
95122
}
96123
def element(k: Pattern[String], v: Pattern[String]): Pattern[String] =
@@ -99,35 +126,53 @@ case class HasKey(isSet: Boolean, element: SymbolOrAlias, key: Option[Pattern[Op
99126
SymbolP(Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "element").get, immutable.Seq(k))
100127
def concat(m1: Pattern[String], m2: Pattern[String]): Pattern[String] =
101128
SymbolP(Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "concat").get, immutable.Seq(m1, m2))
129+
def update(m1: Pattern[String], m2: Pattern[String], m3: Pattern[String]): Pattern[String] =
130+
SymbolP(
131+
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "update").get,
132+
immutable.Seq(m1, m2, m3)
133+
)
102134
child match {
103135
case MapP(keys, values, frame, ctr, orig) =>
104136
MapP(key +: keys, value +: values, frame, ctr, orig)
137+
case ListGetP(keys, values, frame, ctr, orig) =>
138+
ListGetP(key +: keys, value +: values, frame, ctr, orig)
105139
case SetP(elems, frame, ctr, orig) =>
106140
SetP(key +: elems, frame, ctr, orig)
107141
case WildcardP() | VariableP(_, _) =>
108-
if (isSet) {
109-
SetP(
110-
immutable.Seq(key),
111-
Some(child),
112-
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "element").get,
113-
concat(setElement(key), child)
114-
)
115-
} else {
116-
MapP(
117-
immutable.Seq(key),
118-
immutable.Seq(value),
119-
Some(child),
120-
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "element").get,
121-
concat(element(key, value), child)
122-
)
142+
cat match {
143+
case SetS() =>
144+
SetP(
145+
immutable.Seq(key),
146+
Some(child),
147+
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "element").get,
148+
concat(setElement(key), child)
149+
)
150+
case MapS() =>
151+
MapP(
152+
immutable.Seq(key),
153+
immutable.Seq(value),
154+
Some(child),
155+
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "element").get,
156+
concat(element(key, value), child)
157+
)
158+
case ListS() =>
159+
ListGetP(
160+
immutable.Seq(key),
161+
immutable.Seq(value),
162+
child,
163+
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "update").get,
164+
update(child, key, value)
165+
)
166+
case _ => ???
123167
}
124168
case _ => ???
125169
}
126170
}
127171
override lazy val hashCode: Int = scala.runtime.ScalaRunTime._hashCode(this)
128172
}
129173

130-
case class HasNoKey(isSet: Boolean, key: Option[Pattern[Option[Occurrence]]]) extends Constructor {
174+
case class HasNoKey(cat: SortCategory, key: Option[Pattern[Option[Occurrence]]])
175+
extends Constructor {
131176
def name = "0"
132177
def isBest(pat: Pattern[Option[Occurrence]]): Boolean = key.isDefined && pat == key.get
133178
def expand(f: Fringe): Option[immutable.Seq[Fringe]] = Some(immutable.Seq(f))
@@ -141,6 +186,11 @@ case class HasNoKey(isSet: Boolean, key: Option[Pattern[Option[Occurrence]]]) ex
141186
SymbolP(Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "unit").get, immutable.Seq())
142187
def concat(m1: Pattern[String], m2: Pattern[String]): Pattern[String] =
143188
SymbolP(Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "concat").get, immutable.Seq(m1, m2))
189+
def update(m1: Pattern[String], m2: Pattern[String], m3: Pattern[String]): Pattern[String] =
190+
SymbolP(
191+
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "update").get,
192+
immutable.Seq(m1, m2, m3)
193+
)
144194
def wildcard = WildcardP[String]()
145195
child match {
146196
case MapP(keys, values, frame, ctr, orig) =>
@@ -154,21 +204,31 @@ case class HasNoKey(isSet: Boolean, key: Option[Pattern[Option[Occurrence]]]) ex
154204
case SetP(elems, frame, ctr, orig) =>
155205
SetP(wildcard +: elems, frame, ctr, concat(setElement(wildcard), orig))
156206
case WildcardP() | VariableP(_, _) =>
157-
if (isSet) {
158-
SetP(
159-
immutable.Seq(wildcard),
160-
Some(child),
161-
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "element").get,
162-
concat(setElement(wildcard), child)
163-
)
164-
} else {
165-
MapP(
166-
immutable.Seq(wildcard),
167-
immutable.Seq(wildcard),
168-
Some(child),
169-
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "element").get,
170-
concat(element(wildcard, wildcard), child)
171-
)
207+
cat match {
208+
case SetS() =>
209+
SetP(
210+
immutable.Seq(wildcard),
211+
Some(child),
212+
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "element").get,
213+
concat(setElement(wildcard), child)
214+
)
215+
case MapS() =>
216+
MapP(
217+
immutable.Seq(wildcard),
218+
immutable.Seq(wildcard),
219+
Some(child),
220+
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "element").get,
221+
concat(element(wildcard, wildcard), child)
222+
)
223+
case ListS() =>
224+
ListGetP(
225+
immutable.Seq(wildcard),
226+
immutable.Seq(wildcard),
227+
child,
228+
Parser.getSymbolAtt(f.symlib.sortAtt(f.sort), "update").get,
229+
update(child, wildcard, wildcard)
230+
)
231+
case _ => ???
172232
}
173233
case _ => ???
174234
}

matching/src/main/scala/org/kframework/backend/llvm/matching/Generator.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.runtimeverification.k.kore._
44
import org.kframework.backend.llvm.matching.dt.DecisionTree
55
import org.kframework.backend.llvm.matching.pattern.{ Pattern => P }
66
import org.kframework.backend.llvm.matching.pattern.AsP
7+
import org.kframework.backend.llvm.matching.pattern.ListGetP
78
import org.kframework.backend.llvm.matching.pattern.ListP
89
import org.kframework.backend.llvm.matching.pattern.LiteralP
910
import org.kframework.backend.llvm.matching.pattern.MapP
@@ -51,6 +52,25 @@ object Generator {
5152
case _ => ???
5253
}
5354

55+
private def listGetPattern(
56+
sym: SymbolOrAlias,
57+
ps: immutable.Seq[P[String]],
58+
c: SymbolOrAlias
59+
): P[String] =
60+
ps match {
61+
case immutable.Seq(p @ (WildcardP() | VariableP(_, _)), k, v) =>
62+
ListGetP(immutable.Seq(k), immutable.Seq(v), p, c, SymbolP(sym, immutable.Seq(p, k, v)))
63+
case immutable.Seq(ListGetP(ks, vs, frame, _, o), k, v) =>
64+
ListGetP(
65+
ks ++ immutable.Seq(k),
66+
vs ++ immutable.Seq(v),
67+
frame,
68+
c,
69+
SymbolP(sym, immutable.Seq(o, k, v))
70+
)
71+
case _ => ???
72+
}
73+
5474
private def mapPattern(
5575
sym: SymbolOrAlias,
5676
cons: CollectionCons,
@@ -116,6 +136,8 @@ object Generator {
116136
): List[P[String]] = {
117137
def getElementSym(sort: Sort): SymbolOrAlias =
118138
Parser.getSymbolAtt(symlib.sortAtt(sort), "element").get
139+
def getUpdateSym(sort: Sort): SymbolOrAlias =
140+
Parser.getSymbolAtt(symlib.sortAtt(sort), "update").get
119141
def genPattern(pat: Pattern): P[String] =
120142
pat match {
121143
case Application(sym, ps) =>
@@ -128,6 +150,8 @@ object Generator {
128150
case Some("LIST.unit") => listPattern(sym, Unit(), immutable.Seq(), getElementSym(sort))
129151
case Some("LIST.element") =>
130152
listPattern(sym, Element(), ps.map(genPattern), getElementSym(sort))
153+
case Some("LIST.update") =>
154+
listGetPattern(sym, ps.map(genPattern), getUpdateSym(sort))
131155
case Some("MAP.concat") =>
132156
mapPattern(sym, Concat(), ps.map(genPattern), getElementSym(sort))
133157
case Some("MAP.unit") => mapPattern(sym, Unit(), immutable.Seq(), getElementSym(sort))

matching/src/main/scala/org/kframework/backend/llvm/matching/Heuristics.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ sealed trait Heuristic {
3535
key: Option[Pattern[Option[Occurrence]]],
3636
isEmpty: Boolean
3737
): Double = ???
38+
def scoreListGet[T](
39+
p: ListGetP[T],
40+
f: Fringe,
41+
c: Clause,
42+
key: Option[Pattern[Option[Occurrence]]],
43+
isEmpty: Boolean
44+
): Double = ???
3845
def scoreOr[T](
3946
p: OrP[T],
4047
f: Fringe,
@@ -148,6 +155,20 @@ object DefaultHeuristic extends Heuristic {
148155
} else {
149156
1.0
150157
}
158+
override def scoreListGet[T](
159+
p: ListGetP[T],
160+
f: Fringe,
161+
c: Clause,
162+
key: Option[Pattern[Option[Occurrence]]],
163+
isEmpty: Boolean
164+
): Double =
165+
if (p.keys.isEmpty) {
166+
p.frame.score(this, f, c, key, isEmpty)
167+
} else if (key.isDefined) {
168+
if (p.canonicalize(c).keys.contains(key.get)) 1.0 else 0.0
169+
} else {
170+
1.0
171+
}
151172

152173
override def scoreOr[T](
153174
p: OrP[T],

0 commit comments

Comments
 (0)