mirror of
https://github.com/kanaka/mal.git
synced 2024-11-08 23:27:30 +03:00
4aa0ebdf47
Add a step1 test to make sure that implementations are properly throwing an error on unclosed strings. Fix 47 implementations and update the guide to note the correct behavior.
222 lines
5.1 KiB
Plaintext
222 lines
5.1 KiB
Plaintext
load "../logo/types.lg
|
|
|
|
make "open_paren_char char 40
|
|
make "close_paren_char char 41
|
|
make "open_bracket_char char 91
|
|
make "close_bracket_char char 93
|
|
make "open_brace_char char 123
|
|
make "close_brace_char char 125
|
|
|
|
to newlinep :char
|
|
output case ascii :char [
|
|
[[10 13] "true]
|
|
[else "false]
|
|
]
|
|
end
|
|
|
|
to whitespacep :char
|
|
output case ascii :char [
|
|
[[9 10 13 32] "true]
|
|
[else "false]
|
|
]
|
|
end
|
|
|
|
to singlechartokenp :char
|
|
output case :char [
|
|
[[ ( ) \[ \] \{ \} ' ` \^ @ ] "true]
|
|
[else "false]
|
|
]
|
|
end
|
|
|
|
to separatorp :char
|
|
output ifelse whitespacep :char [
|
|
"true
|
|
] [
|
|
case :char [
|
|
[[ ( ) \[ \] \{ \} ' \" ` , \; ] "true]
|
|
[else "false]
|
|
]
|
|
]
|
|
end
|
|
|
|
to read_comment_token :s
|
|
localmake "rest :s
|
|
while [not emptyp :rest] [
|
|
localmake "c first :rest
|
|
ifelse newlinep :c [
|
|
output list " butfirst :rest
|
|
] [
|
|
make "rest butfirst :rest
|
|
]
|
|
]
|
|
output list " :rest
|
|
end
|
|
|
|
to read_word_token :s
|
|
localmake "w "
|
|
localmake "rest :s
|
|
while [not emptyp :rest] [
|
|
localmake "c first :rest
|
|
ifelse separatorp :c [
|
|
output list :w :rest
|
|
] [
|
|
make "w word :w :c
|
|
make "rest butfirst :rest
|
|
]
|
|
]
|
|
output list :w :rest
|
|
end
|
|
|
|
to read_string_token :s
|
|
localmake "w first :s
|
|
localmake "rest butfirst :s
|
|
while [not emptyp :rest] [
|
|
localmake "c first :rest
|
|
if :c = "" [
|
|
make "w word :w :c
|
|
output list :w butfirst :rest
|
|
]
|
|
if :c = "\\ [
|
|
make "w word :w :c
|
|
make "rest butfirst :rest
|
|
make "c first :rest
|
|
]
|
|
make "w word :w :c
|
|
make "rest butfirst :rest
|
|
]
|
|
(throw "error [Expected closing quotes, not EOF])
|
|
end
|
|
|
|
to read_next_token :s
|
|
localmake "c first :s
|
|
localmake "rest butfirst :s
|
|
output cond [
|
|
[[whitespacep :c] list " :rest]
|
|
[[:c = ",] list " :rest]
|
|
[[:c = "~] ifelse ((first :rest) = "@) [list "~@ butfirst :rest] [list "~ :rest] ]
|
|
[[singlechartokenp :c] list :c :rest]
|
|
[[:c = "\;] read_comment_token :s]
|
|
[[:c = ""] read_string_token :s]
|
|
[else read_word_token :s]
|
|
]
|
|
output list first :s butfirst :s
|
|
end
|
|
|
|
to tokenize :str
|
|
localmake "tokens []
|
|
localmake "s :str
|
|
while [not emptyp :s] [
|
|
localmake "res read_next_token :s
|
|
localmake "token first :res
|
|
make "s last :res
|
|
if not emptyp :token [
|
|
make "tokens lput :token :tokens
|
|
]
|
|
]
|
|
output :tokens
|
|
end
|
|
|
|
to reader_new :tokens
|
|
output listtoarray list :tokens 1
|
|
end
|
|
|
|
to reader_peek :reader
|
|
localmake "tokens item 1 :reader
|
|
localmake "pos item 2 :reader
|
|
if :pos > count :tokens [output []]
|
|
output item :pos :tokens
|
|
end
|
|
|
|
to reader_next :reader
|
|
make "token reader_peek :reader
|
|
localmake "pos item 2 :reader
|
|
setitem 2 :reader (1 + :pos)
|
|
output :token
|
|
end
|
|
|
|
to unescape_string :token
|
|
localmake "s butfirst butlast :token ; remove surrounding double-quotes
|
|
localmake "i 1
|
|
localmake "res "
|
|
while [:i <= count :s] [
|
|
localmake "c item :i :s
|
|
ifelse :c = "\\ [
|
|
make "i (:i + 1)
|
|
make "c item :i :s
|
|
make "res word :res case :c [
|
|
[[ n ] char 10]
|
|
[[ " ] "\" ]
|
|
[[ \\ ] "\\ ]
|
|
[else :c]
|
|
]
|
|
] [
|
|
make "res word :res :c
|
|
]
|
|
make "i (:i + 1)
|
|
]
|
|
output :res
|
|
end
|
|
|
|
to read_atom :reader
|
|
localmake "token reader_next :reader
|
|
output cond [
|
|
[[:token = "nil] nil_new]
|
|
[[:token = "true] true_new]
|
|
[[:token = "false] false_new]
|
|
[[numberp :token] obj_new "number :token]
|
|
[[(first :token) = ": ] obj_new "keyword butfirst :token]
|
|
[[(first :token) = "\" ] obj_new "string unescape_string :token]
|
|
[else symbol_new :token]
|
|
]
|
|
end
|
|
|
|
to read_seq :reader :value_type :start_char :end_char
|
|
localmake "token reader_next :reader
|
|
if :token <> :start_char [(throw "error sentence "expected (word "' :start_char "'))]
|
|
localmake "seq []
|
|
make "token reader_peek :reader
|
|
while [:token <> :end_char] [
|
|
if emptyp :token [(throw "error (sentence [expected] (word "' :end_char "',) [got EOF]))]
|
|
make "seq lput read_form :reader :seq
|
|
make "token reader_peek :reader
|
|
]
|
|
ignore reader_next :reader
|
|
output obj_new :value_type :seq
|
|
end
|
|
|
|
to reader_macro :reader :symbol_name
|
|
ignore reader_next :reader
|
|
output obj_new "list list symbol_new :symbol_name read_form :reader
|
|
end
|
|
|
|
to with_meta_reader_macro :reader
|
|
ignore reader_next :reader
|
|
localmake "meta read_form :reader
|
|
output obj_new "list (list symbol_new "with-meta read_form :reader :meta)
|
|
end
|
|
|
|
to read_form :reader
|
|
output case reader_peek :reader [
|
|
[[ ' ] reader_macro :reader "quote ]
|
|
[[ ` ] reader_macro :reader "quasiquote ]
|
|
[[ ~ ] reader_macro :reader "unquote ]
|
|
[[ ~@ ] reader_macro :reader "splice-unquote ]
|
|
[[ \^ ] with_meta_reader_macro :reader ]
|
|
[[ @ ] reader_macro :reader "deref ]
|
|
[[ ( ] read_seq :reader "list :open_paren_char :close_paren_char ]
|
|
[[ ) ] (throw "error sentence [unexpected] (word "' :close_paren_char "')) ]
|
|
[[ \[ ] read_seq :reader "vector :open_bracket_char :close_bracket_char ]
|
|
[[ \] ] (throw "error sentence [unexpected] (word "' :close_bracket_char "')) ]
|
|
[[ \{ ] read_seq :reader "hashmap :open_brace_char :close_brace_char ]
|
|
[[ \} ] (throw "error sentence [unexpected] (word "' :close_brace_char "')) ]
|
|
[else read_atom :reader]
|
|
]
|
|
end
|
|
|
|
to read_str :str
|
|
localmake "tokens tokenize :str
|
|
if emptyp :tokens [output []]
|
|
localmake "reader reader_new :tokens
|
|
output read_form :reader
|
|
end
|