Merge pull request #386 from asarhaddon/test-let-recursive-def
[jackhill/mal.git] / bash / reader.sh
index bc32fa7..ca806f7 100644 (file)
@@ -2,20 +2,32 @@
 # 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
 }
 
@@ -38,7 +50,7 @@ READ_SEQ () {
     while [[ "${token}" != "${end}" ]]; do
         if [[ ! "${token}" ]]; then
             r=
-            _error "exepected '${end}', got EOF"
+            _error "expected '${end}', got EOF"
             return
         fi
         READ_FORM
@@ -54,39 +66,39 @@ 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
 }
@@ -110,7 +122,7 @@ TOKENIZE () {
             chunk=$(( chunk + ${chunksz} ))
         fi
         (( ${#str} == 0 )) && break
-        [[ "${str}" =~ ^^([][{}\(\)^@])|^(~@)|(\"(\\.|[^\\\"])*\")|^(;[^$'\n']*)|^([~\'\`])|^([^][ ~\`\'\";{}\(\)^@]+)|^[,]|^[[:space:]]+ ]]
+        [[ "${str}" =~ ^^([][{}\(\)^@])|^(~@)|(\"(\\.|[^\\\"])*\"?)|^(;[^$'\n']*)|^([~\'\`])|^([^][ ~\`\'\";{}\(\)^@\,]+)|^[,]|^[[:space:]]+ ]]
         match=${BASH_REMATCH[0]}
         str="${str:${#match}}"
         token="${match//$'\n'/}"
@@ -120,9 +132,8 @@ TOKENIZE () {
             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
 }
@@ -131,9 +142,9 @@ TOKENIZE () {
 # 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
@@ -146,8 +157,10 @@ READ_STR () {
 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