# mal (Make Lisp) Parser/Reader
#
+if [ -z "${__mal_readerr_included__}" ]; then
+__mal_readerr_included=true
+
source $(dirname $0)/types.sh
READ_ATOM () {
local token=${__reader_tokens[${__reader_idx}]}
__reader_idx=$(( __reader_idx + 1 ))
case "${token}" in
- [0-9]*) number "${token}" ;;
- \"*) token="${token:1:-1}"
+ [0-9]*) _number "${token}" ;;
+ -[0-9]*) _number "${token}" ;;
+ \"*) if [[ ! "${token}" =~ ^\"(\\.|[^\\\"])*\"$ ]]; then
+ _error "expected '\"', got EOF"
+ return
+ fi
+ token="${token:1:-1}"
+ token="${token//\\\\/${__keyw}}"
token="${token//\\\"/\"}"
- string "${token}" ;;
+ token="${token//\\n/$'\n'}"
+ token="${token//${__keyw}/\\}"
+ _string "${token}" ;;
+ :*) _keyword "${token:1}" ;;
nil) r="${__nil}" ;;
true) r="${__true}" ;;
false) r="${__false}" ;;
- *) symbol "${token}" ;;
+ *) _symbol "${token}" ;;
esac
}
while [[ "${token}" != "${end}" ]]; do
if [[ ! "${token}" ]]; then
r=
- _error "exepected '${end}', got EOF"
+ _error "expected '${end}', got EOF"
return
fi
READ_FORM
local token=${__reader_tokens[${__reader_idx}]}
case "${token}" in
\') __reader_idx=$(( __reader_idx + 1 ))
- symbol quote; local q="${r}"
+ _symbol quote; local q="${r}"
READ_FORM; local f="${r}"
- list "${q}" "${f}" ;;
+ _list "${q}" "${f}" ;;
\`) __reader_idx=$(( __reader_idx + 1 ))
- symbol quasiquote; local q="${r}"
+ _symbol quasiquote; local q="${r}"
READ_FORM; local f="${r}"
- list "${q}" "${f}" ;;
+ _list "${q}" "${f}" ;;
\~) __reader_idx=$(( __reader_idx + 1 ))
- symbol unquote; local q="${r}"
+ _symbol unquote; local q="${r}"
READ_FORM; local f="${r}"
- list "${q}" "${f}" ;;
+ _list "${q}" "${f}" ;;
\~\@) __reader_idx=$(( __reader_idx + 1 ))
- symbol splice-unquote; local q="${r}"
+ _symbol splice-unquote; local q="${r}"
READ_FORM; local f="${r}"
- list "${q}" "${f}" ;;
+ _list "${q}" "${f}" ;;
^) __reader_idx=$(( __reader_idx + 1 ))
- symbol with-meta; local wm="${r}"
+ _symbol with-meta; local wm="${r}"
READ_FORM; local meta="${r}"
READ_FORM; local obj="${r}"
- list "${wm}" "${obj}" "${meta}" ;;
+ _list "${wm}" "${obj}" "${meta}" ;;
@) __reader_idx=$(( __reader_idx + 1 ))
- symbol deref; local d="${r}"
+ _symbol deref; local d="${r}"
READ_FORM; local f="${r}"
- list "${d}" "${f}" ;;
+ _list "${d}" "${f}" ;;
\)) _error "unexpected ')'" ;;
\() READ_SEQ "(" ")"
- list ${r} ;;
+ _list ${r} ;;
\]) _error "unexpected ']'" ;;
\[) READ_SEQ "[" "]"
- vector ${r} ;;
+ _vector ${r} ;;
\}) _error "unexpected '}'" ;;
\{) READ_SEQ "{" "}"
- hash_map ${r} ;;
+ _hash_map ${r} ;;
*) READ_ATOM
esac
}
chunk=$(( chunk + ${chunksz} ))
fi
(( ${#str} == 0 )) && break
- [[ "${str}" =~ ^^([][{}\(\)^@])|^(~@)|(\"(\\.|[^\\\"])*\")|^(;[^$'\n']*)|^([~\'\`])|^([^][ ~\`\'\";{}\(\)^@]+)|^[,]|^[[:space:]]+ ]]
+ [[ "${str}" =~ ^^([][{}\(\)^@])|^(~@)|(\"(\\.|[^\\\"])*\"?)|^(;[^$'\n']*)|^([~\'\`])|^([^][ ~\`\'\";{}\(\)^@\,]+)|^[,]|^[[:space:]]+ ]]
match=${BASH_REMATCH[0]}
str="${str:${#match}}"
token="${match//$'\n'/}"
idx=$(( idx + 1 ))
fi
if [ -z "${match}" ]; then
- echo >&2 "Tokenizing error at: ${str:0:50}"
_error "Tokenizing error at: ${str:0:50}"
- break
+ return 1
fi
done
}
# read in r.
READ_STR () {
declare -a __reader_tokens
- TOKENIZE "${*}" # sets __reader_tokens
+ TOKENIZE "${*}" || return 1 # sets __reader_tokens
#set | grep ^__reader_tokens
- if [ -z "${__reader_tokens[k]}" ]; then
+ if [ -z "${__reader_tokens[0]}" ]; then
r=
return 1 # No tokens
fi
READLINE_EOF=
READLINE_HISTORY_FILE=${HOME}/.mal-history
READLINE () {
- history -r "${READLINE_HISTORY_FILE}"
+ history -r "${READLINE_HISTORY_FILE}" 2>/dev/null || true
read -r -e -p "${1}" r || return "$?"
history -s -- "${r}"
- history -a "${READLINE_HISTORY_FILE}"
+ history -a "${READLINE_HISTORY_FILE}" 2>/dev/null || true
}
+
+fi