meander

Stephan Renatus 2023-11-02T09:42:47.032459Z

hi! I’d like to reduce some noise from a nested structure: the patterns I’d like to simplify are

{:type "CallStmt", :stmt {:func "g0.data.x.p", :args [{:type "local", :value 0} {:type "local", :value 1}], :result 2, :file 0, :col 0, :row 0}} 
⬇️
[:CallStmt {:func "g0.data.x.p", :args [{:type "local", :value 0} {:type "local", :value 1}], :result 2}]
and I got that base case done, more or less, via
(m/match {:type "CallStmt", :stmt {:func "g0.data.x.p", :args [{:type "local", :value 0} {:type "local", :value 1}], :result 2, :file 0, :col 0, :row 0}}
  {:type ?t :stmt {:func ?f :args ?a :result ?r}}
  [(keyword ?t) {:func ?f :args ?a :result ?r}])
but I’ve got a bunch of problems still: 1. I’d like to omit :file, :row, :col, not enumerate what to keep — not every stmt has a :func for example 2. this is just the base, it’s a nested structure that I’d like to — and fail to — cleanup (see thread)

Stephan Renatus 2023-11-02T09:43:06.149269Z

here’s a complete example

{:static {:strings [{:value "result"} {:value "xs"} {:value "y"}], :files [{:value "foo.rego"}]}, :plans {:plans [{:name "x/p", :blocks [{:stmts [{:type "CallStmt", :stmt {:func "g0.data.x.p", :args [{:type "local", :value 0} {:type "local", :value 1}], :result 2, :file 0, :col 0, :row 0}} {:type "AssignVarStmt", :stmt {:source {:type "local", :value 2}, :target 3, :file 0, :col 0, :row 0}} {:type "MakeObjectStmt", :stmt {:target 4, :file 0, :col 0, :row 0}} {:type "ObjectInsertStmt", :stmt {:key {:type "string_index", :value 0}, :value {:type "local", :value 3}, :object 4, :file 0, :col 0, :row 0}} {:type "ResultSetAddStmt", :stmt {:value 4, :file 0, :col 0, :row 0}}]}]}]}, :funcs {:funcs [{:name "g0.data.x.p", :params [0 1], :return 2, :blocks [{:stmts [{:type "ResetLocalStmt", :stmt {:target 3, :file 0, :col 1, :row 4}} {:type "DotStmt", :stmt {:source {:type "local", :value 0}, :key {:type "string_index", :value 1}, :target 4, :file 0, :col 5, :row 5}} {:type "ScanStmt", :stmt {:source 4, :key 5, :value 6, :block {:stmts [{:type "AssignVarStmt", :stmt {:source {:type "local", :value 5}, :target 7, :file 0, :col 5, :row 5}} {:type "AssignVarStmt", :stmt {:source {:type "local", :value 6}, :target 8, :file 0, :col 5, :row 5}} {:type "DotStmt", :stmt {:source {:type "local", :value 0}, :key {:type "string_index", :value 2}, :target 9, :file 0, :col 5, :row 6}} {:type "AssignVarStmt", :stmt {:source {:type "local", :value 9}, :target 10, :file 0, :col 5, :row 6}} {:type "EqualStmt", :stmt {:a {:type "local", :value 8}, :b {:type "local", :value 10}, :file 0, :col 5, :row 7}} {:type "AssignVarOnceStmt", :stmt {:source {:type "bool", :value true}, :target 3, :file 0, :col 1, :row 4}}]}, :file 0, :col 5, :row 5}}]} {:stmts [{:type "IsDefinedStmt", :stmt {:source 3, :file 0, :col 1, :row 4}} {:type "AssignVarOnceStmt", :stmt {:source {:type "local", :value 3}, :target 2, :file 0, :col 1, :row 4}}]} {:stmts [{:type "ReturnLocalStmt", :stmt {:source 2, :file 0, :col 1, :row 4}}]}], :path ["g0" "x" "p"]}]}}

Stephan Renatus 2023-11-02T09:44:09.962479Z

(I’ll keep posting what I come up with trying to figure this out on my own)

Stephan Renatus 2023-11-02T09:54:15.525779Z

(m/rewrites
  (m/$ {:type ?t :stmt {:func (m/some ?f) :args ?a :result ?r}})
  [(m/keyword ?t) :func ?f :args ?a :result ?r]
)
woah, so this actually does the trick for any CallStmt that appears anywhere, but haven’t figured out how to deal with the :func being absent for other types

Stephan Renatus 2023-11-02T10:10:44.206009Z

not really. trying to ignore the :func, I’ve changed it to

(m/rewrites
  (m/$ {:type ?t :stmt {:args ?a :result ?r}})
  [(m/keyword ?t) :args ?a :result ?r])
but that only does the right thing on the first statement it encounters, the rest has :args nil :result nil

Stephan Renatus 2023-11-02T10:11:07.845429Z

so I think this is the wrong approach. I’m considered m/cata… 💭

Stephan Renatus 2023-11-02T10:33:50.666589Z

yup this looks better

Stephan Renatus 2023-11-02T10:39:05.610039Z

(m/rewrite plan
        {:plans {:plans [!p ...]}}
	    {:plans [(m/cata !p) ...]}

		{:name ?n :blocks [!b ...]}
		[?n (m/cata !b) ...]

		{:stmts [!s ...]}
		[(m/cata !s) ...]

       	{:type ?t :stmt ?stmt}
        [?t . ?stmt])

Stephan Renatus 2023-11-02T10:39:52.486139Z

now only (1.) is left

Stephan Renatus 2023-11-02T12:22:24.650769Z

{:type (m/some ?t) :stmt (m/some !s)}
        ((m/keyword ?t) . (m/cata {:stmt !s}))

        {:stmt {:file _ :col _ :row _ & ?rest}}
        ?rest
I think this does the trick

Stephan Renatus 2023-11-02T12:46:10.581829Z

I think I get the hang of it https://gist.github.com/srenatus/97f693ca911f060380a3305ba02fe55e