2 # mal (Make Lisp) Parser/Reader
5 if [ -z "${__mal_readerr_included__}" ]; then
6 __mal_readerr_included
=true
8 source $
(dirname $0)/types.sh
11 local token
=${__reader_tokens[${__reader_idx}]}
12 __reader_idx
=$
(( __reader_idx
+ 1 ))
14 [0-9]*) _number
"${token}" ;;
15 -[0-9]*) _number
"${token}" ;;
16 \"*) if [[ ! "${token}" =~ ^
\"(\\.|
[^
\\\"])*\"$
]]; then
17 _error
"expected '\"', got EOF"
21 token
="${token//\\\\/${__keyw}}"
22 token
="${token//\\\"/\"}"
23 token
="${token//\\n/$'\n'}"
24 token
="${token//${__keyw}/\\}"
26 :*) _keyword
"${token:1}" ;;
28 true
) r
="${__true}" ;;
29 false
) r
="${__false}" ;;
30 *) _symbol
"${token}" ;;
34 # Return seqence of tokens into r.
35 # ${1}: Type of r (vector, list)
36 # ${2}: starting symbol
42 local token
=${__reader_tokens[${__reader_idx}]}
43 __reader_idx
=$
(( __reader_idx
+ 1 ))
44 if [[ "${token}" != "${start}" ]]; then
46 _error
"expected '${start}'"
49 token
=${__reader_tokens[${__reader_idx}]}
50 while [[ "${token}" != "${end}" ]]; do
51 if [[ ! "${token}" ]]; then
53 _error
"expected '${end}', got EOF"
58 token
=${__reader_tokens[${__reader_idx}]}
60 __reader_idx
=$
(( __reader_idx
+ 1 ))
66 local token
=${__reader_tokens[${__reader_idx}]}
68 \') __reader_idx
=$
(( __reader_idx
+ 1 ))
69 _symbol quote
; local q
="${r}"
70 READ_FORM
; local f
="${r}"
71 _list
"${q}" "${f}" ;;
72 \
`) __reader_idx=$(( __reader_idx + 1 ))
73 _symbol quasiquote; local q="${r}"
74 READ_FORM; local f="${r}"
75 _list "${q}" "${f}" ;;
76 \~) __reader_idx=$(( __reader_idx + 1 ))
77 _symbol unquote; local q="${r}"
78 READ_FORM; local f="${r}"
79 _list "${q}" "${f}" ;;
80 \~\@) __reader_idx=$(( __reader_idx + 1 ))
81 _symbol splice-unquote; local q="${r}"
82 READ_FORM; local f="${r}"
83 _list "${q}" "${f}" ;;
84 ^) __reader_idx=$(( __reader_idx + 1 ))
85 _symbol with-meta; local wm="${r}"
86 READ_FORM; local meta="${r}"
87 READ_FORM; local obj="${r}"
88 _list "${wm}" "${obj}" "${meta}" ;;
89 @) __reader_idx=$(( __reader_idx + 1 ))
90 _symbol deref; local d="${r}"
91 READ_FORM; local f="${r}"
92 _list "${d}" "${f}" ;;
93 \)) _error "unexpected ')'" ;;
96 \]) _error "unexpected ']'" ;;
99 \}) _error "unexpected '}'" ;;
106 # Returns __reader_tokens as an indexed array of tokens
109 local datalen=${#data}
120 if (( ${#str} < ( chunksz / 2) )) && (( chunk < datalen )); then
121 str="${str}${data:${chunk}:${chunksz}}"
122 chunk=$(( chunk + ${chunksz} ))
124 (( ${#str} == 0 )) && break
125 [[ "${str}" =~ ^^([][{}\(\)^@])|^(~@)|(\"(\\.|[^\\\"])*\"?)|^(;[^$'\n']*)|^([~\'\`])|^
([^
][ ~\
`\'\";{}\(\)^@\,]+)|^[,]|^[[:space:]]+ ]]
126 match=${BASH_REMATCH[0]}
127 str="${str:${#match}}"
128 token="${match//$'\n'/}"
129 #echo "MATCH: '${token}' / [${str}]"
130 if ! [[ "${token}" =~ (^[,]$|^[[:space:]]*;.*$|^[[:space:]]*$) ]]; then
131 __reader_tokens[${idx}]="${token}"
134 if [ -z "${match}" ]; then
135 _error "Tokenizing error at: ${str:0:50}"
141 # read-str from a raw "string" or from a string object. Retruns object
144 declare -a __reader_tokens
145 TOKENIZE "${*}" || return 1 # sets __reader_tokens
146 #set | grep ^__reader_tokens
147 if [ -z "${__reader_tokens[0]}" ]; then
152 #echo "Token: ${r}: <${ANON["${r}"]}>"
156 # Call readline and save the history. Returns the string read in r.
158 READLINE_HISTORY_FILE=${HOME}/.mal-history
160 history -r "${READLINE_HISTORY_FILE}" 2>/dev/null || true
161 read -r -e -p "${1}" r || return "$?"
163 history -a "${READLINE_HISTORY_FILE}" 2>/dev/null || true