This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-10-13
Channels
- # admin-announcements (48)
- # alda (1)
- # aws (24)
- # beginners (4)
- # boot (103)
- # cider (69)
- # clojure (111)
- # clojure-art (5)
- # clojure-dev (35)
- # clojure-greece (2)
- # clojure-nl (3)
- # clojure-russia (1)
- # clojure-shanghai (1)
- # clojurescript (220)
- # clojurescript-ios (1)
- # clojurewerkz (3)
- # community-development (3)
- # core-logic (5)
- # cursive (5)
- # datomic (24)
- # devcards (21)
- # editors (3)
- # funcool (1)
- # hoplon (20)
- # ldnclj (47)
- # ldnproclodo (1)
- # liberator (1)
- # off-topic (7)
- # om (21)
- # onyx (36)
- # reagent (1)
- # ring-swagger (2)
- # spacemacs (38)
- # yada (17)
@cfleming: re: kotlin, does it have a runtime beyond JRE?
@alandipert: Yes, but pretty lightweight:
~/d/cursive (leiningen-fix)> ls -lah lib/kotlin-r*
-rw-r--r-- 1 colin admin 2.1M Oct 13 10:43 lib/kotlin-reflect.jar
-rw-r--r-- 1 colin admin 1.2M Oct 13 10:43 lib/kotlin-runtime.jar
heresy
i am definitely interested in a "system jvm lang"
Fleming’s Law is: never write code in a language you’d be scared to parse, because the tooling will suck
i would say you are debunked by scala in intellij
been living there recently, i can't believe how good it is considering how insane scala is
oh i see
fleming's 0th law, don't use scala
do you have a moment to discuss analyzers?
i remember you saying you made your own for cursive, is that right?
is there a particular organization you subscribe to? and what format do you thread through your passes, if it's architected like that?
I also have to use their AST classes, unless I want to duplicate everything from there into Clojure data structures, which I don’t.
So I have essentially a mirror of Symbol, Keyword, etc in my AST, but the AST is basically what the reader would return, not what something like core.analyzer would produce.
Then analysis is generally per-form, and the various functionality extensions are keyed off the head symbol.
So I set it up like this: (resolve/register-locals :clojure.core/refer-clojure refer-clojure-symbols)
Where refer-clojure-symbols is a function that returns a map of data describing the locals for that form. That will be invoked and passed the form itself, like a macro, and is responsible for its own parsing.
These extensions are generally called back asynchronously by IntelliJ during inspection passes etc.
yes, thanks
do you have your own reader also?
oh sorry, you answered that already
Yes, it’s a JFlex lexer which I’d love to replace with something less quirky, and a recursive descent parser
do you have a sense for how, ideally, you'd do it?
well, i have a toy lisp compiler going... compiles to java
ha, yes, this is like the nth toy lisp, but there are some particular things i want to test with it
the macros that receive arguments expanded thing, principally... but also different semantics for nil
anyway, my first go was a very tools.analyzer-esque AST, maps of maps
and the first mildly tricky thing is closure conversion
and there are various bonus things with that, like optimization passes to warn/elide unused locals, combine closures when possible, etc
but my goal was just to get it end-to-end first, and come up with a reasonable way to add optimization and lint passes later
top level form
you can either emit the java or compile/load in-process with javax.tools.JavaCompiler
So it’s quite different to how Cursive works. IntelliJ will call me for arbitrary forms, saying “run this inspection on this form”, and I inspect the form.
interesting
are you familiar with the concept of "nanopass"?
i'm not sure if it's the best thing though
the direction i'm going is, the way is nanolisps
basically every pass is an interpretation, not just a pattern match/replace
So I can imagine how that would work for unused locals, for example - when you have a form that you know declares locals, so a let or an fn once you’re expanded, you can walk the scope where the locals are valid and see if they’re ever referred to.
altho i'm not sure if it holds water. basically i just got excited that with the right interpreter, fn* dynamically binds its arguments and symbols evaluate to the fn* syntactically above them by looking at this binding
so the AST evaluates, under the interpreter, to some language for interpretation by the next pass
(defn eval0 [[op & args :as form]]
(case op
let0 (let [id (genid)
[bindings & body] args
locals (zipmap (take-nth 2 bindings) (repeat [:let id]))]
(binding [*env* (merge *env* locals)]
(template
(let1 ~id
~(map-nth 2 eval0 bindings)
~@(map eval0 body)))))
fn0 (let [id (genid)
[args & body] args]
(binding [*env* (zipmap args (repeat [:fn id]))]
(template
(fn1 ~id ~args ~@(map eval0 body)))))
ref0 (let [sym (first args)]
(if-let [closure-id (get *env* sym)]
(let [[type id] closure-id]
(template (~(get {:let 'let-ref1 :fn 'fn-ref1} type) ~id ~sym)))
(template (global1 ~sym))))
lit0 (template (lit1 ~@args))
(pass eval0 form)))
i believe so, yes
although i'm not sure what the interface to these passes should be yet
i only have 1 pass so far lol
I think it’s reasonably well documented, and they have a variety of intermediate languages. I believe all their intermediate langs are immutable, but I don’t know the details of how it works.
oh yeah, i think i've run across their docs whilst googling
and i do, on and off... but every time i get a new computer, i forget to restor my rss feeds
He talks a lot about how this works in the guile compiler, really interesting stuff.
oh yeah! i read with great interest his stuff on register vs. stack vm
the dude is clearly an animal
oh wow, this is really juicy, thanks for the pointer!
this continuation numbering process... very reminiscent of exploding maps into quads for datomic
same thing, i suppose. represent a tree as a series of structures instead of a nested map by numbering paths
@alandipert: kotlin-reflect is only required if you’re using Kotlin’s reflection capabilities
@cfleming: good to know about kotlin, thanks!