1package tengo
2
3var builtinFuncs = []*BuiltinFunction{
4	{
5		Name:  "len",
6		Value: builtinLen,
7	},
8	{
9		Name:  "copy",
10		Value: builtinCopy,
11	},
12	{
13		Name:  "append",
14		Value: builtinAppend,
15	},
16	{
17		Name:  "delete",
18		Value: builtinDelete,
19	},
20	{
21		Name:  "splice",
22		Value: builtinSplice,
23	},
24	{
25		Name:  "string",
26		Value: builtinString,
27	},
28	{
29		Name:  "int",
30		Value: builtinInt,
31	},
32	{
33		Name:  "bool",
34		Value: builtinBool,
35	},
36	{
37		Name:  "float",
38		Value: builtinFloat,
39	},
40	{
41		Name:  "char",
42		Value: builtinChar,
43	},
44	{
45		Name:  "bytes",
46		Value: builtinBytes,
47	},
48	{
49		Name:  "time",
50		Value: builtinTime,
51	},
52	{
53		Name:  "is_int",
54		Value: builtinIsInt,
55	},
56	{
57		Name:  "is_float",
58		Value: builtinIsFloat,
59	},
60	{
61		Name:  "is_string",
62		Value: builtinIsString,
63	},
64	{
65		Name:  "is_bool",
66		Value: builtinIsBool,
67	},
68	{
69		Name:  "is_char",
70		Value: builtinIsChar,
71	},
72	{
73		Name:  "is_bytes",
74		Value: builtinIsBytes,
75	},
76	{
77		Name:  "is_array",
78		Value: builtinIsArray,
79	},
80	{
81		Name:  "is_immutable_array",
82		Value: builtinIsImmutableArray,
83	},
84	{
85		Name:  "is_map",
86		Value: builtinIsMap,
87	},
88	{
89		Name:  "is_immutable_map",
90		Value: builtinIsImmutableMap,
91	},
92	{
93		Name:  "is_iterable",
94		Value: builtinIsIterable,
95	},
96	{
97		Name:  "is_time",
98		Value: builtinIsTime,
99	},
100	{
101		Name:  "is_error",
102		Value: builtinIsError,
103	},
104	{
105		Name:  "is_undefined",
106		Value: builtinIsUndefined,
107	},
108	{
109		Name:  "is_function",
110		Value: builtinIsFunction,
111	},
112	{
113		Name:  "is_callable",
114		Value: builtinIsCallable,
115	},
116	{
117		Name:  "type_name",
118		Value: builtinTypeName,
119	},
120	{
121		Name:  "format",
122		Value: builtinFormat,
123	},
124	{
125		Name:  "range",
126		Value: builtinRange,
127	},
128}
129
130// GetAllBuiltinFunctions returns all builtin function objects.
131func GetAllBuiltinFunctions() []*BuiltinFunction {
132	return append([]*BuiltinFunction{}, builtinFuncs...)
133}
134
135func builtinTypeName(args ...Object) (Object, error) {
136	if len(args) != 1 {
137		return nil, ErrWrongNumArguments
138	}
139	return &String{Value: args[0].TypeName()}, nil
140}
141
142func builtinIsString(args ...Object) (Object, error) {
143	if len(args) != 1 {
144		return nil, ErrWrongNumArguments
145	}
146	if _, ok := args[0].(*String); ok {
147		return TrueValue, nil
148	}
149	return FalseValue, nil
150}
151
152func builtinIsInt(args ...Object) (Object, error) {
153	if len(args) != 1 {
154		return nil, ErrWrongNumArguments
155	}
156	if _, ok := args[0].(*Int); ok {
157		return TrueValue, nil
158	}
159	return FalseValue, nil
160}
161
162func builtinIsFloat(args ...Object) (Object, error) {
163	if len(args) != 1 {
164		return nil, ErrWrongNumArguments
165	}
166	if _, ok := args[0].(*Float); ok {
167		return TrueValue, nil
168	}
169	return FalseValue, nil
170}
171
172func builtinIsBool(args ...Object) (Object, error) {
173	if len(args) != 1 {
174		return nil, ErrWrongNumArguments
175	}
176	if _, ok := args[0].(*Bool); ok {
177		return TrueValue, nil
178	}
179	return FalseValue, nil
180}
181
182func builtinIsChar(args ...Object) (Object, error) {
183	if len(args) != 1 {
184		return nil, ErrWrongNumArguments
185	}
186	if _, ok := args[0].(*Char); ok {
187		return TrueValue, nil
188	}
189	return FalseValue, nil
190}
191
192func builtinIsBytes(args ...Object) (Object, error) {
193	if len(args) != 1 {
194		return nil, ErrWrongNumArguments
195	}
196	if _, ok := args[0].(*Bytes); ok {
197		return TrueValue, nil
198	}
199	return FalseValue, nil
200}
201
202func builtinIsArray(args ...Object) (Object, error) {
203	if len(args) != 1 {
204		return nil, ErrWrongNumArguments
205	}
206	if _, ok := args[0].(*Array); ok {
207		return TrueValue, nil
208	}
209	return FalseValue, nil
210}
211
212func builtinIsImmutableArray(args ...Object) (Object, error) {
213	if len(args) != 1 {
214		return nil, ErrWrongNumArguments
215	}
216	if _, ok := args[0].(*ImmutableArray); ok {
217		return TrueValue, nil
218	}
219	return FalseValue, nil
220}
221
222func builtinIsMap(args ...Object) (Object, error) {
223	if len(args) != 1 {
224		return nil, ErrWrongNumArguments
225	}
226	if _, ok := args[0].(*Map); ok {
227		return TrueValue, nil
228	}
229	return FalseValue, nil
230}
231
232func builtinIsImmutableMap(args ...Object) (Object, error) {
233	if len(args) != 1 {
234		return nil, ErrWrongNumArguments
235	}
236	if _, ok := args[0].(*ImmutableMap); ok {
237		return TrueValue, nil
238	}
239	return FalseValue, nil
240}
241
242func builtinIsTime(args ...Object) (Object, error) {
243	if len(args) != 1 {
244		return nil, ErrWrongNumArguments
245	}
246	if _, ok := args[0].(*Time); ok {
247		return TrueValue, nil
248	}
249	return FalseValue, nil
250}
251
252func builtinIsError(args ...Object) (Object, error) {
253	if len(args) != 1 {
254		return nil, ErrWrongNumArguments
255	}
256	if _, ok := args[0].(*Error); ok {
257		return TrueValue, nil
258	}
259	return FalseValue, nil
260}
261
262func builtinIsUndefined(args ...Object) (Object, error) {
263	if len(args) != 1 {
264		return nil, ErrWrongNumArguments
265	}
266	if args[0] == UndefinedValue {
267		return TrueValue, nil
268	}
269	return FalseValue, nil
270}
271
272func builtinIsFunction(args ...Object) (Object, error) {
273	if len(args) != 1 {
274		return nil, ErrWrongNumArguments
275	}
276	switch args[0].(type) {
277	case *CompiledFunction:
278		return TrueValue, nil
279	}
280	return FalseValue, nil
281}
282
283func builtinIsCallable(args ...Object) (Object, error) {
284	if len(args) != 1 {
285		return nil, ErrWrongNumArguments
286	}
287	if args[0].CanCall() {
288		return TrueValue, nil
289	}
290	return FalseValue, nil
291}
292
293func builtinIsIterable(args ...Object) (Object, error) {
294	if len(args) != 1 {
295		return nil, ErrWrongNumArguments
296	}
297	if args[0].CanIterate() {
298		return TrueValue, nil
299	}
300	return FalseValue, nil
301}
302
303// len(obj object) => int
304func builtinLen(args ...Object) (Object, error) {
305	if len(args) != 1 {
306		return nil, ErrWrongNumArguments
307	}
308	switch arg := args[0].(type) {
309	case *Array:
310		return &Int{Value: int64(len(arg.Value))}, nil
311	case *ImmutableArray:
312		return &Int{Value: int64(len(arg.Value))}, nil
313	case *String:
314		return &Int{Value: int64(len(arg.Value))}, nil
315	case *Bytes:
316		return &Int{Value: int64(len(arg.Value))}, nil
317	case *Map:
318		return &Int{Value: int64(len(arg.Value))}, nil
319	case *ImmutableMap:
320		return &Int{Value: int64(len(arg.Value))}, nil
321	default:
322		return nil, ErrInvalidArgumentType{
323			Name:     "first",
324			Expected: "array/string/bytes/map",
325			Found:    arg.TypeName(),
326		}
327	}
328}
329
330//range(start, stop[, step])
331func builtinRange(args ...Object) (Object, error) {
332	numArgs := len(args)
333	if numArgs < 2 || numArgs > 3 {
334		return nil, ErrWrongNumArguments
335	}
336	var start, stop, step *Int
337
338	for i, arg := range args {
339		v, ok := args[i].(*Int)
340		if !ok {
341			var name string
342			switch i {
343			case 0:
344				name = "start"
345			case 1:
346				name = "stop"
347			case 2:
348				name = "step"
349			}
350
351			return nil, ErrInvalidArgumentType{
352				Name:     name,
353				Expected: "int",
354				Found:    arg.TypeName(),
355			}
356		}
357		if i == 2 && v.Value <= 0 {
358			return nil, ErrInvalidRangeStep
359		}
360		switch i {
361		case 0:
362			start = v
363		case 1:
364			stop = v
365		case 2:
366			step = v
367		}
368	}
369
370	if step == nil {
371		step = &Int{Value: int64(1)}
372	}
373
374	return buildRange(start.Value, stop.Value, step.Value), nil
375}
376
377func buildRange(start, stop, step int64) *Array {
378	array := &Array{}
379	if start <= stop {
380		for i := start; i < stop; i += step {
381			array.Value = append(array.Value, &Int{
382				Value: i,
383			})
384		}
385	} else {
386		for i := start; i > stop; i -= step {
387			array.Value = append(array.Value, &Int{
388				Value: i,
389			})
390		}
391	}
392	return array
393}
394
395func builtinFormat(args ...Object) (Object, error) {
396	numArgs := len(args)
397	if numArgs == 0 {
398		return nil, ErrWrongNumArguments
399	}
400	format, ok := args[0].(*String)
401	if !ok {
402		return nil, ErrInvalidArgumentType{
403			Name:     "format",
404			Expected: "string",
405			Found:    args[0].TypeName(),
406		}
407	}
408	if numArgs == 1 {
409		// okay to return 'format' directly as String is immutable
410		return format, nil
411	}
412	s, err := Format(format.Value, args[1:]...)
413	if err != nil {
414		return nil, err
415	}
416	return &String{Value: s}, nil
417}
418
419func builtinCopy(args ...Object) (Object, error) {
420	if len(args) != 1 {
421		return nil, ErrWrongNumArguments
422	}
423	return args[0].Copy(), nil
424}
425
426func builtinString(args ...Object) (Object, error) {
427	argsLen := len(args)
428	if !(argsLen == 1 || argsLen == 2) {
429		return nil, ErrWrongNumArguments
430	}
431	if _, ok := args[0].(*String); ok {
432		return args[0], nil
433	}
434	v, ok := ToString(args[0])
435	if ok {
436		if len(v) > MaxStringLen {
437			return nil, ErrStringLimit
438		}
439		return &String{Value: v}, nil
440	}
441	if argsLen == 2 {
442		return args[1], nil
443	}
444	return UndefinedValue, nil
445}
446
447func builtinInt(args ...Object) (Object, error) {
448	argsLen := len(args)
449	if !(argsLen == 1 || argsLen == 2) {
450		return nil, ErrWrongNumArguments
451	}
452	if _, ok := args[0].(*Int); ok {
453		return args[0], nil
454	}
455	v, ok := ToInt64(args[0])
456	if ok {
457		return &Int{Value: v}, nil
458	}
459	if argsLen == 2 {
460		return args[1], nil
461	}
462	return UndefinedValue, nil
463}
464
465func builtinFloat(args ...Object) (Object, error) {
466	argsLen := len(args)
467	if !(argsLen == 1 || argsLen == 2) {
468		return nil, ErrWrongNumArguments
469	}
470	if _, ok := args[0].(*Float); ok {
471		return args[0], nil
472	}
473	v, ok := ToFloat64(args[0])
474	if ok {
475		return &Float{Value: v}, nil
476	}
477	if argsLen == 2 {
478		return args[1], nil
479	}
480	return UndefinedValue, nil
481}
482
483func builtinBool(args ...Object) (Object, error) {
484	if len(args) != 1 {
485		return nil, ErrWrongNumArguments
486	}
487	if _, ok := args[0].(*Bool); ok {
488		return args[0], nil
489	}
490	v, ok := ToBool(args[0])
491	if ok {
492		if v {
493			return TrueValue, nil
494		}
495		return FalseValue, nil
496	}
497	return UndefinedValue, nil
498}
499
500func builtinChar(args ...Object) (Object, error) {
501	argsLen := len(args)
502	if !(argsLen == 1 || argsLen == 2) {
503		return nil, ErrWrongNumArguments
504	}
505	if _, ok := args[0].(*Char); ok {
506		return args[0], nil
507	}
508	v, ok := ToRune(args[0])
509	if ok {
510		return &Char{Value: v}, nil
511	}
512	if argsLen == 2 {
513		return args[1], nil
514	}
515	return UndefinedValue, nil
516}
517
518func builtinBytes(args ...Object) (Object, error) {
519	argsLen := len(args)
520	if !(argsLen == 1 || argsLen == 2) {
521		return nil, ErrWrongNumArguments
522	}
523
524	// bytes(N) => create a new bytes with given size N
525	if n, ok := args[0].(*Int); ok {
526		if n.Value > int64(MaxBytesLen) {
527			return nil, ErrBytesLimit
528		}
529		return &Bytes{Value: make([]byte, int(n.Value))}, nil
530	}
531	v, ok := ToByteSlice(args[0])
532	if ok {
533		if len(v) > MaxBytesLen {
534			return nil, ErrBytesLimit
535		}
536		return &Bytes{Value: v}, nil
537	}
538	if argsLen == 2 {
539		return args[1], nil
540	}
541	return UndefinedValue, nil
542}
543
544func builtinTime(args ...Object) (Object, error) {
545	argsLen := len(args)
546	if !(argsLen == 1 || argsLen == 2) {
547		return nil, ErrWrongNumArguments
548	}
549	if _, ok := args[0].(*Time); ok {
550		return args[0], nil
551	}
552	v, ok := ToTime(args[0])
553	if ok {
554		return &Time{Value: v}, nil
555	}
556	if argsLen == 2 {
557		return args[1], nil
558	}
559	return UndefinedValue, nil
560}
561
562// append(arr, items...)
563func builtinAppend(args ...Object) (Object, error) {
564	if len(args) < 2 {
565		return nil, ErrWrongNumArguments
566	}
567	switch arg := args[0].(type) {
568	case *Array:
569		return &Array{Value: append(arg.Value, args[1:]...)}, nil
570	case *ImmutableArray:
571		return &Array{Value: append(arg.Value, args[1:]...)}, nil
572	default:
573		return nil, ErrInvalidArgumentType{
574			Name:     "first",
575			Expected: "array",
576			Found:    arg.TypeName(),
577		}
578	}
579}
580
581// builtinDelete deletes Map keys
582// usage: delete(map, "key")
583// key must be a string
584func builtinDelete(args ...Object) (Object, error) {
585	argsLen := len(args)
586	if argsLen != 2 {
587		return nil, ErrWrongNumArguments
588	}
589	switch arg := args[0].(type) {
590	case *Map:
591		if key, ok := args[1].(*String); ok {
592			delete(arg.Value, key.Value)
593			return UndefinedValue, nil
594		}
595		return nil, ErrInvalidArgumentType{
596			Name:     "second",
597			Expected: "string",
598			Found:    args[1].TypeName(),
599		}
600	default:
601		return nil, ErrInvalidArgumentType{
602			Name:     "first",
603			Expected: "map",
604			Found:    arg.TypeName(),
605		}
606	}
607}
608
609// builtinSplice deletes and changes given Array, returns deleted items.
610// usage:
611// deleted_items := splice(array[,start[,delete_count[,item1[,item2[,...]]]])
612func builtinSplice(args ...Object) (Object, error) {
613	argsLen := len(args)
614	if argsLen == 0 {
615		return nil, ErrWrongNumArguments
616	}
617
618	array, ok := args[0].(*Array)
619	if !ok {
620		return nil, ErrInvalidArgumentType{
621			Name:     "first",
622			Expected: "array",
623			Found:    args[0].TypeName(),
624		}
625	}
626	arrayLen := len(array.Value)
627
628	var startIdx int
629	if argsLen > 1 {
630		arg1, ok := args[1].(*Int)
631		if !ok {
632			return nil, ErrInvalidArgumentType{
633				Name:     "second",
634				Expected: "int",
635				Found:    args[1].TypeName(),
636			}
637		}
638		startIdx = int(arg1.Value)
639		if startIdx < 0 || startIdx > arrayLen {
640			return nil, ErrIndexOutOfBounds
641		}
642	}
643
644	delCount := len(array.Value)
645	if argsLen > 2 {
646		arg2, ok := args[2].(*Int)
647		if !ok {
648			return nil, ErrInvalidArgumentType{
649				Name:     "third",
650				Expected: "int",
651				Found:    args[2].TypeName(),
652			}
653		}
654		delCount = int(arg2.Value)
655		if delCount < 0 {
656			return nil, ErrIndexOutOfBounds
657		}
658	}
659	// if count of to be deleted items is bigger than expected, truncate it
660	if startIdx+delCount > arrayLen {
661		delCount = arrayLen - startIdx
662	}
663	// delete items
664	endIdx := startIdx + delCount
665	deleted := append([]Object{}, array.Value[startIdx:endIdx]...)
666
667	head := array.Value[:startIdx]
668	var items []Object
669	if argsLen > 3 {
670		items = make([]Object, 0, argsLen-3)
671		for i := 3; i < argsLen; i++ {
672			items = append(items, args[i])
673		}
674	}
675	items = append(items, array.Value[endIdx:]...)
676	array.Value = append(head, items...)
677
678	// return deleted items
679	return &Array{Value: deleted}, nil
680}
681