2015-10-28 16:16:43 -07:00
|
|
|
! Copyright (C) 2015 Jordan Lewis.
|
|
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2017-09-27 19:06:43 +05:30
|
|
|
USING: arrays combinators grouping hashtables kernel lists locals
|
|
|
|
|
make lib.types math.parser regexp sequences splitting strings ;
|
2016-02-24 00:45:40 -06:00
|
|
|
IN: lib.reader
|
2015-10-28 16:16:43 -07:00
|
|
|
|
2019-01-24 12:40:36 -06:00
|
|
|
CONSTANT: token-regex R/ (~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"?|;.*|[^\s\[\]{}('"`,;)~^@]+)/
|
2015-10-28 16:16:43 -07:00
|
|
|
|
|
|
|
|
DEFER: read-form
|
|
|
|
|
|
2017-09-27 19:06:43 +05:30
|
|
|
: (read-string) ( str -- maltype )
|
2019-07-30 23:58:48 -05:00
|
|
|
! dup last CHAR: " = [
|
|
|
|
|
dup R/ ^"(?:\\.|[^\\"])*"$/ matches? [
|
2019-01-24 12:40:36 -06:00
|
|
|
rest but-last R/ \\./ [
|
|
|
|
|
{
|
|
|
|
|
{ [ dup >string "\\\\" = ] [ drop "\\" ] }
|
|
|
|
|
{ [ dup >string "\\n" = ] [ drop "\n" ] }
|
|
|
|
|
{ [ dup >string "\\\"" = ] [ drop "\"" ] }
|
|
|
|
|
[ ]
|
|
|
|
|
} cond
|
|
|
|
|
] re-replace-with
|
|
|
|
|
] [
|
|
|
|
|
"expected '\"', got EOF" throw
|
|
|
|
|
] if ;
|
2017-09-27 19:06:43 +05:30
|
|
|
|
2015-10-28 16:16:43 -07:00
|
|
|
: (read-atom) ( str -- maltype )
|
|
|
|
|
{
|
2017-09-27 19:06:43 +05:30
|
|
|
{ [ dup first CHAR: " = ] [ (read-string) ] }
|
2015-10-28 16:16:43 -07:00
|
|
|
{ [ dup first CHAR: : = ] [ rest <malkeyword> ] }
|
|
|
|
|
{ [ dup "false" = ] [ drop f ] }
|
|
|
|
|
{ [ dup "true" = ] [ drop t ] }
|
|
|
|
|
{ [ dup "nil" = ] [ drop nil ] }
|
|
|
|
|
[ <malsymbol> ]
|
|
|
|
|
} cond ;
|
|
|
|
|
|
|
|
|
|
: read-atom ( str -- maltype )
|
|
|
|
|
dup string>number [ nip ] [ (read-atom) ] if* ;
|
|
|
|
|
|
|
|
|
|
:: read-sequence ( seq closer exemplar -- seq maltype )
|
|
|
|
|
seq [
|
|
|
|
|
[
|
Test uncaught throw, catchless try* . Fix 46 impls.
Fixes made to: ada, c, chuck, clojure, coffee, common-lisp, cpp,
crystal, d, dart, elm, erlang, es6, factor, fsharp, gnu-smalltalk,
groovy, guile, haxe, hy, js, livescript, matlab, miniMAL, nasm, nim,
objc, objpascal, ocaml, perl, perl6, php, plsql, ps, python, r,
rpython, ruby, scheme, swift3, tcl, ts, vb, vimscript, wasm, yorick.
Catchless try* test is an optional test. Not all implementations
support catchless try* but a number were fixed so they at least don't
crash on catchless try*.
2018-12-03 13:20:44 -06:00
|
|
|
[ "expected '" closer "', got EOF" append append throw ]
|
2015-10-28 16:16:43 -07:00
|
|
|
[ dup first closer = ] if-empty
|
|
|
|
|
] [
|
|
|
|
|
read-form ,
|
|
|
|
|
] until rest
|
|
|
|
|
] exemplar make ;
|
|
|
|
|
|
|
|
|
|
: read-list ( seq -- seq maltype )
|
|
|
|
|
")" { } read-sequence ;
|
|
|
|
|
|
|
|
|
|
: read-vector ( seq -- seq maltype )
|
|
|
|
|
"]" V{ } read-sequence ;
|
|
|
|
|
|
|
|
|
|
: read-hashmap ( seq -- seq maltype )
|
|
|
|
|
"}" V{ } read-sequence 2 group parse-hashtable ;
|
|
|
|
|
|
|
|
|
|
: consume-next-into-list ( seq symname -- seq maltype )
|
|
|
|
|
[ read-form ] dip <malsymbol> swap 2array ;
|
|
|
|
|
|
|
|
|
|
: read-form ( seq -- seq maltype )
|
|
|
|
|
unclip {
|
|
|
|
|
{ "(" [ read-list ] }
|
|
|
|
|
{ "[" [ read-vector ] }
|
|
|
|
|
{ "{" [ read-hashmap ] }
|
|
|
|
|
{ "'" [ "quote" consume-next-into-list ] }
|
|
|
|
|
{ "`" [ "quasiquote" consume-next-into-list ] }
|
|
|
|
|
{ "~" [ "unquote" consume-next-into-list ] }
|
|
|
|
|
{ "~@" [ "splice-unquote" consume-next-into-list ] }
|
|
|
|
|
{ "^" [ read-form [ read-form ] dip 2array "with-meta" <malsymbol> prefix ] }
|
|
|
|
|
{ "@" [ "deref" consume-next-into-list ] }
|
|
|
|
|
[ read-atom ]
|
|
|
|
|
} case ;
|
|
|
|
|
|
|
|
|
|
: tokenize ( str -- seq )
|
|
|
|
|
token-regex all-matching-subseqs
|
|
|
|
|
[ first CHAR: ; = not ] filter ;
|
|
|
|
|
|
|
|
|
|
: read-str ( str -- maltype )
|
|
|
|
|
tokenize [ " " throw ] [ read-form nip ] if-empty ;
|