···11-type rec t =
22- | Symbol({name: string})
33- | Compound({subexps: array<t>})
44- | Var({idx: int})
55- | Schematic({schematic: int, allowed: array<int>})
66- | Ghost
11+module ConstSymbol: SExpFunc.SYMBOL
7288-include Signatures.TERM
99- with type t := t
1010- and type meta = string
1111- and type schematic = int
1212- and type subst = Map.t<int, t>
33+include module type of SExpFunc.Make(ConstSymbol)
44+let symbol: string => t
55+let getSymbol: ConstSymbol.t => string
+396
src/SExpFunc.res
···11+module type SYMBOL = {
22+ type t
33+ let match: (t, t) => bool
44+ let prettyPrint: (t, ~scope: array<string>) => string
55+ let parse: (string, ~scope: array<string>) => result<(t, string), string>
66+}
77+88+module IntCmp = Belt.Id.MakeComparable({
99+ type t = int
1010+ let cmp = Pervasives.compare
1111+})
1212+1313+module Make = (Symbol: SYMBOL): {
1414+ type rec t =
1515+ | Symbol(Symbol.t)
1616+ | Compound({subexps: array<t>})
1717+ | Var({idx: int})
1818+ | Schematic({schematic: int, allowed: array<int>})
1919+ | Ghost
2020+ module Symbol: SYMBOL with type t := Symbol.t
2121+ include Signatures.TERM
2222+ with type t := t
2323+ and type meta = string
2424+ and type schematic = int
2525+ and type subst = Map.t<int, t>
2626+} => {
2727+ type rec t =
2828+ | Symbol(Symbol.t)
2929+ | Compound({subexps: array<t>})
3030+ | Var({idx: int})
3131+ | Schematic({schematic: int, allowed: array<int>})
3232+ | Ghost
3333+ module Symbol = Symbol
3434+ type meta = string
3535+ type schematic = int
3636+ type subst = Map.t<schematic, t>
3737+ let substEqual = Util.mapEqual
3838+ let mapSubst = Util.mapMapValues
3939+ let makeSubst = () => {
4040+ Map.make()
4141+ }
4242+ let equivalent = (a: t, b: t) => {
4343+ a == b
4444+ }
4545+ let reduce = (term: t) => term
4646+ let rec schematicsIn: t => Belt.Set.t<int, IntCmp.identity> = (it: t) =>
4747+ switch it {
4848+ | Schematic({schematic, _}) => Belt.Set.make(~id=module(IntCmp))->Belt.Set.add(schematic)
4949+ | Compound({subexps}) =>
5050+ subexps->Array.reduce(Belt.Set.make(~id=module(IntCmp)), (s, x) =>
5151+ Belt.Set.union(s, schematicsIn(x))
5252+ )
5353+ | _ => Belt.Set.make(~id=module(IntCmp))
5454+ }
5555+ let rec freeVarsIn: t => Belt.Set.t<int, IntCmp.identity> = (it: t) =>
5656+ switch it {
5757+ | Var({idx}) => Belt.Set.make(~id=module(IntCmp))->Belt.Set.add(idx)
5858+ | Compound({subexps}) =>
5959+ subexps->Array.reduce(Belt.Set.make(~id=module(IntCmp)), (s, x) =>
6060+ Belt.Set.union(s, freeVarsIn(x))
6161+ )
6262+ | _ => Belt.Set.make(~id=module(IntCmp))
6363+ }
6464+ let rec substitute = (term: t, subst: subst) =>
6565+ switch term {
6666+ | Compound({subexps}) => Compound({subexps: Array.map(subexps, x => substitute(x, subst))})
6767+ | Schematic({schematic, _}) =>
6868+ switch Map.get(subst, schematic) {
6969+ | None => term
7070+ | Some(found) => found
7171+ }
7272+ | _ => term
7373+ }
7474+7575+ let combineSubst = (s: subst, t: subst) => {
7676+ let nu = Map.make()
7777+ Map.entries(s)->Iterator.forEach(opt =>
7878+ switch opt {
7979+ | None => ()
8080+ | Some((key, term)) => nu->Map.set(key, term->substitute(t))
8181+ }
8282+ )
8383+ Map.entries(t)->Iterator.forEach(opt =>
8484+ switch opt {
8585+ | None => ()
8686+ | Some((key, term)) => nu->Map.set(key, term->substitute(s))
8787+ }
8888+ )
8989+ nu
9090+ }
9191+ let emptySubst: subst = Map.make()
9292+ let singletonSubst: (int, t) => subst = (schematic, term) => {
9393+ let s = Map.make()
9494+ s->Map.set(schematic, term)
9595+ s
9696+ }
9797+ let rec unifyTerm = (a: t, b: t) =>
9898+ switch (a, b) {
9999+ | (Symbol(na), Symbol(nb)) if na->Symbol.match(nb) => Some(emptySubst)
100100+ | (Var({idx: ia}), Var({idx: ib})) if ia == ib => Some(emptySubst)
101101+ | (Schematic({schematic: sa, _}), Schematic({schematic: sb, _})) if sa == sb => Some(emptySubst)
102102+ | (Compound({subexps: xa}), Compound({subexps: xb})) if Array.length(xa) == Array.length(xb) =>
103103+ unifyArray(Belt.Array.zip(xa, xb))
104104+ | (Schematic({schematic, allowed}), t)
105105+ if !Belt.Set.has(schematicsIn(t), schematic) &&
106106+ Belt.Set.subset(freeVarsIn(t), Belt.Set.fromArray(allowed, ~id=module(IntCmp))) =>
107107+ Some(singletonSubst(schematic, t))
108108+ | (t, Schematic({schematic, allowed}))
109109+ if !Belt.Set.has(schematicsIn(t), schematic) &&
110110+ Belt.Set.subset(freeVarsIn(t), Belt.Set.fromArray(allowed, ~id=module(IntCmp))) =>
111111+ Some(singletonSubst(schematic, t))
112112+ | (_, _) => None
113113+ }
114114+ and unifyArray = (a: array<(t, t)>) => {
115115+ if Array.length(a) == 0 {
116116+ Some(emptySubst)
117117+ } else {
118118+ let (x, y) = a[0]->Option.getUnsafe
119119+ switch unifyTerm(x, y) {
120120+ | None => None
121121+ | Some(s1) =>
122122+ switch a
123123+ ->Array.sliceToEnd(~start=1)
124124+ ->Array.map(((t1, t2)) => (substitute(t1, s1), substitute(t2, s1)))
125125+ ->unifyArray {
126126+ | None => None
127127+ | Some(s2) => Some(combineSubst(s1, s2))
128128+ }
129129+ }
130130+ }
131131+ }
132132+ let unify = (a: t, b: t, ~gen as _=?) => {
133133+ Seq.fromArray(
134134+ switch unifyTerm(a, b) {
135135+ | None => []
136136+ | Some(s) => [s]
137137+ },
138138+ )
139139+ }
140140+ let rec substDeBruijn = (term: t, substs: array<t>, ~from: int=0) =>
141141+ switch term {
142142+ | Symbol(_) => term
143143+ | Compound({subexps}) =>
144144+ Compound({subexps: Array.map(subexps, x => substDeBruijn(x, substs, ~from))})
145145+ | Var({idx: var}) =>
146146+ if var < from {
147147+ term
148148+ } else if var - from < Array.length(substs) && var - from >= 0 {
149149+ Option.getUnsafe(substs[var - from])
150150+ } else {
151151+ Var({idx: var - Array.length(substs)})
152152+ }
153153+ | Schematic({schematic, allowed}) =>
154154+ Schematic({
155155+ schematic,
156156+ allowed: Array.filterMap(allowed, i =>
157157+ if i < from + Array.length(substs) {
158158+ None
159159+ } else {
160160+ Some(i - (from + Array.length(substs)))
161161+ }
162162+ ),
163163+ })
164164+ | Ghost => Ghost
165165+ }
166166+ let rec upshift = (term: t, amount: int, ~from: int=0) =>
167167+ switch term {
168168+ | Symbol(_) => term
169169+ | Compound({subexps}) => Compound({subexps: Array.map(subexps, x => upshift(x, amount, ~from))})
170170+ | Var({idx}) =>
171171+ Var({
172172+ idx: if idx >= from {
173173+ idx + amount
174174+ } else {
175175+ idx
176176+ },
177177+ })
178178+ | Schematic({schematic, allowed}) =>
179179+ Schematic({
180180+ schematic,
181181+ allowed: Array.map(allowed, i =>
182182+ if i >= from {
183183+ i + amount
184184+ } else {
185185+ i
186186+ }
187187+ ),
188188+ })
189189+ | Ghost => Ghost
190190+ }
191191+ let place = (x: int, ~scope: array<string>) => Schematic({
192192+ schematic: x,
193193+ allowed: Array.fromInitializer(~length=Array.length(scope), i => i),
194194+ })
195195+ let mergeSubsts = Util.mapUnion
196196+197197+ type gen = ref<int>
198198+ let seen = (g: gen, s: int) => {
199199+ if s >= g.contents {
200200+ g := s + 1
201201+ }
202202+ }
203203+ let fresh = (g: gen, ~replacing as _=?) => {
204204+ let v = g.contents
205205+ g := g.contents + 1
206206+ v
207207+ }
208208+ let prettyPrintVar = (idx: int, scope: array<string>) => {
209209+ switch scope[idx] {
210210+ | Some(n) if Array.indexOf(scope, n) == idx => n
211211+ | _ => "\\"->String.concat(String.make(idx))
212212+ }
213213+ }
214214+ let makeGen = () => {
215215+ ref(0)
216216+ }
217217+ let rec prettyPrint = (it: t, ~scope: array<string>) =>
218218+ switch it {
219219+ | Symbol(name) => Symbol.prettyPrint(name, ~scope)
220220+ | Var({idx}) => prettyPrintVar(idx, scope)
221221+ | Schematic({schematic, allowed}) =>
222222+ "?"
223223+ ->String.concat(String.make(schematic))
224224+ ->String.concat("(")
225225+ ->String.concat(Array.join(allowed->Array.map(idx => prettyPrintVar(idx, scope)), " "))
226226+ ->String.concat(")")
227227+ | Compound({subexps}) =>
228228+ "("
229229+ ->String.concat(Array.join(subexps->Array.map(e => prettyPrint(e, ~scope)), " "))
230230+ ->String.concat(")")
231231+ | Ghost => "§SExp.Ghost"
232232+ }
233233+234234+ let prettyPrintSubst = (sub, ~scope) =>
235235+ Util.prettyPrintMap(sub, ~showV=t => prettyPrint(t, ~scope))
236236+ let symbolRegexpString = `^([^\\s()\\[\\]]+)`
237237+ let varRegexpString = "^\\\\([0-9]+)$"
238238+ let schematicRegexpString = "^\\?([0-9]+)$"
239239+ type lexeme = LParen | RParen | VarT(int) | SymbolT(Symbol.t) | SchematicT(int)
240240+ let nameRES = "^([^\\s.\\[\\]()]+)\\."
241241+ let prettyPrintMeta = (str: string) => {
242242+ String.concat(str, ".")
243243+ }
244244+ let parseMeta = (str: string) => {
245245+ let re = RegExp.fromStringWithFlags(nameRES, ~flags="y")
246246+ switch re->RegExp.exec(str->String.trim) {
247247+ | None => Error("not a meta name")
248248+ | Some(res) =>
249249+ switch RegExp.Result.matches(res) {
250250+ | [n] => Ok(n, String.sliceToEnd(str->String.trim, ~start=RegExp.lastIndex(re)))
251251+ | _ => Error("impossible happened")
252252+ }
253253+ }
254254+ }
255255+ let parse = (str: string, ~scope: array<string>, ~gen=?) => {
256256+ let cur = ref(String.make(str))
257257+ let lex: unit => option<lexeme> = () => {
258258+ let str = String.trim(cur.contents)
259259+ cur := str
260260+ let checkVariable = (candidate: string) => {
261261+ let varRegexp = RegExp.fromString(varRegexpString)
262262+ switch Array.indexOf(scope, candidate) {
263263+ | -1 =>
264264+ switch varRegexp->RegExp.exec(candidate) {
265265+ | Some(res') =>
266266+ switch RegExp.Result.matches(res') {
267267+ | [idx] => Some(idx->Int.fromString->Option.getUnsafe)
268268+ | _ => None
269269+ }
270270+ | None => None
271271+ }
272272+ | idx => Some(idx)
273273+ }
274274+ }
275275+ if String.get(str, 0) == Some("(") {
276276+ cur := String.sliceToEnd(str, ~start=1)
277277+ Some(LParen)
278278+ } else if String.get(str, 0) == Some(")") {
279279+ cur := String.sliceToEnd(str, ~start=1)
280280+ Some(RParen)
281281+ } else {
282282+ let symbolRegexp = RegExp.fromStringWithFlags(symbolRegexpString, ~flags="y")
283283+ switch symbolRegexp->RegExp.exec(str) {
284284+ | None => None
285285+ | Some(res) =>
286286+ switch RegExp.Result.matches(res) {
287287+ | [symb] => {
288288+ cur := String.sliceToEnd(str, ~start=RegExp.lastIndex(symbolRegexp))
289289+ let parseSymb = () => {
290290+ // FIX: not ideal to throw away symbol error message
291291+ Symbol.parse(symb, ~scope)
292292+ ->Util.Result.ok
293293+ ->Option.map(((s, rest)) => {
294294+ cur := rest->String.concat(cur.contents)
295295+ SymbolT(s)
296296+ })
297297+ }
298298+ switch checkVariable(symb) {
299299+ | Some(idx) => Some(VarT(idx))
300300+ | None => {
301301+ let schematicRegexp = RegExp.fromString(schematicRegexpString)
302302+ switch schematicRegexp->RegExp.exec(symb) {
303303+ | None => parseSymb()
304304+ | Some(res') =>
305305+ switch RegExp.Result.matches(res') {
306306+ | [s] => Some(SchematicT(s->Int.fromString->Option.getUnsafe))
307307+ | _ => parseSymb()
308308+ }
309309+ }
310310+ }
311311+ }
312312+ }
313313+ | _ => None
314314+ }
315315+ }
316316+ }
317317+ }
318318+319319+ let peek = () => {
320320+ // a bit slow, better would be to keep a backlog of lexed tokens..
321321+ let str = String.make(cur.contents)
322322+ let tok = lex()
323323+ cur := str
324324+ tok
325325+ }
326326+ exception ParseError(string)
327327+ let rec parseExp = () => {
328328+ let tok = peek()
329329+ switch tok {
330330+ | Some(SymbolT(s)) => {
331331+ let _ = lex()
332332+ Some(Symbol(s))
333333+ }
334334+ | Some(VarT(idx)) => {
335335+ let _ = lex()
336336+ Some(Var({idx: idx}))
337337+ }
338338+ | Some(SchematicT(num)) => {
339339+ let _ = lex()
340340+ switch lex() {
341341+ | Some(LParen) => {
342342+ let it = ref(None)
343343+ let bits = []
344344+ let getVar = (t: option<lexeme>) =>
345345+ switch t {
346346+ | Some(VarT(idx)) => Some(idx)
347347+ | _ => None
348348+ }
349349+ while {
350350+ it := lex()
351351+ it.contents->getVar->Option.isSome
352352+ } {
353353+ Array.push(bits, it.contents->getVar->Option.getUnsafe)
354354+ }
355355+ switch it.contents {
356356+ | Some(RParen) =>
357357+ switch gen {
358358+ | Some(g) => {
359359+ seen(g, num)
360360+ Some(Schematic({schematic: num, allowed: bits}))
361361+ }
362362+ | None => throw(ParseError("Schematics not allowed here"))
363363+ }
364364+ | _ => throw(ParseError("Expected closing parenthesis"))
365365+ }
366366+ }
367367+ | _ => throw(ParseError("Expected opening parenthesis"))
368368+ }
369369+ }
370370+ | Some(LParen) => {
371371+ let _ = lex()
372372+ let bits = []
373373+ let it = ref(None)
374374+ while {
375375+ it := parseExp()
376376+ it.contents->Option.isSome
377377+ } {
378378+ Array.push(bits, it.contents->Option.getUnsafe)
379379+ }
380380+ switch lex() {
381381+ | Some(RParen) => Some(Compound({subexps: bits}))
382382+ | _ => throw(ParseError("Expected closing parenthesis"))
383383+ }
384384+ }
385385+ | _ => None
386386+ }
387387+ }
388388+ switch parseExp() {
389389+ | exception ParseError(s) => Error(s)
390390+ | None => Error("No expression to parse")
391391+ | Some(e) => Ok((e, cur.contents))
392392+ }
393393+ }
394394+395395+ let ghostTerm = Ghost
396396+}