Commit | Line | Data |
---|---|---|
31690700 JM |
1 | # |
2 | # mal (Make Lisp) Parser/Reader | |
3 | # | |
4 | ||
ea81a808 JM |
5 | if [ -z "${__mal_readerr_included__}" ]; then |
6 | __mal_readerr_included=true | |
7 | ||
31690700 JM |
8 | source $(dirname $0)/types.sh |
9 | ||
10 | READ_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 | |
33 | READ_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 | |
60 | READ_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 | |
102 | TOKENIZE () { | |
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. | |
138 | READ_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. | |
152 | READLINE_EOF= | |
153 | READLINE_HISTORY_FILE=${HOME}/.mal-history | |
154 | READLINE () { | |
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 | |
161 | fi |