aboutsummaryrefslogtreecommitdiff
path: root/bash/reader.sh
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-03-24 16:32:24 -0500
committerJoel Martin <github@martintribe.org>2014-03-24 16:32:24 -0500
commit3169070063b2cb877200117ebb384269d73bcb93 (patch)
tree23de3db1ea5c37afd21a45b6ed7771f56a08c0c4 /bash/reader.sh
downloadmal-3169070063b2cb877200117ebb384269d73bcb93.tar.gz
mal-3169070063b2cb877200117ebb384269d73bcb93.zip
Current state of mal for Clojure West lighting talk.
Diffstat (limited to 'bash/reader.sh')
-rw-r--r--bash/reader.sh153
1 files changed, 153 insertions, 0 deletions
diff --git a/bash/reader.sh b/bash/reader.sh
new file mode 100644
index 0000000..bc32fa7
--- /dev/null
+++ b/bash/reader.sh
@@ -0,0 +1,153 @@
+#
+# mal (Make Lisp) Parser/Reader
+#
+
+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}"
+ token="${token//\\\"/\"}"
+ string "${token}" ;;
+ nil) r="${__nil}" ;;
+ true) r="${__true}" ;;
+ false) r="${__false}" ;;
+ *) symbol "${token}" ;;
+ esac
+}
+
+# Return seqence of tokens into r.
+# ${1}: Type of r (vector, list)
+# ${2}: starting symbol
+# ${3}: ending symbol
+READ_SEQ () {
+ local start="${1}"
+ local end="${2}"
+ local items=""
+ local token=${__reader_tokens[${__reader_idx}]}
+ __reader_idx=$(( __reader_idx + 1 ))
+ if [[ "${token}" != "${start}" ]]; then
+ r=
+ _error "expected '${start}'"
+ return
+ fi
+ token=${__reader_tokens[${__reader_idx}]}
+ while [[ "${token}" != "${end}" ]]; do
+ if [[ ! "${token}" ]]; then
+ r=
+ _error "exepected '${end}', got EOF"
+ return
+ fi
+ READ_FORM
+ items="${items} ${r}"
+ token=${__reader_tokens[${__reader_idx}]}
+ done
+ __reader_idx=$(( __reader_idx + 1 ))
+ r="${items:1}"
+}
+
+# Return form in r
+READ_FORM () {
+ local token=${__reader_tokens[${__reader_idx}]}
+ case "${token}" in
+ \') __reader_idx=$(( __reader_idx + 1 ))
+ symbol quote; local q="${r}"
+ READ_FORM; local f="${r}"
+ list "${q}" "${f}" ;;
+ \`) __reader_idx=$(( __reader_idx + 1 ))
+ symbol quasiquote; local q="${r}"
+ READ_FORM; local f="${r}"
+ list "${q}" "${f}" ;;
+ \~) __reader_idx=$(( __reader_idx + 1 ))
+ symbol unquote; local q="${r}"
+ READ_FORM; local f="${r}"
+ list "${q}" "${f}" ;;
+ \~\@) __reader_idx=$(( __reader_idx + 1 ))
+ symbol splice-unquote; local q="${r}"
+ READ_FORM; local f="${r}"
+ list "${q}" "${f}" ;;
+ ^) __reader_idx=$(( __reader_idx + 1 ))
+ symbol with-meta; local wm="${r}"
+ READ_FORM; local meta="${r}"
+ READ_FORM; local obj="${r}"
+ list "${wm}" "${obj}" "${meta}" ;;
+ @) __reader_idx=$(( __reader_idx + 1 ))
+ symbol deref; local d="${r}"
+ READ_FORM; local f="${r}"
+ list "${d}" "${f}" ;;
+ \)) _error "unexpected ')'" ;;
+ \() READ_SEQ "(" ")"
+ list ${r} ;;
+ \]) _error "unexpected ']'" ;;
+ \[) READ_SEQ "[" "]"
+ vector ${r} ;;
+ \}) _error "unexpected '}'" ;;
+ \{) READ_SEQ "{" "}"
+ hash_map ${r} ;;
+ *) READ_ATOM
+ esac
+}
+
+# Returns __reader_tokens as an indexed array of tokens
+TOKENIZE () {
+ local data="${*}"
+ local datalen=${#data}
+ local idx=0
+ local chunk=0
+ local chunksz=500
+ local match=
+ local token=
+ local str=
+
+ __reader_idx=0
+ __reader_tokens=
+ while true; do
+ if (( ${#str} < ( chunksz / 2) )) && (( chunk < datalen )); then
+ str="${str}${data:${chunk}:${chunksz}}"
+ chunk=$(( chunk + ${chunksz} ))
+ fi
+ (( ${#str} == 0 )) && break
+ [[ "${str}" =~ ^^([][{}\(\)^@])|^(~@)|(\"(\\.|[^\\\"])*\")|^(;[^$'\n']*)|^([~\'\`])|^([^][ ~\`\'\";{}\(\)^@]+)|^[,]|^[[:space:]]+ ]]
+ match=${BASH_REMATCH[0]}
+ str="${str:${#match}}"
+ token="${match//$'\n'/}"
+ #echo "MATCH: '${token}' / [${str}]"
+ if ! [[ "${token}" =~ (^[,]$|^[[:space:]]*;.*$|^[[:space:]]*$) ]]; then
+ __reader_tokens[${idx}]="${token}"
+ idx=$(( idx + 1 ))
+ fi
+ if [ -z "${match}" ]; then
+ echo >&2 "Tokenizing error at: ${str:0:50}"
+ _error "Tokenizing error at: ${str:0:50}"
+ break
+ fi
+ done
+}
+
+# read-str from a raw "string" or from a string object. Retruns object
+# read in r.
+READ_STR () {
+ declare -a __reader_tokens
+ TOKENIZE "${*}" # sets __reader_tokens
+ #set | grep ^__reader_tokens
+ if [ -z "${__reader_tokens[k]}" ]; then
+ r=
+ return 1 # No tokens
+ fi
+ READ_FORM
+ #echo "Token: ${r}: <${ANON["${r}"]}>"
+ return
+}
+
+# Call readline and save the history. Returns the string read in r.
+READLINE_EOF=
+READLINE_HISTORY_FILE=${HOME}/.mal-history
+READLINE () {
+ history -r "${READLINE_HISTORY_FILE}"
+ read -r -e -p "${1}" r || return "$?"
+ history -s -- "${r}"
+ history -a "${READLINE_HISTORY_FILE}"
+}