Skip to content

Commit 3ac3b3a

Browse files
authored
Build parse options once per load instead of per form (#1090)
1 parent 011619a commit 3ac3b3a

3 files changed

Lines changed: 66 additions & 60 deletions

File tree

src/sci/impl/interpreter.cljc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,10 @@
9797
#?@(:clj [utils/warn-on-reflection-var @utils/warn-on-reflection-var
9898
utils/unchecked-math-var @utils/unchecked-math-var])}
9999
(let [reader (r/indexing-push-back-reader (r/string-push-back-reader s))
100-
eval-string+? (when opts (:sci.impl/eval-string+ opts))]
100+
eval-string+? (when opts (:sci.impl/eval-string+ opts))
101+
parse-opts (parser/parse-opts ctx nil)]
101102
(loop [ret nil]
102-
(let [expr (parser/parse-next ctx reader)]
103+
(let [expr (parser/parse-next* reader parse-opts)]
103104
(if (utils/kw-identical? parser/eof expr)
104105
(if eval-string+?
105106
{:val ret

src/sci/impl/load.cljc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
:clj (instance? clojure.tools.reader.reader_types.IndexingReader reader)
2121
:cljs (implements? r/IndexingReader reader))
2222
reader
23-
(r/indexing-push-back-reader reader))]
23+
(r/indexing-push-back-reader reader))
24+
parse-opts (parser/parse-opts ctx nil)]
2425
(loop [ret nil]
25-
(let [x (parser/parse-next ctx reader)]
26+
(let [x (parser/parse-next* reader parse-opts)]
2627
(if (utils/kw-identical? parser/eof x)
2728
ret
2829
(recur (utils/eval ctx x)))))))

src/sci/impl/parser.cljc

Lines changed: 60 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -123,72 +123,76 @@
123123
(throw (ex-info "EvalReader not allowed when *read-eval* is false."
124124
{:type :sci.error/parse})))
125125

126-
(defn auto-resolve [ctx opts]
127-
(or (:auto-resolve opts)
128-
(let [env (:env ctx)
129-
env-val @env
130-
current-ns (utils/current-ns-name)
131-
the-current-ns (get-in env-val [:namespaces current-ns])
132-
aliases (:aliases the-current-ns)
133-
auto-resolve (assoc aliases :current current-ns)]
134-
auto-resolve)))
135-
136126
(defn get-line-number [reader]
137127
(rt/get-line-number reader))
138128

139129
(defn get-column-number [reader]
140130
(rt/get-column-number reader))
141131

132+
(defn current-ns-auto-resolve [ctx]
133+
(fn [alias]
134+
(let [current-ns (utils/current-ns-name)]
135+
(if (utils/kw-identical? :current alias)
136+
current-ns
137+
(get-in @(:env ctx) [:namespaces current-ns :aliases alias])))))
138+
139+
;; The options only close over ctx: the current namespace, *read-eval* and
140+
;; the readers are read when edamame needs them, so one set of options serves
141+
;; every form of a load.
142+
(defn parse-opts [ctx opts]
143+
(cond-> (assoc default-opts
144+
:features (:features ctx)
145+
:auto-resolve (current-ns-auto-resolve ctx)
146+
:syntax-quote {:resolve-symbol #(fully-qualify ctx %)}
147+
:readers (fn [t]
148+
(let [readers (:readers ctx)
149+
readers (if (utils/var? readers) @readers readers)]
150+
(or (and readers (readers t))
151+
(@data-readers t)
152+
(some-> (@utils/eval-resolve-state ctx {} t)
153+
meta
154+
:sci.impl.record/map-constructor)
155+
(when-let [f @default-data-reader-fn]
156+
(fn [form]
157+
(f t form))))))
158+
:read-eval (fn [x]
159+
(if @read-eval
160+
(utils/eval ctx x)
161+
(throw-eval-read x))))
162+
opts (merge opts)))
163+
164+
(defn parse-next*
165+
"Parses the next form from r with options made by parse-opts."
166+
[r edamame-opts]
167+
(try (let [v (edamame/parse-next r edamame-opts)]
168+
(if (utils/kw-identical? v :edamame.core/eof)
169+
eof
170+
(if (and (symbol? v)
171+
(rt/indexing-reader? r))
172+
(vary-meta v assoc
173+
:line (get-line-number r)
174+
:column (- (get-column-number r)
175+
#?(:cljd (.-length (str v))
176+
:clj (.length (str v))
177+
:cljs (.-length (str v)))))
178+
v)))
179+
(catch #?(:cljd cljd.core/ExceptionInfo
180+
:clj clojure.lang.ExceptionInfo
181+
:cljs cljs.core/ExceptionInfo) e
182+
(throw (ex-info #?(:cljd (ex-message e)
183+
:clj (.getMessage e)
184+
:cljs (.-message e))
185+
(assoc (ex-data e)
186+
:type :sci.error/parse
187+
:phase "parse"
188+
:file @utils/current-file)
189+
e)))))
190+
142191
(defn parse-next
143192
([ctx r]
144193
(parse-next ctx r nil))
145194
([ctx r opts]
146-
(let [features (:features ctx)
147-
readers (:readers ctx)
148-
readers (if (utils/var? readers) @readers readers)
149-
auto-resolve (auto-resolve ctx opts)
150-
parse-opts (cond-> (assoc default-opts
151-
:features features
152-
:auto-resolve auto-resolve
153-
:syntax-quote {:resolve-symbol #(fully-qualify ctx %)}
154-
:readers (fn [t]
155-
(or (and readers (readers t))
156-
(@data-readers t)
157-
(some-> (@utils/eval-resolve-state ctx {} t)
158-
meta
159-
:sci.impl.record/map-constructor)
160-
(when-let [f @default-data-reader-fn]
161-
(fn [form]
162-
(f t form)))))
163-
:read-eval (if @read-eval
164-
(fn [x]
165-
(utils/eval ctx x))
166-
throw-eval-read))
167-
opts (merge opts))
168-
ret (try (let [v (edamame/parse-next r parse-opts)]
169-
(if (utils/kw-identical? v :edamame.core/eof)
170-
eof
171-
(if (and (symbol? v)
172-
(rt/indexing-reader? r))
173-
(vary-meta v assoc
174-
:line (get-line-number r)
175-
:column (- (get-column-number r)
176-
#?(:cljd (.-length (str v))
177-
:clj (.length (str v))
178-
:cljs (.-length (str v)))))
179-
v)))
180-
(catch #?(:cljd cljd.core/ExceptionInfo
181-
:clj clojure.lang.ExceptionInfo
182-
:cljs cljs.core/ExceptionInfo) e
183-
(throw (ex-info #?(:cljd (ex-message e)
184-
:clj (.getMessage e)
185-
:cljs (.-message e))
186-
(assoc (ex-data e)
187-
:type :sci.error/parse
188-
:phase "parse"
189-
:file @utils/current-file)
190-
e))))]
191-
ret)))
195+
(parse-next* r (parse-opts ctx opts))))
192196

193197
(defn reader [x]
194198
(edamame/reader x))

0 commit comments

Comments
 (0)