1 Object subclass: Reader [
4 TokenRegex := '[\s,]*(~@|[\[\]{}()''`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}(''"`,;)]*)'.
6 NumberRegex := '-?[0-9]+(?:\.[0-9]+)?'.
8 Reader class >>
tokenizer: input
[
9 | tokens token hit pos done |
10 tokens
:= OrderedCollection new
.
15 hit
:= input
searchRegex: TokenRegex startingAt: pos
.
17 token size
= 0 ifTrue: [
18 tokens
add: (input
copyFrom: pos
to: input size
) trimSeparators
.
21 (token size
= 0 or: [token
matchRegex: CommentRegex]) ifFalse: [
24 pos
:= pos
+ (hit match size
).
25 pos > input size
ifTrue: [
32 Reader class >>
readStr: input
[
33 | tokens reader form |
34 tokens
:= self tokenizer: input
.
35 reader
:= self new: tokens
.
36 tokens isEmpty
ifTrue: [
37 ^MALEmptyInput new signal
39 ^self readForm: reader
.
42 Reader class >>
readForm: reader
[
46 ^self readList: reader
class: MALList ender: ')'
49 ^self readList: reader
class: MALVector ender: ']'
52 ^self readList: reader
class: MALMap ender: '}'
55 (token
matchRegex: '[])}]') ifTrue: [
56 ^MALUnexpectedToken new
signal: token
59 token
= '''' ifTrue: [
60 ^self readSimpleMacro: reader
name: #quote
63 ^self readSimpleMacro: reader
name: #quasiquote
66 ^self readSimpleMacro: reader
name: #unquote
68 token
= '~@' ifTrue: [
69 ^self readSimpleMacro: reader
name: #'splice-unquote'
72 ^self readSimpleMacro: reader
name: #deref
76 ^self readWithMetaMacro: reader
79 ^self readAtom: reader
82 Reader class >>
readList: reader
class: aClass
ender: ender
[
84 storage
:= OrderedCollection new
.
87 [ token
:= reader peek
. token isNil
] whileFalse: [
88 token
= ender
ifTrue: [
90 storage
:= storage asDictionary
.
96 storage
add: (self readForm: reader
).
98 ^MALUnterminatedSequence new
signal: ender
101 Reader class >>
readAtom: reader
[
103 token
:= reader next
.
105 token
= 'true' ifTrue: [ ^MALObject True ].
106 token
= 'false' ifTrue: [ ^MALObject False ].
107 token
= 'nil' ifTrue: [ ^MALObject Nil ].
109 (token first
= $") ifTrue: [
110 (token last = $") ifTrue: [
111 ^MALString new: token parse
113 ^MALUnterminatedSequence new
signal: '"'
117 (token
matchRegex: NumberRegex) ifTrue: [
118 ^MALNumber new: token asNumber
121 (token first
= $:) ifTrue: [
122 ^MALKeyword new: token allButFirst asSymbol
125 ^MALSymbol new: token asSymbol
128 Reader class >>
readSimpleMacro: reader
name: name
[
130 "pop reader macro token"
132 form
:= self readForm: reader
.
133 list
:= OrderedCollection from: { MALSymbol new: name
. form
}.
137 Reader class >>
readWithMetaMacro: reader
[
139 "pop reader macro token"
141 meta
:= self readForm: reader
.
142 form
:= self readForm: reader
.
143 list
:= OrderedCollection from:
144 { MALSymbol new: #'with-meta'. form
. meta
}.
148 Reader class >>
new: tokens
[
161 ^storage
at: index
ifAbsent: [ nil ]