1
1
mirror of https://github.com/kanaka/mal.git synced 2024-08-17 17:50:24 +03:00
mal/impls/picolisp/reader.l
Joel Martin 8a19f60386 Move implementations into impls/ dir
- Reorder README to have implementation list after "learning tool"
  bullet.

- This also moves tests/ and libs/ into impls. It would be preferrable
  to have these directories at the top level.  However, this causes
  difficulties with the wasm implementations which need pre-open
  directories and have trouble with paths starting with "../../". So
  in lieu of that, symlink those directories to the top-level.

- Move the run_argv_test.sh script into the tests directory for
  general hygiene.
2020-02-10 23:50:16 -06:00

127 lines
4.6 KiB
Plaintext

(class +Reader)
# tokens
(dm T (Tokens)
(=: tokens Tokens) )
(dm next> ()
(pop (:: tokens)) )
(dm peek> ()
(car (: tokens)) )
(de read-str (String)
(let (Tokens (tokenizer String)
Reader (new '(+Reader) Tokens) )
(read-form Reader) ) )
(de tokenizer (String)
# [\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)
(let (Special " []{}()'\"`,;" )
(make
(for (Chars (chop String) Chars)
(let Char (pop 'Chars)
(cond
((or (sp? Char) (= Char ","))
# do nothing, whitespace
)
((and (= Char "~") (= (car Chars) "@"))
(link "~@")
(pop 'Chars) ) # remove @ token
((index Char (chop "[]{}()'`~^\@"))
(link Char) )
((= Char "\"")
(link
(pack
(make
(link Char) # HACK
(use Done
(while (and Chars (not Done))
(let Char (pop 'Chars)
(cond
((= Char "\\")
(if Chars
(let Char (pop 'Chars)
(if (= Char "n")
(link "\n")
(link Char) ) )
(throw 'err (MAL-error (MAL-string "expected '\"', got EOF"))) ) )
((<> Char "\"")
(link Char) )
((= Char "\"")
(setq Done T) ) ) ) )
(unless Done
(throw 'err (MAL-error (MAL-string "expected '\"', got EOF"))) ) ) ) ) ) )
((= Char ";")
(while (and Chars (<> Char "\n"))
(setq Char (pop 'Chars)) ) )
((and (not (index Char (chop Special))) (not (sp? Char)))
(link
(pack
(make
(link Char)
(let Char (car Chars)
(while (and Chars (not (index Char (chop Special))) (not (sp? Char)))
(link (pop 'Chars))
(setq Char (car Chars)) ) ) ) ) ) ) ) ) ) ) ) )
(de read-form (Reader)
(case (peek> Reader)
("'" (read-macro Reader 'quote))
("`" (read-macro Reader 'quasiquote))
("~" (read-macro Reader 'unquote))
("~@" (read-macro Reader 'splice-unquote))
("@" (read-macro Reader 'deref))
("\^" (read-meta Reader))
("(" (read-list Reader 'list ")"))
("[" (read-list Reader 'vector "]"))
("{" (read-list Reader 'map "}"))
(T (read-atom Reader)) ) )
(de read-macro (Reader symbol)
(next> Reader) # pop reader macro token
(MAL-list (list (MAL-symbol symbol) (read-form Reader))) )
(de read-meta (Reader)
(next> Reader) # pop reader macro token
(let Form (read-form Reader)
(MAL-list (list (MAL-symbol 'with-meta) (read-form Reader) Form) ) ) )
(de read-list (Reader Type Ender)
(next> Reader) # pop list start
(new (list (case Type
(list '+MALList)
(vector '+MALVector)
(map '+MALMap) ) )
(make
(use Done
(while (not Done)
(let Token (peek> Reader)
(cond
((= Token Ender)
(next> Reader) # pop list end
(setq Done T) )
((not Token)
(let Msg (pack "expected '" Ender "', got EOF")
(throw 'err (MAL-error (MAL-string Msg))) ) )
(T (link (read-form Reader))) ) ) ) ) ) ) )
(de read-atom (Reader)
(let (Token (next> Reader)
Chars (chop Token))
(cond
((= Token "true")
*MAL-true)
((= Token "false")
*MAL-false)
((= Token "nil")
*MAL-nil)
((format Token)
(MAL-number @) )
((= (car Chars) "\"")
(MAL-string (pack (cdr Chars))) )
((= (car Chars) ":")
(MAL-keyword (intern (pack (cdr Chars)))) )
((not Token)
(throw 'err (MAL-error (MAL-string "end of token stream"))) )
(T (MAL-symbol (intern Token))) ) ) )