mirror of
https://github.com/kanaka/mal.git
synced 2024-09-20 10:07:45 +03:00
4eb88ef295
Tested on UCBLogo 6.0 with some minor tweaks (for performance and adding a `timems` function). The tweaks are performed during Docker image creation (see Dockerfile). Tests of step 5 are skipped because UCBLogo is too slow. Interop is available via `(logo-eval "logo code to run")`. The `examples` directory contains a Mal example of drawing a tree using turtle graphics.
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])
|
|
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
|