sci

https://github.com/babashka/SCI - also see #babashka and #nbb
kwrooijen 2020-08-02T10:53:27.359600Z

Hey, I'm working with Edamame at the moment and something I'm currently bumping into is that I don't know the exact position of non meta objects. It would be nice if I could get access to that data somehow. I was thinking maybe a flag to return a wrapper record for non meta types? e.g. somewhere in https://github.com/borkdude/edamame/blob/1357bca1cd38434394028e6280b60ba52a25d83d/src/edamame/impl/parser.cljc#L494-L500 With the following code added

(defrecord EdamameValue [value])
,,,

(with-meta (EdamameValue. obj)
  {(:row-key ctx) (:row loc)
   (:col-key ctx) (:col loc)
   (:end-row-key ctx) (:row end-loc)
   (:end-col-key ctx) (:col end-loc)})
Just a suggestion, not sure if it's a good solution. I would realy benefit from the extra information though. Thoughts?

kwrooijen 2020-08-02T10:54:32.360700Z

I noticed that obj can also be :edamame.impl.parser/expected-delimiter which should be ignored in this case. I don't know if there are any other special forms like this

borkdude 2020-08-02T10:57:15.361800Z

Can you give a concrete example of how you would use this kind of output? FWIW, I'm using rewrite-clj in clj-kondo to get access to all locations, it returns wrapped values.

borkdude 2020-08-02T10:58:25.363300Z

I do think edamame could also return these wrapped values, but maybe a function to write your own wrappers might be even more flexible

borkdude 2020-08-02T10:58:41.363700Z

as it already accepts functions and options for most stuff

kwrooijen 2020-08-02T10:58:57.363900Z

For example right now I'm checking if a value is the correct type. And if it's not I want to output the row / col of that value.

kwrooijen 2020-08-02T10:59:48.364100Z

(Basically writing a simple compiler)

kwrooijen 2020-08-02T11:00:31.364800Z

Or transpiler I should say

borkdude 2020-08-02T11:00:37.365Z

right. so we could hook in a simple function here: https://github.com/borkdude/edamame/blob/1357bca1cd38434394028e6280b60ba52a25d83d/src/edamame/impl/parser.cljc#L494-L500 that gets access to the new obj and metadata, so you could hook in your own thing there

kwrooijen 2020-08-02T11:01:23.365500Z

That would be great. Something like a multmethod that matches on type? Or what did you have in mind?

borkdude 2020-08-02T11:02:43.366600Z

no, nothing like that, just a function (fn [{:keys [:object :location]}]) so you can hook in your own implementation of what you want there

borkdude 2020-08-02T11:03:03.366800Z

let me hack together an example

borkdude 2020-08-02T11:03:19.367Z

first, lunch

kwrooijen 2020-08-02T11:03:39.367200Z

No rush, thanks! 👍

kwrooijen 2020-08-02T11:08:16.367600Z

Something like this then?

borkdude 2020-08-02T11:13:30.368400Z

yeah, although I would use a map argument instead of 2 positional ones, so it can be extended

kwrooijen 2020-08-02T11:23:07.368800Z

Cool, I'll make a PR then

borkdude 2020-08-02T11:24:45.369200Z

no need, I'm already working on it

borkdude 2020-08-02T11:25:01.369500Z

but maybe it would be fun to see if you would come up with the same 😉

kwrooijen 2020-08-02T11:25:22.369800Z

Probably won't though 😛

borkdude 2020-08-02T11:44:17.370200Z

@kevin.van.rooijen So this is what will happen there:

user=> (parse-string "[1]" {:obj-fn (fn [{:keys [:obj :loc]}] {:obj obj :loc loc})})
{:obj [{:obj 1, :loc {:row 1, :col 2, :end-row 1, :end-col 3}}], :loc {:row 1, :col 1, :end-row 1, :end-col 4}}

borkdude 2020-08-02T11:45:42.370800Z

Pushed a commit to a branch: f1f6cfb1f3c2e3057902fc8b92a05c5cb27dce2a

kwrooijen 2020-08-02T11:45:42.370900Z

Ah ok, so this would apply for all types then

borkdude 2020-08-02T11:46:01.371400Z

Well, that's up to your function, you can just pass through the object itself too, depending on the type

borkdude 2020-08-02T11:46:34.372Z

(fn [{:keys [:obj :loc]}] (if (map? obj) obj {:foo obj}))

borkdude 2020-08-02T11:47:05.372600Z

Feel free to play with it and let me know if this works for you, before we merge it.

kwrooijen 2020-08-02T11:47:36.373200Z

Right, currently I have this

(defn object-fn [{:keys [obj location]}]
  (cond
    (= String (type obj))
    (with-meta (->GDString obj) location)

    (= Long (type obj))
    (with-meta (->GDInt obj) location)

    (= Keyword (type obj))
    (with-meta (->GDKeyword obj) location)

    :else
    obj))
With the same idea, except that I was only applying it to the non meta type

kwrooijen 2020-08-02T11:48:16.373600Z

I'll try checking out your commit

borkdude 2020-08-02T11:48:27.373900Z

yeah, you can instead check if the object supports metadata and then do something different

kwrooijen 2020-08-02T11:49:15.374500Z

