-
Notifications
You must be signed in to change notification settings - Fork 0
/
apl.sh
executable file
·160 lines (151 loc) · 5.75 KB
/
apl.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/bin/bash
RENDER=""
CSVOUTPUT=""
FINAL_OUTPUT="⎕←"
INPUT="SET"
# this allows trains to be rendered as ASCII trees
PREAMBLE="(⎕NS⍬).(_←enableSALT⊣⎕CY'salt')\n]Box on -trains=tree\n"
print_usage() {
echo "Usage: apl [OPTION] {FUNCTION} [input file ⍵]"
echo " apl [OPTION] {FUNCTION} [input file ⍺] [input file ⍵]"
echo " apl --no-input [OPTION] {EXPRESSION}"
echo ""
echo " -d, --debug"
echo " print the generated APL expression, to stderr, before it is evaluated"
echo ""
echo " -ni, --no-input"
echo " don't attempt to read from stdin"
echo " NOTE: reading from stdin is assumed so you need this option if you just"
echo " want to evaluate an expression with no other input"
echo ""
echo " -r {function name}, --render {function name}"
echo " use function (either 'disp' or 'display') to render the final result"
echo ""
echo " -oc, --output-csv"
echo " print the result of the evaluation as CSV"
echo ""
echo " -ic, --input-csv"
echo " treat input file ⍵ as a CSV and read it in using ⎕CSV"
echo " then ⍵ to your function is the array produced by ⎕CSV"
echo ""
echo " -ch, --use-csv-headers"
echo " make the column names of the CSV file available as variables"
echo " which evaluate to the position of the column and which can be"
echo " used to index into the array (by column name)"
echo ""
echo "Examples:"
echo ""
echo " see https://github.com/justin2004/apl_in_the_shell"
echo ""
}
while :; do
case $1 in
-h|--help)
print_usage
;;
-d|--debug) DEBUG="SET"
;;
-ni|--no-input) unset INPUT
;;
-r|--render)
RENDER="$2"
script+="'display' 'disp'⎕CY'dfns' ⋄"
shift
;;
-oc|--output-csv) CSVOUTPUT="SET"
CSVOUTPUT_EXPRESSION="'/dev/stdout'(⎕CSV⍠'IfExists' 'Replace')⍨"
FINAL_OUTPUT="" # ⎕CSV output will return the number of bytes written and we don't want
# that to gunk up stdout
;;
-ic|--input-csv) CSVINPUT="SET"
;;
-ch|--use-csv-headers) USE_CSV_HEADERS="SET"
# now try to get column names
csv_headers_script+="col_names_raw ← ,1↑firstargument ⋄"
csv_headers_script+="col_names← {⍵/⍨^\⍵∊(¯1∘⎕c⎕a),⎕a}¨ col_names_raw ⋄"
# TODO if not col_names ≡ col_names_raw then print a warning?
csv_headers_script+="{⍎¨,/¯1⌽'←',1⌽({⍵},⍕∘⍪∘⍳∘≢)⍵} col_names ⋄"
csv_headers_script+="firstargument ← 1↓firstargument ⋄"
;;
*) break
esac
shift
done
user_function=$1
first=$2
second=$3
if [ -z "$user_function" ]
then
print_usage
# echo ERROR: TODO put a helpful usage message here
# echo "for now look at the README for usage (https://github.com/justin2004/apl_in_the_shell)"
exit 1
fi
if [ ! -z "$first" ]
then
if [ "-" = "$first" ]
then
first="/dev/stdin"
fi
if [ ! -z $CSVINPUT ]
then
script+="firstargument←⎕CSV"\'$first\'" 'UTF-8' (4) ⋄"
# the 4 above means: "The field is to be interpreted numeric data but invalid numeric data is tolerated. Empty fields and fields which cannot be converted to numeric values are returned instead as character data"
# there are other options however: https://help.dyalog.com/18.2/Content/Language/System%20Functions/csv.htm
if [ ! -z $USE_CSV_HEADERS ]
then
script+=$csv_headers_script
fi
else
script+="firstargument←⊃⎕NGET"\'$first\'" 1 ⋄"
fi
if [ ! -z "$second" ]
then
if [ "-" = "$second" ]
then
second="/dev/stdin"
fi
script+="secondargument←⊃⎕NGET"\'$second\'" 1 ⋄"
script+="$FINAL_OUTPUT $RENDER $CSVOUTPUT_EXPRESSION firstargument ($user_function) secondargument"
else
script+="$FINAL_OUTPUT $RENDER $CSVOUTPUT_EXPRESSION ($user_function) firstargument"
fi
else
first="/dev/stdin"
if [ ! -z $CSVINPUT ]
then
# we have csv input from stdin
script+="firstargument←⎕CSV"\'$first\'" 'UTF-8' (4) ⋄"
# the 4 above means: "The field is to be interpreted numeric data but invalid numeric data is tolerated. Empty fields and fields which cannot be converted to numeric values are returned instead as character data"
# there are other options however: https://help.dyalog.com/18.2/Content/Language/System%20Functions/csv.htm
if [ ! -z $USE_CSV_HEADERS ]
then
script+=$csv_headers_script
fi
script+="$FINAL_OUTPUT $RENDER $CSVOUTPUT_EXPRESSION ($user_function) firstargument"
else
# we have input from stdin but it isn't csv
if [ ! -z $INPUT ]
then
# we have input from stdin but it isn't csv AND INPUT was specified (so look for a firstargument)
script+="firstargument←⊃⎕NGET"\'$first\'" 1 ⋄"
script+="$FINAL_OUTPUT $RENDER $CSVOUTPUT_EXPRESSION ($user_function) firstargument"
else
# we have input from stdin but it isn't csv AND INPUT was not specified (so don't look for a firstargument)
USE_PREAMBLE="SET"
# we only want to use the preamble if --no-input is specified
script+="$FINAL_OUTPUT $RENDER $CSVOUTPUT_EXPRESSION ($user_function)"
fi
fi
fi
if [ ! -z $DEBUG ]
then
echo DEBUG: APL script is: >&2
echo DEBUG: $script >&2
fi
if [ ! -z $USE_PREAMBLE ]
then
dyalogscript <(echo -e $PREAMBLE ; echo $script)
else
dyalogscript <(echo $script)
fi