-
-
Notifications
You must be signed in to change notification settings - Fork 14
/
core.cljc
157 lines (125 loc) · 5.16 KB
/
core.cljc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
(ns edamame.core
(:require
[clojure.tools.reader.reader-types :as rt]
[edamame.impl.parser :as p]
[clojure.string :as str]
[edamame.impl.ns-parser :as nsp]))
(defn parse-string
"Parses first EDN value from string.
Supported parsing options can be `true` for default behavior or a function
that is called on the form and returns a form in its place:
`:deref`: parse forms starting with `@`. If `true`, the resulting
expression will be parsed as `(deref expr)`.
`:fn`: parse function literals (`#(inc %)`). If `true`, will be parsed as `(fn [%1] (inc %))`.
`:quote`: parse quoted expression `'foo`. If `true`, will be parsed as `(quote foo)`.
`:read-eval`: parse read-eval (`=(+ 1 2 3)`). If `true`, the
resulting expression will be parsed as `(read-eval (+ 1 2 3))`.
`:regex`: parse regex literals (`#\"foo\"`). If `true`, defaults to
`re-pattern`.
`:var`: parse var literals (`#'foo`). If `true`, the resulting
expression will be parsed as `(var foo)`.
`:syntax-quote`: parse syntax-quote (`(+ 1 2 3)`). Symbols get
qualified using `:resolve-symbol` which defaults to `identity`:
```clojure
(parse-string \"`x\" {:syntax-quote {:resolve-symbol #(symbol \"user\" (str %))}})
;;=> (quote user/x)
```
By default, also parses `unquote` and `unquote-splicing` literals,
resolving them accordingly.
`:unquote`: parse unquote (`~x`). Requires `:syntax-quote` to be set.
If `true` and not inside `syntax-quote`, defaults to `clojure.core/unquote`.
`:unquote-splicing`: parse unquote-splicing (`~@x`). Requires `:syntax-quote`
to be set. If `true` and not inside `syntax-quote`, defaults
to `clojure.core/unquote-splicing`.
`:all`: when `true`, the above options will be set to `true` unless
explicitly provided.
Supported options for processing reader conditionals:
`:read-cond`: - `:allow` to process reader conditionals, or
`:preserve` to keep all branches
`:features`: - persistent set of feature keywords for reader conditionals (e.g. `#{:clj}`).
`:auto-resolve`: map of alias to namespace symbols for
auto-resolving keywords. Use `:current` as the alias for the current
namespace.
`:readers`: data readers.
`:postprocess`: a function that is called with a map containing
`:obj`, the read value, and `:loc`, the location metadata. This can
be used to handle objects that cannot carry metadata differently. If
this option is provided, attaching location metadata is not
automatically added to the object.
`:location?`: a predicate that is called with the parsed
object. Should return a truthy value to determine if location
information will be added.
`:uneval`: a function of a map with `:uneval` and `:next` to preserve `#_` expressions by combining them with next value.
Additional arguments to tools.reader may be passed with
`:tools.reader/opts`, like `:readers` for passing reader tag functions.
"
([s]
(p/parse-string s nil))
([s opts]
(p/parse-string s opts)))
(defn parse-string-all
"Like `parse-string` but parses all values from string and returns them
in a vector."
([s]
(p/parse-string-all s nil))
([s opts]
(p/parse-string-all s opts)))
(defn reader
"Coerces x into indexing pushback-reader to be used with
parse-next. Accepts string or `java.io.Reader`"
[x]
(p/reader x))
(defn source-reader
"Coerces x into source-logging-reader to be used with
parse-next. Accepts string or `java.io.Reader`"
[x]
(p/source-logging-reader x))
(defn get-line-number [reader]
(p/get-line-number reader))
(defn get-column-number [reader]
(p/get-column-number reader))
(defn normalize-opts
"Expands `opts` into normalized opts, e.g. `:all true` is expanded
into explicit options."
[opts]
(p/normalize-opts opts))
(defn parse-next
"Parses next form from reader. Accepts same opts as `parse-string`,
but must be normalized with `normalize-opts` first."
([reader] (parse-next reader (p/normalize-opts {})))
([reader normalized-opts]
(when (rt/source-logging-reader? reader)
(let [^StringBuilder buf (p/buf reader)]
#?(:clj (.setLength buf 0)
:cljs (.clear buf))))
(let [v (p/parse-next normalized-opts reader)]
(if (identical? p/eof v)
(or (get normalized-opts :eof)
::eof)
v))))
(defn parse-next+string
"Parses next form from reader. Accepts same opts as `parse-string`,
but must be normalized with `normalize-opts` first.
Returns read value + string read (whitespace-trimmed)."
([reader] (parse-next+string reader (p/normalize-opts {})))
([reader normalized-opts]
(if (rt/source-logging-reader? reader)
(let [v (parse-next reader normalized-opts)
s (str/trim (str (p/buf reader)))]
[v s])
(throw (ex-info "parse-next+string must be called with source-reader" {})))))
(defn iobj?
"Returns true if obj can carry metadata."
[obj]
#?(:clj
(instance? clojure.lang.IObj obj)
:cljs (satisfies? IWithMeta obj)))
(defn parse-ns-form
"Parses `ns-form`, an s-expression, into map with:
- `:name`: the name of the namespace
- `:aliases`: a map of aliases to lib names"
[ns-form]
(nsp/parse-ns-form ns-form))
;;;; Scratch
(comment
(parse-string "(1 2 3 #_4)"))