That's also an option, but I need to check based on type anyway. So I think for my usecase this would be a bit more strict

borkdude 2020-08-02T11:49:34.374700Z

@kevin.van.rooijen

user=> (parse-string "[1]" {:obj-fn (fn [{:keys [:obj :loc]}] (if (instance? clojure.lang.IObj obj) (vary-meta obj merge loc) [obj loc]))})
[[1 {:row 1, :col 2, :end-row 1, :end-col 3}]]

borkdude 2020-08-02T11:51:06.374900Z

or:

user=> (defrecord Wrapper [obj loc])
user.Wrapper
user=> (parse-string "[1]" {:obj-fn (fn [{:keys [:obj :loc]}] (if (instance? clojure.lang.IObj obj) (vary-meta obj merge loc) (->Wrapper obj loc)))})
[#user.Wrapper{:obj 1, :loc {:row 1, :col 2, :end-row 1, :end-col 3}}]

kwrooijen 2020-08-02T11:51:53.375300Z

Ah I see it also takes care of ::expected-delimiter 🙂

borkdude 2020-08-02T11:52:23.375600Z

yeah, that was something I ran into

kwrooijen 2020-08-02T12:02:02.375900Z

Seems to work like a charm 🙂

borkdude 2020-08-02T12:04:23.376300Z

Reading nested objects also seems to work quite well:

user=> (parse-string "#{1 1}" {:obj-fn (fn [{:keys [:obj :loc]}] [obj loc])})
[#{[1 {:row 1, :col 3, :end-row 1, :end-col 4}] [1 {:row 1, :col 5, :end-row 1, :end-col 6}]} {:row 1, :col 1, :end-row 1, :end-col 7}]

borkdude 2020-08-02T12:05:08.376500Z

lucky guess 😉

kwrooijen 2020-08-02T12:05:47.377Z

Tests still pass and my issue is fixed. Good enough for me 😛

borkdude 2020-08-02T12:07:02.377800Z

I might rename the function and write some tests, then I'll merge to master, but for you it will probably only be a keyword change. I'll let it sink in a bit while I do some other stuff

kwrooijen 2020-08-02T12:07:22.378100Z

Sounds good. Thanks a lot for your help!

borkdude 2020-08-02T14:45:31.378800Z

@kevin.van.rooijen Merged to master. I believe the only change was that :obj-fn is now called :postprocess

🎉 1
borkdude 2020-08-02T14:46:04.379400Z

@dominicm I believe you also asked for this feature once, about half a year ago maybe

dominicm 2020-08-02T14:49:24.380100Z

I think I was looking at this for reader tags, so I could error gracefully.

borkdude 2020-08-02T14:51:09.380400Z

edamame also has options for that I believe

borkdude 2020-08-02T14:51:30.380800Z

I think you were looking at the metadata stuff for aero, for validating settings

borkdude 2020-08-02T14:51:59.381400Z

since EDN etc doesn't have metadata in general but numbers, strings, etc do not carry metadata whatsoever

borkdude 2020-08-02T18:02:59.382200Z

@kevin.van.rooijen btw, do you have a link to how you're using this, or is it closed source?

kwrooijen 2020-08-02T18:04:12.382600Z

It's private at the moment. But I can open source it

borkdude 2020-08-02T18:05:33.383600Z

I wonder if you postwalk the structure

kwrooijen 2020-08-02T18:07:37.384Z

Postwalking what exactly?

kwrooijen 2020-08-02T18:08:32.384500Z

This is all I'm doing with it at the moment:

(defn obj-fn [{:keys [obj loc]}]
  (let [loc (-> loc
                (update :row dec)
                (update :end-row dec))]
    (cond
      (= String (type obj))
      (with-meta (->GDString obj) loc)

      (= Long (type obj))
      (with-meta (->GDLong obj) loc)

      (= Keyword (type obj))
      (with-meta (->GDKeyword obj) loc)

      (= Boolean (type obj))
      (with-meta (->GDBoolean obj) loc)

      :else
      (with-meta obj loc))))

borkdude 2020-08-02T18:22:30.385100Z

alright. I do recommend using the built-in predicates like (int? ...), (boolean? ...) etc

kwrooijen 2020-08-02T18:22:56.385500Z

Hm, I'm honestly wondering why I didn't do that 😄

kwrooijen 2020-08-02T18:23:24.385800Z

Nice to have a code review every now and then

borkdude 2020-08-02T18:28:35.386400Z

also (with-meta obj loc) will replace metadata on the obj, not sure if that's a problem in your tool

kwrooijen 2020-08-02T18:29:19.386700Z

I don't think matter since I'm creating the records, right?

kwrooijen 2020-08-02T18:29:57.387500Z

I mean it doesn't matter for me functionally speaking. But if I'm creating the record on the spot, which means they don't have any metadata

borkdude 2020-08-02T18:30:40.388200Z

I was referring to the :else branch where you are not creating records

kwrooijen 2020-08-02T18:33:22.389100Z

Ah right. I noticed that the values in the :else branch didn't have any metadata (in my case). But you're right. to be safe I should be using vary-meta instead

borkdude 2020-08-02T18:33:53.389500Z

Do whatever you want, just something to note 🙂

kwrooijen 2020-08-02T18:35:17.389700Z

I appreciate the feedback 👍