diff options
| author | Joel Martin <github@martintribe.org> | 2014-03-24 16:32:24 -0500 |
|---|---|---|
| committer | Joel Martin <github@martintribe.org> | 2014-03-24 16:32:24 -0500 |
| commit | 3169070063b2cb877200117ebb384269d73bcb93 (patch) | |
| tree | 23de3db1ea5c37afd21a45b6ed7771f56a08c0c4 /bash/reader.sh | |
| download | mal-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.sh | 153 |
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}" +} |
