-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBuiltins.fs
395 lines (354 loc) · 13 KB
/
Builtins.fs
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
module Builtins
open System
open ProjectParser
open InterpreterTypes
open ScopeHelper
exception BuiltinException of string
let noarg name args =
match args with
| [] -> ()
| _ -> raise (BuiltinException
(sprintf "%s: can only be called with no arguments" name))
let singlearg name args =
match args with
| [x] -> x
| _ -> raise (BuiltinException
(sprintf "%s: can only be called with one argument" name))
let twoarg name args =
match args with
| [x; y] -> x, y
| _ -> raise (BuiltinException
(sprintf "%s: can only be called with two arguments" name))
let anonfuncargs i =
[0..(i-1)]
|> List.map (sprintf "arg%i")
|> String.concat ","
let btryint args =
match singlearg "tryint" args with
| ValInt i -> ValBool true
| ValString s ->
match tryParseInt s with
| Some _ -> ValBool true
| None -> ValBool false
| _ -> ValBool false
let bint args =
match singlearg "int" args with
| ValInt i -> ValInt i
| ValString s ->
match tryParseInt s with
| Some i -> ValInt i
| None -> ValNone
| _ -> ValNone
let rec bstropt inner args scope =
match singlearg "tostring" args with
| ValInt i -> ValString (sprintf "%i" i), scope
| ValString s ->
if inner then
ValString (sprintf "\"%s\"" s), scope
else
ValString (sprintf "%s" s), scope
| ValBool b -> ValString (if b then "true" else "false"), scope
| ValListReference ref ->
let values = getListFromRef ref scope
let rec bprintinner xs scope =
match xs with
| [] -> [], scope
| v :: remaining ->
let vOut, newScope = bstropt true [v] scope
match vOut with
| ValString s ->
let rest, newScope2 = bprintinner remaining newScope
s :: rest, newScope2
| _ -> raise (BuiltinException "Invalid return type for ToString")
let outList, outScope = bprintinner values scope
ValString (sprintf "[%s]" (String.concat ", " outList)), outScope
| ValNone -> ValString "none", scope
| ValReference xs ->
match xs with
| [] -> ValString ("emptyref"), scope
| x :: _ ->
match x with
| ScopeGlobal -> ValString ("global"), scope
| TempBlock -> ValString ("tempblock"), scope
| FuncLocal (s, i) ->
ValString (sprintf "local %s: %i" s i), scope
| ScopeLocal s -> ValString (sprintf "type %s" s), scope
| ScopeInstance (s, i) ->
ValString (sprintf "instance %s: %i" s i), scope
| ValFunc (args, _) ->
ValString (sprintf "anonfunc(%s)" (anonfuncargs args.Length)), scope
| ValBuiltinFunc _ -> ValString ("builtinfunc"), scope
| ValListInner _ ->
raise (BuiltinException "tostring: cannot directly access list inner")
| ValOrderedNamespace _ ->
raise (BuiltinException
"tostring: cannot directly access ordered namespace")
//| _ -> raise (BuiltinException "tostring: input type cannot be converted to string")
let bstr args scope =
bstropt false args scope
let bprintraw newline args scope =
let v, newScope = bstr args scope
match v with
| ValString s ->
let printfunc = if newline then printfn else printf
printfunc "%s" s; ValNone, newScope
| _ -> raise (BuiltinException "Invalid return type for ToString")
let bprint args scope =
let v, newScope = bprintraw true args scope
v, newScope
let bToCharList args scope =
match singlearg "toCharList" args with
| ValString s ->
let vs = Seq.toList s |> List.map (int >> ValInt)
makeNewList vs scope
| _-> raise (BuiltinException "toCharList: invalid input type")
let bFromCharList args scope =
match singlearg "fromCharList" args with
| ValListReference ref ->
let rec fromCharListInner vs =
match vs with
| [] -> []
| v :: remaining ->
match v with
| ValInt i ->
char i :: fromCharListInner remaining
| _ ->
raise (BuiltinException
"fromCharList: element not a number")
let vs = getListFromRef ref scope
ValString (new String(fromCharListInner vs |> Array.ofList)), scope
| _ -> raise (BuiltinException "fromCharList: invalid input type")
let bCharToStr args =
match singlearg "charToStr" args with
| ValInt i ->
ValString (new String([|char i|]))
| _ -> raise (BuiltinException "charToStr: invalid input type")
let bCharAt args =
match twoarg "charAt" args with
| ValString s, ValInt i ->
if i >= s.Length || i < 0 then
raise (BuiltinException "charAt: index out of bounds")
ValInt (int (Seq.toArray s).[i])
| _ -> raise (BuiltinException "charAt: invalid input type")
let binput args scope =
match args with
| [] -> ValString(Console.ReadLine()), scope
| [v] ->
let _, newScope = bprintraw false [v] scope
ValString(Console.ReadLine()), newScope
| _ ->
raise (BuiltinException "input: incorrect number of arguments")
let bsqrt args =
match singlearg "sqrt" args with
| ValInt i -> ValInt (int (sqrt (float i)))
| _ -> raise (BuiltinException "sqrt: invalid input type")
let bnot e =
match e with
| ValBool b -> ValBool (not b)
| _ -> raise (BuiltinException "!: type error - not a boolean")
let bpushf args scope =
match twoarg "pushf" args with
| ValListReference ref, v ->
let xs = getListFromRef ref scope
ValNone, setListToRef ref (v :: xs) scope
| _ -> raise (BuiltinException "pushf: type error - first argument not a list")
let bpopf args scope =
match singlearg "popf" args with
| ValListReference ref ->
let xs = getListFromRef ref scope
if xs.IsEmpty then
raise (BuiltinException "popf: cannot pop from empty list")
else
let v = List.head xs
v, setListToRef ref (List.tail xs) scope
| _ -> raise (BuiltinException "popf: type error - first argument not a list")
let bconcat args scope =
match twoarg "concat" args with
| ValListReference ref1, ValListReference ref2 ->
let xs = getListFromRef ref1 scope
let ys = getListFromRef ref2 scope
makeNewList (xs @ ys) scope
| ValString s1, ValString s2 ->
ValString (s1 + s2), scope
| _ -> raise (BuiltinException "concat: type error")
let blen args scope =
match singlearg "len" args with
| ValListReference ref ->
let xs = getListFromRef ref scope
ValInt xs.Length, scope
| ValString s ->
ValInt s.Length, scope
| _ -> raise (BuiltinException "len: type error")
let rec brange args scope =
match args with
| [x] ->
brange [ValInt 0; x] scope
| [x; y] ->
match x, y with
| ValInt i, ValInt j ->
if i >= j then
makeNewList [] scope
else
makeNewList (List.map ValInt [i..(j-1)]) scope
| _ ->
raise (BuiltinException "range: type error - argument not an int")
| _ -> raise (BuiltinException "range: incorrect number of arguments")
let bclone args scope =
match singlearg "clone" args with
| ValListReference ref ->
let xs = getListFromRef ref scope
makeNewList xs scope
| ValInt i -> ValInt i, scope
| ValString s -> ValString s, scope
| ValBool b -> ValBool b, scope
| _ ->
raise (BuiltinException "clone: type error - unsupported type")
let rec bsublist args scope =
let rec skipn n l =
match l, n with
| _, 0 -> l
| [], _ -> raise (BuiltinException "sublist: index out of bounds")
| _ :: xs, _ -> skipn (n - 1) xs
match args with
| [x; y] ->
match x with
| ValListReference ref ->
let len, newScope = blen [ValListReference ref] scope
bsublist [x; y; len] newScope
| _ -> raise (BuiltinException "sublist: type error")
| [x; y; z] ->
match x, y, z with
| ValListReference ref, ValInt i, ValInt j ->
let xs = getListFromRef ref scope
if j < i then
raise (BuiltinException "sublist: index out of bounds")
elif j > xs.Length then
raise (BuiltinException "sublist: index out of bounds")
else
let ys = List.truncate (j - i) (skipn i xs)
makeNewList ys scope
| _ -> raise (BuiltinException "sublist: type error")
| _ -> raise (BuiltinException "sublist: incorrect number of arguments")
let breverse args scope =
match singlearg "reverse" args with
| ValListReference ref ->
let vs = getListFromRef ref scope
ValListReference ref, setListToRef ref (List.rev vs) scope
| ValString s ->
ValString (new String(Array.rev (s.ToCharArray()))), scope
| _ -> raise (BuiltinException "reverse: type error")
let brand args =
match singlearg "rand" args with
| ValInt i ->
let rnd = System.Random()
ValInt (rnd.Next() % i)
| _ -> raise (BuiltinException "rand: type error - argument not an int")
//let bmap args scope =
// match twoargs "map" args with
// | ValFunc f, ValListReference ref ->
// let xs = getListFromRef ref scope
let rec beqop e1 e2 =
let res =
match e1, e2 with
| ValNone, ValNone -> true
| ValBool a, ValBool b -> a = b
| ValInt a, ValInt b -> a = b
| ValString s1, ValString s2 -> s1 = s2
| ValFunc (n1, b1), ValFunc (n2, b2) -> (n1 = n2) && (b1 = b2)
| ValListReference l1, ValListReference l2 ->
//TODO stuctural equality for lists
l1 = l2
//List.fold (&&) true
// (List.zip l1 l2 |> List.map (fun (x, y) ->
// match beqop x y with
// | ValBool inner -> inner
// | _ -> false)
// )
| ValReference r1, ValReference r2 -> r1 = r2
| _, _ ->
raise (BuiltinException "==: type error on one or more arguments")
ValBool res
let bcompop op numOp e1 e2 =
match e1, e2 with
| ValInt a, ValInt b -> ValBool (numOp a b)
| _, _ ->
raise (BuiltinException
(sprintf "%s: type error on one or more arguments"
(optostr op)))
let bboolop op numOp e1 e2 =
match e1, e2 with
| ValBool a, ValBool b -> ValBool (numOp a b)
| _, _ ->
raise (BuiltinException
(sprintf "%s: type error on one or more arguments"
(optostr op)))
let bnumop op numOp e1 e2 =
match e1, e2 with
| ValInt a, ValInt b -> ValInt (numOp a b)
| _, _ ->
raise (BuiltinException
(sprintf "%s: type error on one or more arguments"
(optostr op)))
let bunaryminus e =
match e with
| ValInt v -> ValInt (-v)
| _ -> raise (BuiltinException "-: type error on one or more arguments")
let bunaryplus e =
match e with
| ValInt v -> ValInt (v)
| _ -> raise (BuiltinException "+: type error on one or more arguments")
let bunarynot e =
match e with
| ValBool v -> ValBool (not v)
| _ -> raise (BuiltinException "!: type error on one or more arguments")
let opto op =
match op with
| Add -> bnumop Add (+)
| Sub -> bnumop Sub (-)
| Mult -> bnumop Mult (*)
| Div -> bnumop Div (/)
| Mod -> bnumop Mod (%)
| Eq -> beqop
| Neq -> (fun a b -> bnot (beqop a b))
| Leq -> bcompop Leq (<=)
| Geq -> bcompop Geq (>=)
| Lt -> bcompop Lt (<)
| Gt -> bcompop Gt (>)
| And -> bboolop And (&&)
| Or -> bboolop Or (||)
| Dot -> raise (BuiltinException ". is not a binary op")
let bbinary bop =
opto bop
let contextfree bfun =
(fun vs scope -> bfun vs, scope)
let builtins : Map<string, Value> =
[
("toCharList", ValBuiltinFunc bToCharList)
("fromCharList", ValBuiltinFunc bFromCharList)
("charToStr", ValBuiltinFunc (contextfree bCharToStr))
("charAt", ValBuiltinFunc (contextfree bCharAt))
("tryInt", ValBuiltinFunc (contextfree btryint))
("int", ValBuiltinFunc (contextfree bint))
//("reverse",)
//("map",)
//("fold",)
//("filter",)
//("compose",)
//("applyone",)
//("applyall",)
("str", ValBuiltinFunc bstr)
("print", ValBuiltinFunc bprint)
("printraw", ValBuiltinFunc (bprintraw false))
("input", ValBuiltinFunc binput)
("sqrt", ValBuiltinFunc (contextfree bsqrt))
("pushf", ValBuiltinFunc bpushf)
("popf", ValBuiltinFunc bpopf)
("concat", ValBuiltinFunc bconcat)
("len", ValBuiltinFunc blen)
("range", ValBuiltinFunc brange)
("clone", ValBuiltinFunc bclone)
("sublist", ValBuiltinFunc bsublist)
("reverse", ValBuiltinFunc breverse)
("rand", ValBuiltinFunc (contextfree brand))
("hello", ValString "Hello, world!")
] |> Map.ofSeq