Merge branch 'wasamasa-elisp'
[jackhill/mal.git] / bash / reader.sh
CommitLineData
31690700
JM
1#
2# mal (Make Lisp) Parser/Reader
3#
4
ea81a808
JM
5if [ -z "${__mal_readerr_included__}" ]; then
6__mal_readerr_included=true
7
31690700
JM
8source $(dirname $0)/types.sh
9
10READ_ATOM () {
11 local token=${__reader_tokens[${__reader_idx}]}
12 __reader_idx=$(( __reader_idx + 1 ))
13 case "${token}" in
a61be4d3
JM
14 [0-9]*) _number "${token}" ;;
15 -[0-9]*) _number "${token}" ;;
31690700
JM
16 \"*) token="${token:1:-1}"
17 token="${token//\\\"/\"}"
8d78bc26 18 token="${token//\\n/$'\n'}"
c3256515 19 token="${token//\\\\/\\}"
ea81a808 20 _string "${token}" ;;
b8ee29b2 21 :*) _keyword "${token:1}" ;;
31690700
JM
22 nil) r="${__nil}" ;;
23 true) r="${__true}" ;;
24 false) r="${__false}" ;;
ea81a808 25 *) _symbol "${token}" ;;
31690700
JM
26 esac
27}
28
29# Return seqence of tokens into r.
30# ${1}: Type of r (vector, list)
31# ${2}: starting symbol
32# ${3}: ending symbol
33READ_SEQ () {
34 local start="${1}"
35 local end="${2}"
36 local items=""
37 local token=${__reader_tokens[${__reader_idx}]}
38 __reader_idx=$(( __reader_idx + 1 ))
39 if [[ "${token}" != "${start}" ]]; then
40 r=
41 _error "expected '${start}'"
42 return
43 fi
44 token=${__reader_tokens[${__reader_idx}]}
45 while [[ "${token}" != "${end}" ]]; do
46 if [[ ! "${token}" ]]; then
47 r=
48 _error "exepected '${end}', got EOF"
49 return
50 fi
51 READ_FORM
52 items="${items} ${r}"
53 token=${__reader_tokens[${__reader_idx}]}
54 done
55 __reader_idx=$(( __reader_idx + 1 ))
56 r="${items:1}"
57}
58
59# Return form in r
60READ_FORM () {
61 local token=${__reader_tokens[${__reader_idx}]}
62 case "${token}" in
63 \') __reader_idx=$(( __reader_idx + 1 ))
ea81a808 64 _symbol quote; local q="${r}"
31690700 65 READ_FORM; local f="${r}"
ea81a808 66 _list "${q}" "${f}" ;;
31690700 67 \`) __reader_idx=$(( __reader_idx + 1 ))
ea81a808 68 _symbol quasiquote; local q="${r}"
31690700 69 READ_FORM; local f="${r}"
ea81a808 70 _list "${q}" "${f}" ;;
31690700 71 \~) __reader_idx=$(( __reader_idx + 1 ))
ea81a808 72 _symbol unquote; local q="${r}"
31690700 73 READ_FORM; local f="${r}"
ea81a808 74 _list "${q}" "${f}" ;;
31690700 75 \~\@) __reader_idx=$(( __reader_idx + 1 ))
ea81a808 76 _symbol splice-unquote; local q="${r}"
31690700 77 READ_FORM; local f="${r}"
ea81a808 78 _list "${q}" "${f}" ;;
31690700 79 ^) __reader_idx=$(( __reader_idx + 1 ))
ea81a808 80 _symbol with-meta; local wm="${r}"
31690700
JM
81 READ_FORM; local meta="${r}"
82 READ_FORM; local obj="${r}"
ea81a808 83 _list "${wm}" "${obj}" "${meta}" ;;
31690700 84 @) __reader_idx=$(( __reader_idx + 1 ))
ea81a808 85 _symbol deref; local d="${r}"
31690700 86 READ_FORM; local f="${r}"
ea81a808 87 _list "${d}" "${f}" ;;
31690700
JM
88 \)) _error "unexpected ')'" ;;
89 \() READ_SEQ "(" ")"
ea81a808 90 _list ${r} ;;
31690700
JM
91 \]) _error "unexpected ']'" ;;
92 \[) READ_SEQ "[" "]"
ea81a808 93 _vector ${r} ;;
31690700
JM
94 \}) _error "unexpected '}'" ;;
95 \{) READ_SEQ "{" "}"
ea81a808 96 _hash_map ${r} ;;
31690700
JM
97 *) READ_ATOM
98 esac
99}
100
101# Returns __reader_tokens as an indexed array of tokens
102TOKENIZE () {
103 local data="${*}"
104 local datalen=${#data}
105 local idx=0
106 local chunk=0
107 local chunksz=500
108 local match=
109 local token=
110 local str=
111
112 __reader_idx=0
113 __reader_tokens=
114 while true; do
115 if (( ${#str} < ( chunksz / 2) )) && (( chunk < datalen )); then
116 str="${str}${data:${chunk}:${chunksz}}"
117 chunk=$(( chunk + ${chunksz} ))
118 fi
119 (( ${#str} == 0 )) && break
70aff0c1 120 [[ "${str}" =~ ^^([][{}\(\)^@])|^(~@)|(\"(\\.|[^\\\"])*\")|^(;[^$'\n']*)|^([~\'\`])|^([^][ ~\`\'\";{}\(\)^@\,]+)|^[,]|^[[:space:]]+ ]]
31690700
JM
121 match=${BASH_REMATCH[0]}
122 str="${str:${#match}}"
123 token="${match//$'\n'/}"
124 #echo "MATCH: '${token}' / [${str}]"
125 if ! [[ "${token}" =~ (^[,]$|^[[:space:]]*;.*$|^[[:space:]]*$) ]]; then
126 __reader_tokens[${idx}]="${token}"
127 idx=$(( idx + 1 ))
128 fi
129 if [ -z "${match}" ]; then
31690700 130 _error "Tokenizing error at: ${str:0:50}"
70aff0c1 131 return 1
31690700
JM
132 fi
133 done
134}
135
136# read-str from a raw "string" or from a string object. Retruns object
137# read in r.
138READ_STR () {
139 declare -a __reader_tokens
70aff0c1 140 TOKENIZE "${*}" || return 1 # sets __reader_tokens
31690700 141 #set | grep ^__reader_tokens
b8ee29b2 142 if [ -z "${__reader_tokens[0]}" ]; then
31690700
JM
143 r=
144 return 1 # No tokens
145 fi
146 READ_FORM
147 #echo "Token: ${r}: <${ANON["${r}"]}>"
148 return
149}
150
151# Call readline and save the history. Returns the string read in r.
152READLINE_EOF=
153READLINE_HISTORY_FILE=${HOME}/.mal-history
154READLINE () {
c9de2e82 155 history -r "${READLINE_HISTORY_FILE}" 2>/dev/null || true
31690700
JM
156 read -r -e -p "${1}" r || return "$?"
157 history -s -- "${r}"
c9de2e82 158 history -a "${READLINE_HISTORY_FILE}" 2>/dev/null || true
31690700 159}
ea81a808
JM
160
161fi