Files
Odin/core/text/template/function.odin
2022-03-03 18:08:04 +00:00

148 lines
3.1 KiB
Odin

package text_template
import "core:fmt"
import "core:reflect"
import "core:strconv"
Function :: #type proc(args: []any) -> (value: any, err: Error)
@(private)
new_any :: proc(x: $T) -> any {
ptr := new_clone(x)
return any{ptr, typeid_of(T)}
}
builtin_funcs: map[string]Function
@(private, init)
init_builtin_funcs :: proc() {
builtin_funcs["and"] = nil // requires shortcircuiting behaviour so implemented internally
builtin_funcs["or"] = nil // requires shortcircuiting behaviour so implemented internally
builtin_funcs["not"] = proc(args: []any) -> (value: any, err: Error) {
if len(args) != 1 {
err = .Invalid_Argument_Count
return
}
t, _ := is_true(args[0])
return new_any(t), nil
}
builtin_funcs["index"] = proc(args: []any) -> (value: any, err: Error) {
if len(args) < 2 {
err = .Invalid_Argument_Count
return
}
arg := args[0]
for idx in args[1:] {
i, ok := reflect.as_int(idx)
if !ok {
err = .Invalid_Argument_Type
return
}
if reflect.length(arg) < i {
return nil, .Out_Of_Bounds_Access
}
arg = reflect.index(arg, i)
}
return arg, nil
}
builtin_funcs["len"] = proc(args: []any) -> (value: any, err: Error) {
if len(args) != 1 {
err = .Invalid_Argument_Count
return
}
n := reflect.length(args[0])
return new_any(n), nil
}
builtin_funcs["int"] = proc(args: []any) -> (value: any, err: Error) {
if len(args) != 1 {
err = .Invalid_Argument_Count
return
}
res: i64
switch v in get_value(args[0]) {
case bool:
res = i64(v)
case i64:
res = i64(v)
case f64:
res = i64(v)
case string:
if value, ok := strconv.parse_f64(v); ok {
res = i64(value)
} else if value, ok := strconv.parse_i64(v); ok {
res = i64(value)
} else {
return nil, .Invalid_Argument_Type
}
case:
return nil, .Invalid_Argument_Type
}
return new_any(res), nil
}
builtin_funcs["float"] = proc(args: []any) -> (value: any, err: Error) {
if len(args) != 1 {
err = .Invalid_Argument_Count
return
}
res: f64
switch v in get_value(args[0]) {
case bool:
res = f64(i64(v))
case i64:
res = f64(v)
case f64:
res = f64(v)
case string:
if value, ok := strconv.parse_f64(v); ok {
res = f64(value)
} else if value, ok := strconv.parse_i64(v); ok {
res = f64(value)
} else {
return nil, .Invalid_Argument_Type
}
case:
return nil, .Invalid_Argument_Type
}
return new_any(res), nil
}
builtin_funcs["print"] = proc(args: []any) -> (value: any, err: Error) {
return new_any(fmt.aprint(..args)), nil
}
builtin_funcs["println"] = proc(args: []any) -> (value: any, err: Error) {
return new_any(fmt.aprintln(..args)), nil
}
builtin_funcs["printf"] = proc(args: []any) -> (value: any, err: Error) {
if len(args) < 1 {
err = .Invalid_Argument_Count
return
}
format_any := args[0]
format_any.id = reflect.typeid_base(format_any.id)
format: string
switch v in format_any {
case string:
format = v
case cstring:
format = string(v)
case:
err = .Invalid_Argument_Type
return
}
other_args := args[1:]
return new_any(fmt.aprintf(format, ..other_args)), nil
}
}