This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-08-02
Channels
- # announcements (5)
- # beginners (35)
- # calva (15)
- # chlorine-clover (9)
- # clj-kondo (8)
- # clojure (34)
- # clojure-europe (6)
- # clojure-uk (1)
- # clojurescript (4)
- # conjure (23)
- # data-science (2)
- # datalog (6)
- # emacs (1)
- # events (8)
- # figwheel-main (3)
- # fulcro (10)
- # jackdaw (3)
- # joker (1)
- # kaocha (1)
- # malli (4)
- # nrepl (1)
- # off-topic (1)
- # pathom (1)
- # re-frame (4)
- # reagent (2)
- # reveal (11)
- # rewrite-clj (15)
- # rum (1)
- # sci (61)
- # shadow-cljs (1)
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?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
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.
I do think edamame could also return these wrapped values, but maybe a function to write your own wrappers might be even more flexible
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.
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
That would be great. Something like a multmethod that matches on type? Or what did you have in mind?
no, nothing like that, just a function (fn [{:keys [:object :location]}])
so you can hook in your own implementation of what you want there
yeah, although I would use a map argument instead of 2 positional ones, so it can be extended
@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}}
Well, that's up to your function, you can just pass through the object itself too, depending on the type
Feel free to play with it and let me know if this works for you, before we merge it.
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 typeyeah, you can instead check if the object supports metadata and then do something different
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
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}]]
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}}]
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}]
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
@kevin.van.rooijen Merged to master. I believe the only change was that :obj-fn
is now called :postprocess
@dominicm I believe you also asked for this feature once, about half a year ago maybe
since EDN etc doesn't have metadata in general but numbers, strings, etc do not carry metadata whatsoever
@kevin.van.rooijen btw, do you have a link to how you're using this, or is it closed source?
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))))
alright. I do recommend using the built-in predicates like (int? ...)
, (boolean? ...)
etc
also (with-meta obj loc)
will replace metadata on the obj, not sure if that's a problem in your tool
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