/* * Copyright 2025 Casper Dalgaard Nielsen * Adam Yasser Tallouzi * * Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE.md file. */////// Purpose of phase: For `PredSym(name, id)` we want `id` to be unique, for the whole program./// This phase passes over the Datalog-Ast and replaces the `id` and after everything is done/// recreates the old `PredSym`s for the resulting model.////// This is necessary as Flix uses the id-part for generating local predicates, not as unique identifiers.///////// This purpose of this module is to transform `PredSym`s defined by `(name, id)`, to `PredSym`s/// uniquely defined by their `id`.///pubmod Fixpoint3.Phase.RenamePredSyms {use Fixpoint3.Ast.Datalog.{Datalog, Constraint, BodyPredicate, BodyTerm, HeadTerm, Polarity, VarSym}use Fixpoint3.Ast.Datalog.Datalog.{Datalog, Model, Join, Provenance}use Fixpoint3.Ast.Datalog.Constraint.Constraintuse Fixpoint3.Ast.Datalog.HeadPredicateuse Fixpoint3.Ast.Datalog.HeadPredicate.HeadAtomuse Fixpoint3.Ast.Datalog.BodyPredicate.{BodyAtom, Functional, Guard1, Guard2, Guard3, Guard4, Guard5}use Fixpoint3.Ast.Ram.RelSymuse Fixpoint3.Ast.Shared.{Denotation, isRelational, PredSym}use Fixpoint3.Ast.Shared.PredSym.PredSymuse Fixpoint3.UniqueIntsuse Fixpoint3.Util.getOrCrashtypealiasFixInformation = Map[Int32, PredSym]////// Maps all `PredSym`s in `d` to have unique ids. Returns the resulting/// program and information which `renamePredSyms` can use to recreate the original program.////// This function expects `PredSym`s to be defined by their `(name, id)`, while afterwards they/// will be uniquely defined by their `id`.///pubdefassignUniqueIdentifiersToPredSyms(rc: Region[r], d: Datalog): (Datalog, FixInformation) \ r =letmapping = UniqueInts.empty(rc);letfixed = fixPredSymsInternal(d, mapping); (fixed, UniqueInts.reverse(mapping))////// Recursively applies `mapping` to the different Datalog enums to make `PredSym`s unique.///deffixPredSymsInternal(d: Datalog, mapping: UniqueInts[PredSym, r]): Datalog \ r = matchd {case Datalog(facts, rules) =>lettransformer = mapForward(mapping); Datalog(remapConstraints(facts, transformer), remapConstraints(rules, transformer))case Model(facts) => (Map#{}, facts) ||> Map.foldLeftWithKey(acc -> match RelSym.Symbol(predSym, arity, den) -> v -> {letnewSym = RelSym.Symbol(mapForward(mapping, predSym), arity, den);Map.insert(newSym, v, acc) } ) |> Modelcase Provenance(rules, facts) =>lettransformer = mapForward(mapping);letnewRules = remapConstraints(rules, transformer); (Map#{}, facts) ||> Map.foldLeftWithKey(acc -> match RelSym.Symbol(predSym, arity, den) -> v ->letnewSym = RelSym.Symbol(mapForward(mapping, predSym), arity, den);Map.insert(newSym, v, acc) ) |> Provenance(newRules)case Join(d1, d2) => Join(fixPredSymsInternal(d1, mapping), fixPredSymsInternal(d2, mapping)) }////// Replaces `PredSym(name, id)` in `d` with `Map.get(id, fixing)`.///pubdefrenamePredSyms(d: Datalog, fixing: FixInformation): Datalog = matchd {case Datalog(facts, rules) =>lettransformer = mapBack(fixing); Datalog(remapConstraints(facts, transformer), remapConstraints(rules, transformer))case Model(map) =>lettransformer = mapBack(fixing); (Map#{}, map) ||> Map.foldLeftWithKey(newMap -> match RelSym.Symbol(p, arity, den) -> v ->Map.insert(RelSym.Symbol(transformer(p), arity, den), v, newMap) ) |> Modelcase Provenance(rules, model) => {lettransformer = mapBack(fixing);letnewRules = remapConstraints(rules, transformer); (Map#{}, model) ||> Map.foldLeftWithKey(newMap -> match RelSym.Symbol(p, arity, den) -> v ->Map.insert(RelSym.Symbol(transformer(p), arity, den), v, newMap) ) |> Provenance(newRules) }case Join(_, _) => bug!("Bad argument of type 'Join' in PredSym renaming") }////// Maps `pred` back to its original `PredSym` according to `reversing`.///defmapBack(reversing: FixInformation, pred: PredSym): PredSym =// The `id`s are assigned 0 to n for `n` `PredSym`s. They should// be well within the range for `Int32`. Also no new `PredSym`s should// have been created. There is no recovery for either.let PredSym(_, id) = pred;getOrCrash(Map.get(getOrCrash(Int64.tryToInt32(id)), reversing))////// Maps `pred` back to its new `PredSym` according to `state`.///defmapForward(state: UniqueInts[PredSym, r], pred: PredSym): PredSym \ r =let PredSym(name, _) = pred;letindex = UniqueInts.createIndex(pred, state); PredSym(name, Int32.toInt64(index))////// Maps `PredSym`s of `constraints` according to `transformer`.///defremapConstraints(constraints: Vector[Constraint], transformer: PredSym -> PredSym \ r): Vector[Constraint] \ r = {Vector.map(match Constraint(head, body) -> Constraint(remapHead(transformer, head), Vector.map(remapBody(transformer), body)), constraints) }////// Maps `PredSym`s of `head` according to `transformer`.///defremapHead(transformer: PredSym -> PredSym \ r, head: HeadPredicate): HeadPredicate \ r = matchhead {case HeadAtom(pred, den, terms) => HeadAtom(transformer(pred), den, terms) }////// Maps `PredSym`s of `body` according to `transformer`.///defremapBody(transformer: PredSym -> PredSym \ r, body: BodyPredicate): BodyPredicate \ r = matchbody {case BodyAtom(pred, den, pol, fixed, terms) => BodyAtom(transformer(pred), den, pol, fixed, terms)case_ => body }}