	// evaluator/builtins.go convert to here with use compiler.go

	package compiler

	import (
		"bufio"
		"crypto/md5"
		"encoding/base64"
		"encoding/hex"
		"fmt"
		"io"
		"log"
		"math"
		"math/rand"
		"net"
		"os"
		"os/exec"
		"regexp"
		"strconv"
		"strings"
		"syscall"
		"time"
	
		_ "unsafe"
	
		"github.com/skratchdot/open-golang/open"
	
		stub "github.com/oytunistrator/asm/generator/unsafe-stub"
	
		"gitlab.com/olanguage/olang/color"
		"gitlab.com/olanguage/olang/crypto"
		"gitlab.com/olanguage/olang/filedb"
		"gitlab.com/olanguage/olang/object"
		"gitlab.com/olanguage/olang/systemlib"
		"gitlab.com/olanguage/olang/watcher"
	
		"database/sql"

		_ "github.com/buger/jsonparser"
		_ "github.com/clbanning/mxj"
		_ "github.com/davecgh/go-spew/spew"
		_ "github.com/julienschmidt/httprouter"
		_ "github.com/denisenkom/go-mssqldb"	
		_ "github.com/go-sql-driver/mysql"
		_ "github.com/lib/pq"
		_ "github.com/mattn/go-sqlite3"
	)
	
	var ApplyFunctionInside func(fn object.Object, args []object.Object) object.Object
	
	func init() {
		ApplyFunctionInside = applyFunction
	}
	
	var builtins = map[string]*object.Builtin{
		"itostr": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				switch arg := args[0].(type) {
				case *object.Integer:
					return &object.String{Value: string(arg.Result())}
				default:
					return newError("argument to `len` not supported, got %s", args[0].Type())
				}
			},
		},
		"len": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				switch arg := args[0].(type) {
				case *object.Array:
					return &object.Integer{Value: int64(len(arg.Elements))}
				case *object.String:
					return &object.Integer{Value: int64(len(arg.Value))}
				case *object.Integer:
					return &object.Integer{Value: int64(len(strconv.FormatInt(arg.Value, 10)))}
				default:
					return newError("argument to `len` not supported, got %s", args[0].Type())
				}
			},
		},
	
		"first": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				if args[0].Type() != object.ARRAY_OBJ {
					return newError("argument to `first` must be ARRAY, got %s", args[0].Type())
				}
	
				arr := args[0].(*object.Array)
				if len(arr.Elements) > 0 {
					return arr.Elements[0]
				}
	
				return &object.Empty{}
			},
		},
	
		"last": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				if args[0].Type() != object.ARRAY_OBJ {
					return newError("argument to `last` must be ARRAY, got %s", args[0].Type())
				}
	
				arr := args[0].(*object.Array)
				length := len(arr.Elements)
				if length > 0 {
					return arr.Elements[length-1]
				}
	
				return &object.Empty{}
			},
		},
	
		"rest": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				if args[0].Type() != object.ARRAY_OBJ {
					return newError("argument to `rest` must be ARRAY, got %s", args[0].Type())
				}
	
				arr := args[0].(*object.Array)
				length := len(arr.Elements)
				if length > 0 {
					newElements := make([]object.Object, length-1)
					copy(newElements, arr.Elements[1:length])
					return &object.Array{Elements: newElements}
				}
	
				return &object.Empty{}
			},
		},
	
		"push": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 2 {
					return newError("wrong number of arguments. got=%d, want=2 or 3", len(args))
				}
	
				switch obj := args[0].(type) {
				case *object.Array:
					length := len(obj.Elements)
	
					newElements := make([]object.Object, length+1)
					copy(newElements, obj.Elements)
					newElements[length] = args[1]
	
					return &object.Array{Elements: newElements}
				case *object.Hash:
					if len(args) == 3 {
						length := len(obj.Pairs)
						replaceKey := false
						var replaceId object.HashKey
	
						pairs := make(map[object.HashKey]object.HashPair)
						i := 0
						for _, item := range obj.Pairs {
							hashed := object.HashKey{Value: uint64(i)}
							pair := object.HashPair{Key: item.Key, Value: item.Value}
							pairs[hashed] = pair
							if item.Key.Result() == args[1].Result() {
								replaceKey = true
								replaceId = hashed
							}
							i++
						}
	
						if replaceKey {
							hashed := replaceId
							pairs[hashed] = object.HashPair{Key: args[1], Value: args[2]}
						} else {
							hashed := object.HashKey{Value: uint64(length)}
							pairs[hashed] = object.HashPair{Key: args[1], Value: args[2]}
						}
	
						return &object.Hash{Pairs: pairs}
					}
				default:
					return newError("argument to `push` must be ARRAY or HASH, got %s", args[0].Type())
				}
				return &object.Empty{}
			},
		},
		"colorize": {
			Fn: func(args ...object.Object) object.Object {
	
				if len(args) <= 1 {
					return newError("wrong number of arguments. got=%d, want=2 or more", len(args))
				}
	
				text := ""
				switch arg := args[0].(type) {
				case *object.String:
					text = arg.Value
				default:
					return newError("argument to `len` not supported, got %s", args[0].Type())
				}
	
				colorArg := ""
				switch arg := args[1].(type) {
				case *object.String:
					colorArg = arg.Value
				default:
					return newError("argument to `len` not supported, got %s", args[1].Type())
				}
	
				backArg := false
				if len(args) == 3 {
					switch arg := args[2].(type) {
					case *object.Boolean:
						backArg = arg.Value
					}
				}
	
				createdColor := color.Create(
					colorArg,
					text,
					backArg)
	
				return &object.String{Value: string(createdColor.StdOut())}
			},
		},
		"webserver": {
			Fn: func(args ...object.Object) object.Object {
				webServer := NewServer("webserver")
				return webServer.Server(args...)
			},
		},
		"read": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) <= 0 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
				path := ""
				switch arg := args[0].(type) {
				case *object.String:
					path = string(arg.Value)
				default:
					return newError("argument to `read` not supported, got %s", args[0].Type())
				}
				read := systemlib.ReadFile(path)
	
				return &object.String{Value: read}
			},
		},
		"write": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("wrong number of arguments. got=%d, want=2", len(args))
				}
				path := ""
				content := ""
				write := false
				switch arg := args[0].(type) {
				case *object.String:
					path = arg.Result()
				default:
					return newError("argument to `write` not supported, got %s", args[0].Type())
				}
	
				switch arg := args[1].(type) {
				case *object.String:
					content = arg.Result()
				default:
					return newError("argument to `write` not supported, got %s", args[0].Type())
				}
	
				systemlib.CreateFile(path)
				write = systemlib.WriteFile(path, content)
	
				return &object.Boolean{Value: write}
			},
		},
		"remove": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("wrong number of arguments. got=%d, want=2", len(args))
				}
	
				path := ""
	
				switch arg := args[0].(type) {
				case *object.String:
					path = arg.Result()
				default:
					return newError("argument to `remove` not supported, got %s", args[0].Type())
				}
	
				del := systemlib.DeleteFile(path)
	
				return &object.Boolean{Value: del}
			},
		},
		"mkdir": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				switch arg := args[0].(type) {
				case *object.String:
					systemlib.CreateDir(arg.Result())
				case *object.Array:
					for _, elm := range arg.Elements {
						systemlib.CreateDir(elm.Result())
					}
				default:
					return newError("argument to `mkdir` not supported, got %s", args[0].Type())
				}
	
				return &object.Empty{}
			},
		},
		"rmdir": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				switch arg := args[0].(type) {
				case *object.String:
					systemlib.DeleteDir(arg.Result())
	
				case *object.Array:
					for _, elm := range arg.Elements {
						systemlib.DeleteDir(elm.Result())
					}
				default:
					return newError("argument to `rmdir` not supported, got %s", args[0].Type())
				}
	
				return &object.Empty{}
			},
		},
		"finfo": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				pairs := make(map[object.HashKey]object.HashPair)
	
				switch arg := args[0].(type) {
				case *object.String:
					finfo, err := os.Stat(arg.Result())
	
					if err != nil {
						return newError("finfo error: %s", err.Error())
					}
	
					hkey := object.HashKey{Value: uint64(0)}
					hval := object.HashPair{Key: &object.String{Value: "name"}, Value: &object.String{Value: finfo.Name()}}
	
					pairs[hkey] = hval
	
					hkey = object.HashKey{Value: uint64(1)}
					hval = object.HashPair{Key: &object.String{Value: "size"}, Value: &object.Integer{Value: finfo.Size()}}
	
					pairs[hkey] = hval
	
					hkey = object.HashKey{Value: uint64(2)}
					hval = object.HashPair{Key: &object.String{Value: "isdir"}, Value: &object.Boolean{Value: finfo.IsDir()}}
	
					pairs[hkey] = hval
	
					hkey = object.HashKey{Value: uint64(3)}
					hval = object.HashPair{Key: &object.String{Value: "perm"}, Value: &object.Integer{Value: int64(finfo.Mode().Perm())}}
	
					pairs[hkey] = hval
	
					hkey = object.HashKey{Value: uint64(4)}
					hval = object.HashPair{Key: &object.String{Value: "date"}, Value: &object.String{Value: string(finfo.ModTime().String())}}
	
					pairs[hkey] = hval
	
				default:
					return newError("argument to `finfo` not supported, got %s", args[0].Type())
				}
	
				return &object.Hash{Pairs: pairs}
			},
		},
		"chmod": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("wrong number of arguments. got=%d, want=2", len(args))
				}
	
				switch arg := args[0].(type) {
				case *object.String:
					file := arg.Result()
					switch mod := args[1].(type) {
					case *object.Integer:
						unixMod := os.FileMode(mod.Value)
						os.Chmod(file, unixMod)
					default:
						return newError("argument to `chmod` not supported, got %s", args[1].Type())
					}
				default:
					return newError("argument to `chmod` not supported, got %s", args[0].Type())
				}
	
				return &object.Boolean{Value: true}
			},
		},
		"atostr": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) <= 0 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
				result := ""
				switch arg := args[0].(type) {
				case *object.Array:
					for _, arg := range arg.Elements {
						result += string(arg.Result())
						if len(args) == 2 {
							switch arg := args[1].(type) {
							case *object.String:
								result += string(arg.Result())
							default:
								return newError("argument to `atostr` not supported, got %s", args[1].Type())
							}
						}
					}
				default:
					return newError("argument to `atostr` not supported, got %s", args[0].Type())
				}
	
				return &object.String{Value: result}
			},
		},
		"json": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) <= 0 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				result := ParseJsonToString(args[0])
				return &object.String{Value: result}
			},
		},
		"rand": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				rand.Seed(time.Now().UnixNano())
				num := 0
				str := ""
	
				switch arg := args[0].(type) {
				case *object.Integer:
					num = int(arg.Value) + 1
				default:
					return newError("argument to `rand` not supported, got %s", args[0].Type())
				}
	
				result := int64(rand.Intn(num))
	
				if len(args) == 2 {
	
					switch arg := args[1].(type) {
					case *object.String:
						str = arg.Result()
					default:
						return newError("argument to `rand` not supported, got %s", args[0].Type())
					}
	
					var letterRunes = []rune(str)
					b := make([]rune, num)
					for i := range b {
						b[i] = letterRunes[rand.Intn(len(letterRunes))]
					}
	
					return &object.String{Value: string(b)}
				}
	
				return &object.Integer{Value: result}
			},
		},
	
		"getval": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) > 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
				switch arg := args[0].(type) {
				case *object.Hash:
					hash := arg
					switch arg := args[1].(type) {
					case *object.String:
						for _, pair := range hash.Pairs {
							if pair.Key.Inspect() == arg.Inspect() {
								return checkType2(pair.Value)
							}
						}
					}
				case *object.Array:
					arr := arg
					switch arg := args[1].(type) {
					case *object.Integer:
						for _, arr := range arr.Elements {
							if arr.Inspect() == arg.Inspect() {
								return checkType2(arr)
							}
						}
					}
				default:
					return newError("argument to `getval` not supported, got %s", args[0].Type())
				}
	
				return &object.Boolean{Value: true}
			},
		},
		"jsonf": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) > 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
				switch arg := args[0].(type) {
				case *object.String:
					file := systemlib.ReadFile(arg.Value)
	
					data := []byte(file)
	
					return ParseJson(data)
				default:
					return newError("argument to `jsonp` not supported, got %s", args[0].Type())
				}
			},
		},
		"jsonp": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) > 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
				switch arg := args[0].(type) {
				case *object.String:
					data := []byte(arg.Value)
	
					return ParseJson(data)
				default:
					return newError("argument to `jsonp` not supported, got %s", args[0].Type())
				}
			},
		},
		"xmlf": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) > 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
				switch arg := args[0].(type) {
				case *object.String:
					file := systemlib.ReadFile(arg.Value)
					return ParseXML(file)
				default:
					return newError("argument to `xmlp` not supported, got %s", args[0].Type())
				}
			},
		},
		"xmlp": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) > 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
				switch arg := args[0].(type) {
				case *object.String:
					return ParseXML(arg.Value)
				default:
					return newError("argument to `xmlp` not supported, got %s", args[0].Type())
				}
			},
		},
		"wdir": {
			Fn: func(args ...object.Object) object.Object {
				res, _ := os.Getwd()
				return &object.String{Value: res}
			},
		},
		"chdir": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) > 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
				switch arg := args[0].(type) {
				case *object.String:
					os.Chdir(string(arg.Value))
					res, _ := os.Getwd()
					return &object.String{Value: res}
				default:
					return newError("argument to `chdir` not supported, got %s", args[0].Type())
				}
			},
		},
		"args": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) > 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
				switch arg := args[0].(type) {
				case *object.Integer:
					for i, argument := range os.Args {
						if arg.Value == int64(i) {
							return &object.String{Value: argument}
						}
					}
				default:
					return newError("argument to `args` not supported, got %s", args[0].Type())
				}
				return &object.String{Value: ""}
			},
		},
		"exist": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) > 1 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
				switch arg := args[0].(type) {
				case *object.String:
					_, err := os.Stat(arg.Value)
	
					if os.IsNotExist(err) {
						return &object.Boolean{Value: false}
					}
	
					if err != nil {
						return &object.Boolean{Value: false}
					}
	
				default:
					return newError("argument to `exist` not supported, got %s", args[0].Type())
				}
				return &object.Boolean{Value: true}
			},
		},
		"renderf": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("wrong number of arguments. got=%d, want=2", len(args))
				}
				switch arg := args[0].(type) {
				case *object.String:
					file := systemlib.ReadFile(arg.Value)
					switch arg := args[1].(type) {
					case *object.Hash:
						for _, pair := range arg.Pairs {
							file = strings.Replace(file, "{% "+pair.Key.Result()+" %}", pair.Value.Result(), -1)
						}
						return &object.String{Value: file}
					default:
						return newError("argument to `renderf` not supported, got %s", args[0].Type())
					}
				default:
					return newError("argument to `renderf` not supported, got %s", args[0].Type())
				}
			},
		},
		"sysenv": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 0 {
					switch envKey := args[0].(type) {
					case *object.String:
						if len(args) == 2 {
							switch envVal := args[1].(type) {
							case *object.String:
								os.Setenv(string(envKey.Value), string(envVal.Value))
							default:
								return newError("argument to `sysenv` not supported, got %s", args[0].Type())
							}
						}
						return &object.String{Value: os.Getenv(string(envKey.Value))}
					default:
						return newError("argument to `sysenv` not supported, got %s", args[0].Type())
					}
				} else {
					i := 0
					pairs := make(map[object.HashKey]object.HashPair)
					for _, e := range os.Environ() {
						pair := strings.Split(e, "=")
	
						nk := &object.String{Value: string(pair[0])}
						nv := &object.String{Value: string(pair[1])}
						hashed := object.HashKey{Value: uint64(i)}
	
						hp := object.HashPair{Key: nk, Value: nv}
						pairs[hashed] = hp
						i++
					}
					return &object.Hash{Pairs: pairs}
				}
			},
		},
		"proc_kill": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("`proc_kill` function needs 1 you defined only %s arguments.", len(args))
				}
				switch cmd := args[0].(type) {
				case *object.Process:
					cmd.Proc.Process.Kill()
				default:
					return newError("argument to `proc_kill` not supported, got %s", args[0].Type())
				}
	
				return &object.Empty{}
			},
		},
		"open": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 1 {
					return newError("`open` function needs 1 you defined only %s arguments.", len(args))
				}
	
				command := ""
				switch arg := args[0].(type) {
				case *object.String:
					command = arg.Value
				default:
					return newError("argument to `open` not supported, got %s", arg.Type())
				}
	
				attr := ""
				if len(args) > 1 {
					for i := 1; i < len(args); i++ {
						switch ar := args[i].(type) {
						case *object.String:
							attr += ar.Result()
						default:
							return newError("argument to `exec` not supported, got %s", ar.Type())
						}
					}
				}
	
				open.RunWith(attr, command)
	
				return &object.Empty{}
			},
		},
		"run": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 1 {
					return newError("`run` function needs 1 you defined only %s arguments.", len(args))
				}
	
				command := ""
				switch arg := args[0].(type) {
				case *object.String:
					command = arg.Value
				default:
					return newError("argument to `run` not supported, got %s", arg.Type())
				}
	
				var attr []string
				if len(args) > 1 {
					for i := 1; i < len(args); i++ {
						switch ar := args[i].(type) {
						case *object.String:
							attr = append(attr, ar.Result())
						default:
							return newError("argument to `run` not supported, got %s", ar.Type())
						}
					}
				}
	
				binary, lookErr := exec.LookPath(command)
				if lookErr != nil {
					return newError("command not found error %s", lookErr)
				}
	
				env := os.Environ()
	
				execErr := syscall.Exec(binary, attr, env)
				if execErr != nil {
					return newError("error %s", execErr)
				}
	
				return &object.Empty{}
			},
		},
		"exec": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 1 {
					return newError("`exec` function needs 1 you defined only %s arguments.", len(args))
				}
	
				command := ""
				switch arg := args[0].(type) {
				case *object.String:
					command = arg.Value
				default:
					return newError("argument to `exec` not supported, got %s", arg.Type())
				}
	
				attr := ""
				if len(args) > 1 {
					for i := 1; i < len(args); i++ {
						switch ar := args[i].(type) {
						case *object.String:
							attr += ar.Result()
						default:
							return newError("argument to `exec` not supported, got %s", ar.Type())
						}
					}
				}
	
				cmd := exec.Command(command, attr)
	
				output, err := cmd.CombinedOutput()
	
				if err != nil {
					return newError("command execute error %s", err)
				}
	
				return &object.Process{Pid: int64(cmd.Process.Pid), Output: string(output), Proc: cmd}
			},
		},
		"sh_exec": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 1 {
					return newError("`sh_exec` function needs 1 you defined only %s arguments.", len(args))
				}
	
				command := ""
				switch arg := args[0].(type) {
				case *object.String:
					command = arg.Value
				default:
					return newError("argument to `sh_exec` not supported, got %s", arg.Type())
				}
	
				attr := ""
				if len(args) > 1 {
					for i := 1; i < len(args); i++ {
						switch ar := args[i].(type) {
						case *object.String:
							attr += ar.Result()
						default:
							return newError("argument to `sh_exec` not supported, got %s", ar.Type())
						}
					}
				}
	
				cmd := exec.Command("sh", "-c", "`"+command+" "+attr+"`")
	
				output, err := cmd.CombinedOutput()
	
				if err != nil {
					return newError("command execute error %s", err)
				}
	
				return &object.Process{Pid: int64(cmd.Process.Pid), Output: string(output), Proc: cmd}
			},
		},
		"cmd_exec": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 1 {
					return newError("`cmd_exec` function needs 1 you defined only %s arguments.", len(args))
				}
	
				command := ""
				switch arg := args[0].(type) {
				case *object.String:
					command = arg.Value
				default:
					return newError("argument to `cmd_exec` not supported, got %s", arg.Type())
				}
	
				attr := ""
				if len(args) > 1 {
					for i := 1; i < len(args); i++ {
						switch ar := args[i].(type) {
						case *object.String:
							attr += ar.Result()
						default:
							return newError("argument to `cmd_exec` not supported, got %s", ar.Type())
						}
					}
				}
	
				cmd := exec.Command("cmd.exe", "/c", "`"+command+" "+attr+"`")
	
				output, err := cmd.CombinedOutput()
	
				if err != nil {
					return newError("command execute error %s", err)
				}
	
				return &object.Process{Pid: int64(cmd.Process.Pid), Output: string(output), Proc: cmd}
			},
		},
		"proc_out": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 1 {
					return newError("`proc_out` function needs 1 you defined only %s arguments.", len(args))
				}
	
				results := make([]object.Object, 0)
				for _, arg := range args {
					switch ar := arg.(type) {
					case *object.Process:
						results = append(results, &object.String{Value: ar.Output})
					default:
						return newError("argument to `proc_out` not supported, got %s", ar.Type())
					}
				}
				return &object.Array{Elements: results}
			},
		},
		"proc_pid": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 1 {
					return newError("`proc_pid` function needs 1 you defined only %s arguments.", len(args))
				}
	
				results := make([]object.Object, 0)
				for _, arg := range args {
					switch ar := arg.(type) {
					case *object.Process:
						results = append(results, &object.Integer{Value: ar.Pid})
					default:
						return newError("argument to `proc_pid` not supported, got %s", ar.Type())
					}
				}
				return &object.Array{Elements: results}
			},
		},
		"inspect": {
			Fn: func(args ...object.Object) object.Object {
				for _, arg := range args {
					switch ar := arg.(type) {
					default:
						if ar != nil {
							fmt.Println(ar.Inspect())
						}
					}
				}
				return &object.Empty{}
			},
		},
		"regexp_check": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("regexp_check function needs 2 you defined only %s arguments.", len(args))
				}
	
				switch matchstr := args[0].(type) {
				case *object.String:
					rex := regexp.MustCompile(matchstr.Value)
					switch text := args[1].(type) {
					case *object.String:
						arr := rex.MatchString(text.Value)
						return &object.Boolean{Value: arr}
					default:
						return newError("argument to `regexp_check` not supported, got %s", text.Type())
					}
				default:
					return newError("argument to `regexp_check` not supported, got %s", matchstr.Type())
				}
			},
		},
		"regexp_find": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("regexp_find function needs 2 you defined only %s arguments.", len(args))
				}
	
				switch matchstr := args[0].(type) {
				case *object.String:
					rex := regexp.MustCompile(matchstr.Value)
					switch text := args[1].(type) {
					case *object.String:
						arr := rex.FindAllString(text.Value, -2)
						resultElements := make([]object.Object, 0, 1)
						for _, result := range arr {
							_res_str := &object.String{Value: result}
							resultElements = append(resultElements, _res_str)
						}
						return &object.Array{Elements: resultElements}
					default:
						return newError("argument to `regexp_find` not supported, got %s", text.Type())
					}
				default:
					return newError("argument to `regexp_find` not supported, got %s", matchstr.Type())
				}
			},
		},
		"sock_send": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("sock_send function needs 2 you defined only %s arguments.", len(args))
				}
	
				switch arg := args[0].(type) {
				case *object.Socket:
					result := ""
					sock := arg
	
					switch msg := args[1].(type) {
					case *object.String:
						switch sock.ConType {
						case "tcp":
							addr := strings.Join([]string{sock.Addr, sock.Port}, ":")
							conn, err := net.Dial(sock.ConType, addr)
	
							defer conn.Close()
	
							if err != nil {
								log.Fatalln(err)
							}
	
							conn.Write([]byte(msg.Result()))
							buff := make([]byte, 1024)
							n, _ := conn.Read(buff)
							result = fmt.Sprintf("%s", buff[:n])
						case "udp":
							port, _ := strconv.Atoi(sock.Port)
							addr := net.UDPAddr{
								Port: port,
								IP:   net.ParseIP(sock.Addr),
							}
	
							conn, err := net.DialUDP("udp", nil, &addr)
	
							defer conn.Close()
	
							if err != nil {
								log.Fatalln(err)
							}
	
							conn.Write([]byte(msg.Result()))
							buff := make([]byte, 1024)
							n, _, err := conn.ReadFromUDP(buff)
							if err != nil {
								result = ""
							}
							result = fmt.Sprintf("%s", buff[:n])
	
						}
	
						return &object.String{Value: result}
					default:
						return newError("argument to `dial_send` not supported, got %s", arg.Type())
					}
				default:
					return newError("argument to `dial_send` not supported, got %s", arg.Type())
				}
			},
		},
		"sock_listen": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) > 6 {
					return newError("sock_listen function needs 2 you defined only %s arguments.", len(args))
				}
	
				switch sock := args[0].(type) {
				case *object.Socket:
	
					switch list := args[1].(type) {
					case *object.Hash:
						if len(args) > 2 {
							sock.DefaultResponse = args[2]
						}
						if len(args) == 6 {
							sock.OnReady = args[3].Result()
							sock.OnRequest = args[4].Result()
							sock.OnResponse = args[5].Result()
						}
						ml := make([]object.Message, 0)
	
						for _, pair := range list.Pairs {
							ml = append(ml, object.Message{Request: pair.Key.Result(), Response: pair.Value.Result()})
						}
	
						sock.Messages = ml
	
						switch sock.ConType {
						case "tcp":
							addr := strings.Join([]string{sock.Addr, sock.Port}, ":")
							listen, err := net.Listen(sock.ConType, addr)
	
							if listen == nil {
								return nil
							}
							defer listen.Close()
							if err != nil {
								os.Exit(1)
							}
	
							if sock.OnReady != "" {
								log.Println(strings.Replace(sock.OnReady, "{{addr}}", addr, -1))
							}
	
							for {
								conn, err := listen.Accept()
								if err != nil {
									continue
								}
								request := make([]byte, 1024) // set maximum request length to 128B to prevent flood based attacks
								defer conn.Close()
	
								for {
									read_len, err := conn.Read(request)
									if err != nil {
										break
									}
	
									request := string(request[:read_len])
	
									response := sock.FindResponse(request)
	
									if response == "" {
										switch defaultResponse := sock.DefaultResponse.(type) {
										case *object.Function:
											args := []object.Object{&object.String{Value: request}, &object.String{Value: response}}
											response = ApplyFunctionInside(defaultResponse, args).Result()
										default:
											response = sock.DefaultResponse.Result()
										}
									}
	
									conn.Write([]byte(response))
	
									if sock.Debugger {
										log.Println(conn.LocalAddr().String() + " < " + request)
										log.Println(conn.LocalAddr().String() + " > " + response)
									}
								}
							}
						case "udp":
							port, _ := strconv.Atoi(sock.Port)
							addr := net.UDPAddr{
								Port: port,
								IP:   net.ParseIP(sock.Addr),
							}
	
							listen, err := net.ListenUDP("udp", &addr)
	
							if listen == nil {
								return nil
							}
							defer listen.Close()
							if err != nil {
								os.Exit(1)
							}
	
							if sock.OnReady != "" {
								log.Println(strings.Replace(sock.OnReady, "{{addr}}", sock.Addr, -1))
							}
	
							for {
								request := make([]byte, 1024)
								for {
									n, addr, err := listen.ReadFromUDP(request[:])
									if err != nil {
										break
									}
	
									request := string(request[:n])
	
									response := sock.FindResponse(request)
	
									if response == "" {
										switch defaultResponse := sock.DefaultResponse.(type) {
										case *object.Function:
											args := []object.Object{&object.String{Value: request}, &object.String{Value: response}}
											response = ApplyFunctionInside(defaultResponse, args).Result()
										default:
											response = sock.DefaultResponse.Result()
										}
									}
	
									listen.WriteToUDP([]byte(response), addr)
	
									if sock.Debugger {
										log.Println(addr.IP.String() + " < " + request)
										log.Println(addr.IP.String() + " > " + response)
									}
								}
							}
						}
	
					default:
						return newError("argument to `sock_listen` not supported, got %s", sock.Type())
					}
				default:
					return newError("argument to `sock_listen` not supported, got %s", sock.Type())
				}
	
				return &object.Empty{}
			},
		},
	
		"quit": {
			Fn: func(args ...object.Object) object.Object {
				os.Exit(0)
				return &object.Empty{}
			},
		},
		"exit": {
			Fn: func(args ...object.Object) object.Object {
				os.Exit(0)
				return &object.Empty{}
			},
		},
		"database": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("database function needs 2 you defined only %s arguments.", len(args))
				}
	
				obj := &object.Database{}
	
				switch typeStr := args[0].(type) {
				case *object.String:
					obj.DbType = typeStr.Result()
				default:
					return newError("argument to `database` not supported, got %s", typeStr.Type())
				}
	
				switch conStr := args[1].(type) {
				case *object.String:
					obj.ConnString = conStr.Result()
				default:
					return newError("argument to `database` not supported, got %s", conStr.Type())
				}
	
				switch obj.DbType {
				case "postgres", "mysql", "sqlite3":
					db, err := sql.Open(obj.DbType, obj.ConnString)
					if err != nil {
						return newError("Connection failed.")
					} else {
						obj.Connection = db
					}
				case "internal":
					filename := string(obj.ConnString)
					fdb := filedb.New(filename)
					fdb.Create()
					obj.Connection = fdb
				default:
					warning := newWarning("O Language is not supported %s database type. Switched internal database mode. Sorry :(", obj.DbType)
					color.Println(warning.Result())
					filename := string(obj.ConnString)
					fdb := filedb.New(filename)
					fdb.Create()
					obj.Connection = fdb
				}
	
				return obj
			},
		},
		"model": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 3 {
					return newError("model function needs 3 you defined only %s arguments.", len(args))
				}
	
				modelReturn := &object.Model{}
	
				switch db := args[0].(type) {
				case *object.Database:
					modelReturn.Database = db
				default:
					return newError("argument to `model` not supported, got %s", db.Type())
				}
	
				switch name := args[1].(type) {
				case *object.String:
					modelReturn.Name = name.Result()
				default:
					return newError("argument to `model` not supported, got %s", name.Type())
				}
	
				switch defm := args[2].(type) {
				case *object.Hash:
					modelReturn.Columns = defm
				default:
					return newError("argument to `model` not supported, got %s", defm.Type())
				}
	
				return modelReturn
			},
		},
		"migrate": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("model function minimum needs 1 model. you defined only %s model.", len(args))
				}
	
				for _, arg := range args {
					switch model := arg.(type) {
					case *object.Model:
						switch model.Database.DbType {
						case "postgres", "mysql", "sqlite3":
							return modelMigrateSql(model)
						case "internal":
							return newError("%s doesnt support migrate function.", model.Database.DbType)
						default:
							return newError("internal doesnt support migrate function.")
						}
	
					}
				}
	
				return &object.Empty{}
			},
		},
		"fetch": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("fetch function needs 2 you defined only %s arguments.", len(args))
				}
	
				switch model := args[0].(type) {
				case *object.Model:
					switch model.Database.DbType {
					case "postgres", "mysql", "sqlite3":
						return modelFetchSql(model, args[1])
					case "internal":
						return modelFetchInternalDb(model, args[1])
					default:
						return modelFetchInternalDb(model, args[1])
					}
	
				}
	
				return &object.Empty{}
			},
		},
		"update": {
			Fn: func(args ...object.Object) object.Object {
	
				if len(args) > 2 {
					return newError("update function needs 2 or more you defined only %s arguments.", len(args))
				}
	
				switch model := args[0].(type) {
				case *object.Model:
					switch model.Database.DbType {
					case "postgres", "mysql", "sqlite3":
						return modelUpdateSql(model, args[1], args[2])
					case "internal":
						return modelUpdateInternalDb(model, args[1])
					default:
						return modelUpdateInternalDb(model, args[1])
					}
	
				}
	
				return &object.Empty{}
			},
		},
		"create": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("create function needs 2 you defined only %s arguments.", len(args))
				}
	
				switch model := args[0].(type) {
				case *object.Model:
					switch model.Database.DbType {
					case "postgres", "mysql", "sqlite3":
						return modelCreateSql(model, args[1])
					case "internal":
						return modelCreateInternalDb(model, args[1])
					default:
						return modelCreateInternalDb(model, args[1])
					}
	
				}
	
				return &object.Empty{}
			},
		},
		"delete": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("create function needs 2 you defined only %s arguments.", len(args))
				}
	
				switch model := args[0].(type) {
				case *object.Model:
					switch model.Database.DbType {
					case "postgres", "mysql", "sqlite3":
						return modelDeleteSql(model, args[1])
					case "internal":
						return modelDeleteInternalDb(model, args[1])
					default:
						return modelDeleteInternalDb(model, args[1])
					}
	
				}
	
				return &object.Empty{}
			},
		},
		"drop": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("drop function needs 1 you defined only %s arguments.", len(args))
				}
	
				switch model := args[0].(type) {
				case *object.Model:
					switch model.Database.DbType {
					case "postgres", "mysql", "sqlite3":
						return modelDropSql(model)
					case "internal":
						return newError("%s doesnt support drop function.", model.Database.DbType)
					default:
						return newError("internal doesnt support drop function.")
					}
	
				}
	
				return &object.Empty{}
			},
		},
		"truncate": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("create function needs 1 you defined only %s arguments.", len(args))
				}
	
				switch model := args[0].(type) {
				case *object.Model:
					switch model.Database.DbType {
					case "postgres", "mysql", "sqlite3":
						return modelTruncateSql(model)
					case "internal":
						return newError("%s doesnt support truncate function.", model.Database.DbType)
					default:
						return newError("internal doesnt support truncate function.")
					}
				}
	
				return &object.Empty{}
			},
		},
		"query": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 2 {
					return newError("query function needs minimum 2 you defined only %s arguments.", len(args))
				}
	
				switch model := args[0].(type) {
				case *object.Model:
					switch model.Database.DbType {
					case "postgres", "mysql", "sqlite3":
						//cols := model.Columns
						db := model.Database.Connection.(*sql.DB)
						switch query := args[1].(type) {
						case *object.String:
							if len(args) == 3 {
								switch arg := args[2].(type) {
								case *object.Array:
									return runPreparedQuery(db, query, arg)
								case *object.String:
									return runDbQuery(db, query, arg.Result())
								case *object.Integer:
									return runDbQuery(db, query, arg.Result())
								}
							}
							return runDbQuery(db, query)
						}
					case "internal":
						return newError("%s doesnt support query function.", model.Database.DbType)
					default:
						return newError("internal doesnt support query function.")
					}
				}
	
				return &object.Empty{}
			},
		},
		"search": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 2 {
					return newError("search function needs 2 you defined only %s arguments.", len(args))
				}
	
				switch model := args[0].(type) {
				case *object.Model:
					switch model.Database.DbType {
					case "postgres", "mysql", "sqlite3":
						return newError("%s doesnt support truncate function.", model.Database.DbType)
					case "internal":
						return modelSearchInternalDb(model, args[1])
					default:
						return modelSearchInternalDb(model, args[1])
					}
	
				}
	
				return &object.Empty{}
			},
		},
		"replace": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 3 {
					return newError("replace function needs 3 you defined only %s arguments.", len(args))
				}
	
				str := ""
	
				switch source := args[0].(type) {
				case *object.String:
	
					switch find := args[1].(type) {
					case *object.String:
						switch change := args[2].(type) {
						case *object.String:
							str = strings.Replace(source.Result(), find.Result(), change.Result(), -1)
	
							return &object.String{Value: str}
						default:
							return newError("argument to `replace` not supported, got %s", change.Type())
						}
					default:
						return newError("argument to `replace` not supported, got %s", find.Type())
					}
				default:
					return newError("argument to `replace` not supported, got %s", source.Type())
				}
			},
		},
		"asm": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 2 {
					return newError("asm function needs 2 or more. you defined only %s arguments.", len(args))
				}
	
				switch opCode := args[0].(type) {
				case *object.String:
					switch dest := args[1].(type) {
					case *object.String, *object.Integer, *object.Null:
						//dst = dest.Result()
	
						var newArgs []interface{}
						if len(args) > 2 {
							for i := 2; i < (len(args) - 2); i++ {
								c := (i - 2)
								newArgs[c] = args[i].Result()
							}
						}
						stub.Asm(opCode.Result(), dest.Result(), newArgs...)
						return &object.Boolean{Value: true}
					default:
						return newError("destination code must be string or integer, got %s", dest.Type())
					}
				default:
					return newError("operation code must be string, got %s", opCode.Type())
				}
			},
		},
		"math_sum": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 3 {
					return newError("math_sum() 3 arguments needed, got %s", len(args))
				}
	
				result := int64(0)
	
				switch start := args[0].(type) {
				case *object.Integer:
					switch end := args[1].(type) {
					case *object.Integer:
						switch op := args[2].(type) {
						case *object.Array:
	
							length := len(op.Elements)
	
							newElements := make([]object.Object, 0, length)
							for _, elm := range op.Elements {
								switch a := elm.(type) {
								case *object.Integer:
									for i := start.Value; i <= end.Value; i++ {
										result = result + (int64(i) * a.Value)
									}
									newElements = append(newElements, &object.Integer{Value: int64(result)})
								}
							}
							return &object.Array{Elements: newElements}
						case *object.Function:
							if len(op.Parameters) == 2 {
								args := make([]object.Object, 0, 2)
								args = append(args, start)
								args = append(args, end)
								return ApplyFunctionInside(op, args)
							}
						default:
							for i := start.Value; i <= end.Value; i++ {
								result = result + i
							}
							return &object.Integer{Value: int64(result)}
						}
					default:
						return newError("math_sum() seccond variable is must be int, your definition is %s", end.Type())
					}
				default:
					return newError("math_sum() first variable is must be int, your definition is %s", start.Type())
				}
				return &object.Empty{}
			},
		},
		"map": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 2 {
					return newError("map() function need minimum 2 value, got %s", len(args))
				}
	
				if len(args) == 2 {
					switch fun := args[0].(type) {
					case *object.Function:
						switch ob := args[1].(type) {
						case *object.Array:
							length := len(ob.Elements)
	
							newElements := make([]object.Object, 0, length)
							for _, elm := range ob.Elements {
								switch a := elm.(type) {
								case *object.Integer:
									args := make([]object.Object, 0, 1)
									args = append(args, a)
									newElements = append(newElements, ApplyFunctionInside(fun, args))
								}
							}
							return &object.Array{Elements: newElements}
						case *object.Hash:
							length := len(ob.Pairs)
							newElements := make([]object.Object, 0, length)
							for _, pair := range ob.Pairs {
								args := make([]object.Object, 0, 2)
								args = append(args, pair.Key)
								args = append(args, pair.Value)
								newElements = append(newElements, ApplyFunctionInside(fun, args))
							}
							return &object.Array{Elements: newElements}
						default:
							return newError("map() second variable is must be array or hash, your definition is %s", ob.Type())
						}
					default:
						return newError("map() first variable is must be function, needs one or two parameters, your definition is %s", fun.Type())
					}
				}
	
				if len(args) > 2 {
					switch fun := args[0].(type) {
					case *object.Function:
						totalArgs := len(args)
						dropedFunc := make([]object.Object, totalArgs-1)
						copy(dropedFunc, args[1:totalArgs])
	
						return ApplyFunctionInside(fun, dropedFunc)
					default:
						return newError("map() first variable is must be function, needs some parameters, your definition is %s", fun.Type())
					}
				}
	
				return &object.Empty{}
			},
		},
		"math_cos": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("math_cos() function need one argument, got %s", len(args))
				}
	
				switch num := args[0].(type) {
				case *object.Integer:
					result := math.Cos(float64(num.Value))
					return &object.Float{Value: result}
				case *object.Float:
					result := math.Cos(num.Value)
					return &object.Float{Value: result}
				default:
					return newError("math_cos() first variable is must be integer, your definition is %s", num.Type())
				}
			},
		},
		"math_sin": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("math_sin() function need one argument, got %s", len(args))
				}
	
				switch num := args[0].(type) {
				case *object.Integer:
					result := math.Sin(float64(num.Value))
					return &object.Float{Value: result}
				case *object.Float:
					result := math.Sin(num.Value)
					return &object.Float{Value: result}
				default:
					return newError("math_sin() first variable is must be integer, your definition is %s", num.Type())
				}
			},
		},
		"math_tan": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("math_tan() function need one argument, got %s", len(args))
				}
	
				switch num := args[0].(type) {
				case *object.Integer:
					result := math.Tan(float64(num.Value))
					return &object.Float{Value: result}
				case *object.Float:
					result := math.Tan(num.Value)
					return &object.Float{Value: result}
				default:
					return newError("math_tan() first variable is must be integer, your definition is %s", num.Type())
				}
			},
		},
		"math_log": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("math_log() function need one argument, got %s", len(args))
				}
	
				switch num := args[0].(type) {
				case *object.Integer:
					result := math.Log(float64(num.Value))
					return &object.Float{Value: result}
				case *object.Float:
					result := math.Log(num.Value)
					return &object.Float{Value: result}
				default:
					return newError("math_log() first variable is must be integer, your definition is %s", num.Type())
				}
			},
		},
		"math_abs": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) != 1 {
					return newError("math_abs() function need one argument, got %s", len(args))
				}
	
				switch num := args[0].(type) {
				case *object.Integer:
					result := math.Abs(float64(num.Value))
					return &object.Float{Value: result}
				case *object.Float:
					result := math.Abs(num.Value)
					return &object.Float{Value: result}
				default:
					return newError("math_abs() first variable is must be integer, your definition is %s", num.Type())
				}
			},
		},
	
		"output": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) <= 0 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				result := &object.String{}
	
				switch str := args[0].(type) {
				case *object.String:
					length := len(args)
					newArgs := make([]object.Object, length-1)
					copy(newArgs, args[1:length])
					convertObj := make([]interface{}, 0)
					for i := 0; i < len(newArgs); i++ {
						convertObj = append(convertObj, newArgs[i].Result())
					}
					result.Value = fmt.Sprintf(str.Result(), convertObj...)
	
					fmt.Println(result.Result())
	
					return &object.Empty{}
				default:
					return newError("output() first variable is must be string, your definition is %s", str.Type())
				}
			},
		},
	
		"input": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) <= 0 {
					return newError("wrong number of arguments. got=%d, want=1", len(args))
				}
	
				switch text := args[0].(type) {
				case *object.String:
					fmt.Print(text.Result())
	
				}
	
				var stdin *bufio.Reader
				var line []rune
				var c rune
				var err error
	
				stdin = bufio.NewReader(os.Stdin)
	
				for {
					c, _, _ = stdin.ReadRune()
					if err == io.EOF || c == '\n' {
						break
					}
					line = append(line, c)
				}
	
				return &object.String{Value: string(line[:])}
			},
		},
	
		"encrypt": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 2 {
					return newError("encrypt() function needs 2 arguments, got %s", len(args))
				}
	
				switch key := args[0].(type) {
				case *object.String:
					switch data := args[1].(type) {
					case *object.String:
						enc := crypto.New(key.Result())
						return &object.String{Value: enc.Encrypt(data.Result())}
					default:
						return newError("encrypt() function second value (data) must be string, got %s", data.Type())
					}
				default:
					return newError("encrypt() function first value (key) must be string, got %s", key.Type())
				}
			},
		},
	
		"decrypt": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 2 {
					return newError("decrypt() function needs 2 arguments, got %s", len(args))
				}
	
				switch key := args[0].(type) {
				case *object.String:
					switch data := args[1].(type) {
					case *object.String:
						enc := crypto.New(key.Result())
						return &object.String{Value: enc.Decrypt(data.Result())}
					default:
						return newError("encrypt() function second value (data) must be string, got %s", data.Type())
					}
				default:
					return newError("encrypt() function first value (key) must be string, got %s", key.Type())
				}
			},
		},
		"hash_encode": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 2 {
					return newError("hash_encode() function needs 2 arguments, got %s", len(args))
				}
	
				switch hashType := args[0].(type) {
				case *object.String:
					switch hashType.Result() {
					case "base64":
						switch data := args[1].(type) {
						case *object.String:
							encodedString := base64.StdEncoding.EncodeToString([]byte(data.Result()))
							return &object.String{Value: encodedString}
						default:
							return newError("hash_encode() function second value (data) must be string, got %s", data.Type())
						}
					case "md5":
						switch data := args[1].(type) {
						case *object.String:
							hasher := md5.New()
							hasher.Write([]byte(data.Result()))
							return &object.String{Value: hex.EncodeToString(hasher.Sum(nil))}
						default:
							return newError("hash_encode() function second value (data) must be string, got %s", data.Type())
						}
					}
	
				default:
					return newError("hash_encode() function first value (type) must be string, got %s", hashType.Type())
				}
				return &object.Empty{}
			},
		},
	
		"hash_decode": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 2 {
					return newError("hash_decode() function needs 2 arguments, got %s", len(args))
				}
	
				switch hashType := args[0].(type) {
				case *object.String:
					switch hashType.Result() {
					case "base64":
						switch data := args[1].(type) {
						case *object.String:
							originalStringBytes, err := base64.StdEncoding.DecodeString(data.Result())
							if err != nil {
								newError("hash_decode() Some error occured during base64 decode. Error: %s", err.Error())
							}
							return &object.String{Value: string(originalStringBytes)}
						default:
							return newError("hash_decode() function second value (data) must be string, got %s", data.Type())
						}
					case "md5":
						switch data := args[1].(type) {
						case *object.String:
							return newError("hash_decode() function not support %s decode", hashType)
						default:
							return newError("hash_decode() function second value (data) must be string, got %s", data.Type())
						}
					}
	
				default:
					return newError("hash_decode() function first value (type) must be string, got %s", hashType.Type())
				}
				return &object.Empty{}
			},
		},
		"type": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 1 {
					return newError("type() function needs 1 arguments, got %s", len(args))
				}
				return &object.String{Value: string(args[0].Type())}
			},
		},
		"fwatch": {
			Fn: func(args ...object.Object) object.Object {
				if len(args) < 2 {
					return newError("fwatch() function needs 2 arguments, got %s", len(args))
				}
	
				switch file := args[0].(type) {
				case *object.String:
					switch fn := args[1].(type) {
					case *object.Function:
						w := watcher.New()
	
						w.Add(file.Result())
	
						w.Run(func() {
							obj := make([]object.Object, 0, 1)
							ApplyFunctionInside(fn, obj)
						})
					default:
						return newError("fwatch() function second must be function, got %s", fn.Type())
					}
				default:
					return newError("fwatch() function first value must be string, got %s", file.Type())
				}
	
				return &object.Empty{}
			},
		},
	}
	
	var PreBuiltFunctions = builtins