lib

package
v0.0.0-...-0fc4dc5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 2, 2025 License: BSD-2-Clause Imports: 101 Imported by: 0

Documentation

Index

Constants

View Source
const MAX_PARSE_FORM_MEMORY = 10000

Variables

View Source
var Assert = []sim.NativeFunction{
	{
		Name:      "assert.contains",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var msg string
			ln := len(args)
			switch ln {
			case 2:
				if err := ValidateArgs(args, sim.String, sim.String); err != nil {
					return sim.NullValue, err
				}
			case 3:
				if err := ValidateArgs(args, sim.String, sim.String, sim.String); err != nil {
					return sim.NullValue, err
				}
				msg = args[2].String()
			default:
				return sim.NullValue, fmt.Errorf("expected 2 or 3 args, got %d", ln)
			}

			a := args[0].String()
			b := args[1].String()

			if !strings.Contains(b, a) {
				if msg != "" {
					return sim.NullValue, errors.New(msg)
				}
				return sim.NullValue, fmt.Errorf("'%s' not contained in '%s'", a, b)
			}
			return sim.NullValue, nil
		},
	},

	{
		Name:      "assert.equal",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var msg string
			ln := len(args)
			switch ln {
			case 2:
			case 3:
				a3 := args[2]
				if a3.Type != sim.String {
					return sim.NullValue, fmt.Errorf("expected error message to be a string, got %v", a3.TypeName())
				}
				msg = a3.String()
			default:
				return sim.NullValue, fmt.Errorf("expected 2 or 3 args, got %d", ln)

			}

			a := args[0]
			b := args[1]

			if !areEqual(a, b) {
				if msg != "" {
					return sim.NullValue, errors.New(msg)
				}
				return sim.NullValue, fmt.Errorf("values are different: %v, %v", serializeOrErr(a), serializeOrErr(b))
			}
			return sim.NullValue, nil
		},
	},
	{
		Name:      "assert.isTrue",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var msg string
			ln := len(args)
			switch ln {
			case 1:
			case 2:
				if args[1].Type != sim.String {
					return sim.NullValue, fmt.Errorf("expected error message to be a string, got %v", args[1].TypeName())
				}
				msg = args[1].String()
			default:
				return sim.NullValue, fmt.Errorf("expected 1 or 2 args, got %d", ln)
			}

			a := args[0]

			switch a.Type {
			case sim.Bool:
				if a.ToBool() {
					return sim.TrueValue, nil
				}
			}

			if msg != "" {
				return sim.NullValue, errors.New(msg)
			}
			return sim.NullValue, fmt.Errorf("expected true, got %v", a)
		},
	},
	{
		Name:      "assert.isFalse",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var msg string
			ln := len(args)
			switch ln {
			case 1:
			case 2:
				if args[1].Type != sim.String {
					return sim.NullValue, fmt.Errorf("expected error message to be a string, got %v", args[1].TypeName())
				}
				msg = args[1].String()
			default:
				return sim.NullValue, fmt.Errorf("expected 1 or 2 args, got %d", ln)
			}

			a := args[0]

			switch a.Type {
			case sim.Bool:
				if !a.ToBool() {
					return sim.TrueValue, nil
				}
			}

			if msg != "" {
				return sim.NullValue, errors.New(msg)
			}
			return sim.NullValue, fmt.Errorf("expected false, got %v", a)
		},
	},
	{
		Name:      "assert.isNull",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var msg string
			ln := len(args)
			switch ln {
			case 1:
			case 2:
				if args[1].Type != sim.String {
					return sim.NullValue, fmt.Errorf("expected error message to be a string, got %v", args[1].TypeName())
				}
				msg = args[1].String()
			default:
				return sim.NullValue, fmt.Errorf("expected 1 or 2 args, got %d", ln)
			}

			a := args[0]

			switch a.Type {
			case sim.Null, sim.Undefined:
			default:
				if msg != "" {
					return sim.NullValue, errors.New(msg)
				}
				return sim.NullValue, fmt.Errorf("expected null, got %v", a)
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "assert.isNotNull",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var msg string
			ln := len(args)
			switch ln {
			case 1:
			case 2:
				if args[1].Type != sim.String {
					return sim.NullValue, fmt.Errorf("expected error message to be a string, got %v", args[1].TypeName())
				}
				msg = args[1].String()
			default:
				return sim.NullValue, fmt.Errorf("expected 1 or 2 args, got %d", ln)
			}

			a := args[0]

			switch a.Type {
			case sim.Null, sim.Undefined:
				if msg != "" {
					return sim.NullValue, errors.New(msg)
				}
				return sim.NullValue, fmt.Errorf("%v is null", a)
			default:
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "assert.exception",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			if a.Type != sim.String {
				return sim.NullValue, fmt.Errorf("expected argument 1 to be a string, got %s", a.TypeName())
			}

			expected := a.String()

			v := args[1]
			err := runFuncOrClosure(vm, v)
			if err == nil {
				return sim.NullValue, fmt.Errorf("expected exception: %s", expected)
			}

			if expected != "" && !strings.Contains(err.Error(), expected) {
				return sim.NullValue, fmt.Errorf("invalid exception, does not contain '%s': %s", expected, err.Error())
			}

			vm.Error = nil

			return sim.NullValue, nil
		},
	},
	{
		Name:      "assert.int",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[1]) {
				return sim.NullValue, fmt.Errorf("expected argument 2 to be a string, got %s", args[1].TypeName())
			}

			a := args[0]
			msg := args[1].String()

			var v int64
			var err error

			switch a.Type {
			case sim.Int:
				v = a.ToInt()
			case sim.String:
				v, err = strconv.ParseInt(a.String(), 0, 64)
				if err != nil {
					return sim.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not int", a.TypeName()))
				}
			default:
				return sim.NullValue, errors.New(msg)
			}

			return sim.NewInt64(v), nil
		},
	},
	{
		Name:      "assert.float",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[1]) {
				return sim.NullValue, fmt.Errorf("expected argument 2 to be a string, got %s", args[1].TypeName())
			}

			a := args[0]
			msg := args[1].String()

			var v int64
			var err error

			switch a.Type {
			case sim.Int:
				v = a.ToInt()
			case sim.String:
				v, err = strconv.ParseInt(a.String(), 0, 64)
				if err != nil {
					return sim.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not float", a.TypeName()))
				}
			default:
				return sim.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not float", a.TypeName()))
			}

			return sim.NewInt64(v), nil
		},
	},
	{
		Name:      "assert.string",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[1]) {
				return sim.NullValue, fmt.Errorf("expected argument 2 to be a string, got %s", args[1].TypeName())
			}

			a := args[0]
			msg := args[1].String()

			var v string

			switch a.Type {
			case sim.Int, sim.Float, sim.Bool, sim.String:
				v = a.String()
			default:
				return sim.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not a string", a.TypeName()))
			}

			return sim.NewString(v), nil
		},
	},
	{
		Name:      "assert.bool",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[1]) {
				return sim.NullValue, fmt.Errorf("expected argument 2 to be a string, got %s", args[1].TypeName())
			}

			a := args[0]
			msg := args[1].String()
			var v sim.Value

			switch a.Type {

			case sim.Bool:
				v = a

			case sim.Int:
				switch a.ToInt() {
				case 0:
					v = sim.FalseValue
				case 1:
					v = sim.TrueValue
				default:
					return sim.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not bool", a.TypeName()))
				}

			case sim.String:
				s := a.String()
				s = strings.Trim(s, " ")
				switch s {
				case "true", "1":
					v = sim.TrueValue
				case "false", "0":
					v = sim.FalseValue
				default:
					return sim.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not bool", a.TypeName()))
				}

			default:
				return sim.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not bool", a.TypeName()))

			}

			return v, nil
		},
	},
	{
		Name:      "assert.object",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[1]) {
				return sim.NullValue, fmt.Errorf("expected argument 2 to be a string, got %s", args[1].TypeName())
			}

			a := args[0]
			msg := args[1].String()

			switch a.Type {
			case sim.Map:
			default:
				return sim.NullValue, fmt.Errorf(msg, showAssertMessage("%v is not an object", a.TypeName()))
			}

			return a, nil
		},
	},
}
View Source
var Async = []sim.NativeFunction{
	{
		Name:        "go",
		Arguments:   1,
		Permissions: []string{"async"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return launchGoroutine(args, vm, nil)
		},
	},
}
View Source
var Atomic = []sim.NativeFunction{
	{
		Name:      "atomic.addInt",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int, sim.Int); err != nil {
				return sim.NullValue, err
			}

			i := args[0]
			v := args[1]

			// Handle both pointer and direct int64 values
			var ptr *int64
			switch val := i.Internal.(type) {
			case *int64:
				ptr = val
			case int64:

				newVal := val + v.ToInt()
				i.Internal = newVal
				return sim.NewInt64(newVal), nil
			default:
				return sim.NullValue, fmt.Errorf("expected an int, got %T", i.Internal)
			}

			atomic.AddInt64(ptr, v.ToInt())

			return i, nil
		},
	},
	{
		Name:      "atomic.storeInt",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int, sim.Int); err != nil {
				return sim.NullValue, err
			}

			i := args[0]
			v := args[1]

			// Handle both pointer and direct int64 values
			var ptr *int64
			switch val := i.Internal.(type) {
			case *int64:
				ptr = val
			case int64:

				newVal := v.ToInt()
				i.Internal = newVal
				return sim.NewInt64(newVal), nil
			default:
				return sim.NullValue, fmt.Errorf("expected an int, got %T", i.Internal)
			}

			atomic.StoreInt64(ptr, v.ToInt())

			return i, nil
		},
	},
	{
		Name:      "atomic.loadInt",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			i := args[0]

			switch val := i.Internal.(type) {
			case *int64:
				v := atomic.LoadInt64(val)
				return sim.NewInt64(v), nil
			case int64:

				return sim.NewInt64(val), nil
			default:
				return sim.NullValue, fmt.Errorf("expected an int, got %T", i.Internal)
			}
		},
	},
}
View Source
var Base64 = []sim.NativeFunction{
	{
		Name:      "base64.encode",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			switch a.Type {
			case sim.Null, sim.Undefined:
				return sim.NullValue, nil
			case sim.Bytes, sim.String:
				encoder := base64.RawStdEncoding
				encoded := encoder.EncodeToString(a.ToBytes())
				return sim.NewString(encoded), nil
			default:
				return sim.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
	{
		Name:      "base64.encodeWithPadding",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			switch a.Type {
			case sim.Null, sim.Undefined:
				return sim.NullValue, nil
			case sim.Bytes, sim.String:
				encoder := base64.StdEncoding.WithPadding(base64.StdPadding)
				encoded := encoder.EncodeToString(a.ToBytes())
				return sim.NewString(encoded), nil
			default:
				return sim.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
	{
		Name:      "base64.encodeURLWithPadding",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			switch a.Type {
			case sim.Null, sim.Undefined:
				return sim.NullValue, nil
			case sim.Bytes, sim.String:
				encoder := base64.RawURLEncoding.WithPadding(base64.StdPadding)
				encoded := encoder.EncodeToString(a.ToBytes())
				return sim.NewString(encoded), nil
			default:
				return sim.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
	{
		Name:      "base64.decode",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			switch a.Type {
			case sim.Null, sim.Undefined:
				return sim.NullValue, nil
			case sim.String:
				encoder := base64.RawStdEncoding
				decoded, err := encoder.DecodeString(a.String())
				if err != nil {
					return sim.NullValue, err
				}
				return sim.NewBytes(decoded), nil
			default:
				return sim.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
	{
		Name:      "base64.decodeWithPadding",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			switch a.Type {
			case sim.Null, sim.Undefined:
				return sim.NullValue, nil
			case sim.String:
				encoder := base64.StdEncoding.WithPadding(base64.StdPadding)
				encoded, err := encoder.DecodeString(a.String())
				if err != nil {
					return sim.NullValue, err
				}
				return sim.NewBytes(encoded), nil
			default:
				return sim.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
}
View Source
var Binary = []sim.NativeFunction{
	{
		Name:      "binary.putInt16LittleEndian",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Int); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.LittleEndian.PutUint16(b, uint16(i))
			return sim.NullValue, nil
		},
	},
	{
		Name:      "binary.putInt32LittleEndian",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Int); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.LittleEndian.PutUint32(b, uint32(i))
			return sim.NullValue, nil
		},
	},
	{
		Name:      "binary.putInt64LittleEndian",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Int); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.LittleEndian.PutUint64(b, uint64(i))
			return sim.NullValue, nil
		},
	},
	{
		Name:      "binary.putInt16BigEndian",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Int); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.BigEndian.PutUint16(b, uint16(i))
			return sim.NullValue, nil
		},
	},
	{
		Name:      "binary.putInt32BigEndian",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Int); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.BigEndian.PutUint32(b, uint32(i))
			return sim.NullValue, nil
		},
	},
	{
		Name:      "binary.putInt64BigEndian",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Int); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := args[1].ToInt()
			binary.BigEndian.PutUint64(b, uint64(i))
			return sim.NullValue, nil
		},
	},
	{
		Name:      "binary.int16LittleEndian",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.LittleEndian.Uint16(b)
			return sim.NewInt64(int64(i)), nil
		},
	},
	{
		Name:      "binary.int32LittleEndian",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.LittleEndian.Uint32(b)
			return sim.NewInt64(int64(i)), nil
		},
	},
	{
		Name:      "binary.int64LittleEndian",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.LittleEndian.Uint64(b)
			return sim.NewInt64(int64(i)), nil
		},
	},
	{
		Name:      "binary.int16BigEndian",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.BigEndian.Uint16(b)
			return sim.NewInt64(int64(i)), nil
		},
	},
	{
		Name:      "binary.int32BigEndian",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.BigEndian.Uint32(b)
			return sim.NewInt64(int64(i)), nil
		},
	},
	{
		Name:      "binary.int64BigEndian",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			i := binary.BigEndian.Uint64(b)
			return sim.NewInt64(int64(i)), nil
		},
	},
}
View Source
var Bufio = []sim.NativeFunction{
	{
		Name:      "bufio.newScanner",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			r := args[0].ToObject()

			reader, ok := r.(io.Reader)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected a io.Reader, got %v", args[0])
			}

			s := bufio.NewScanner(reader)

			return sim.NewObject(&scanner{s}), nil
		},
	},
	{
		Name:      "bufio.newReader",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			r := args[0].ToObject()

			reader, ok := r.(io.Reader)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected a io.Reader, got %v", args[0])
			}

			s := bufio.NewReader(reader)

			return sim.NewObject(&bufioReader{s}), nil
		},
	},
	{
		Name:      "bufio.newWriter",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			r := args[0].ToObject()

			w, ok := r.(io.Writer)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected a io.Writer, got %v", args[0])
			}

			s := bufio.NewWriter(w)

			return sim.NewObject(&bufioWriter{s}), nil
		},
	},
}
View Source
var Bytecode = []sim.NativeFunction{
	{
		Name:      "bytecode.compile",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}

			path := args[0].String()

			var fs filesystem.FS

			l := len(args)

			if l > 1 {
				filesystem, ok := args[1].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return sim.NullValue, fmt.Errorf("expected a filesystem, got %v", args[1])
				}
				fs = filesystem.FS
			} else {
				fs = vm.FileSystem
			}

			p, err := sim.Compile(fs, path)
			if err != nil {
				return sim.NullValue, fmt.Errorf("compiling %s: %w", path, err)
			}

			if err := ValidatePermissions(p, vm); err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(&program{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.compileStr",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			code := args[0].String()

			p, err := sim.CompileStr(code)
			if err != nil {
				return sim.NullValue, errors.New(err.Error())
			}

			if err := ValidatePermissions(p, vm); err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(&program{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.hash",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.Bool, sim.Bool, sim.Object); err != nil {
				return sim.NullValue, err
			}

			path := args[0].String()

			var fs filesystem.FS

			l := len(args)

			if l > 1 {
				filesystem, ok := args[1].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return sim.NullValue, fmt.Errorf("expected a filesystem, got %v", args[1])
				}
				fs = filesystem.FS
			} else {
				fs = vm.FileSystem
			}

			hash, err := parser.Hash(fs, path)
			if err != nil {
				return sim.NullValue, fmt.Errorf("compiling %s: %w", path, err)
			}

			s := base64.StdEncoding.EncodeToString(hash)
			return sim.NewString(s), nil
		},
	},
	{
		Name:      "bytecode.parseStr",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			code := args[0].String()

			p, err := sim.ParseStr(code)
			if err != nil {
				return sim.NullValue, errors.New(err.Error())
			}

			return sim.NewObject(&astProgram{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.loadProgram",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			p, err := binary.Load(args[0].ToBytes())
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(&program{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.load",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}

			l := len(args)
			path := args[0].String()
			var fs filesystem.FS

			if l > 1 {
				filesystem, ok := args[1].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return sim.NullValue, fmt.Errorf("expected a filesystem, got %v", args[1])
				}
				fs = filesystem.FS
			} else {
				fs = vm.FileSystem
			}

			f, err := fs.Open(path)
			if err != nil {
				return sim.NullValue, err
			}
			defer f.Close()

			p, err := binary.Read(f)
			if err != nil {
				return sim.NullValue, err
			}

			p.Name = strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))

			return sim.NewObject(&program{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.readProgram",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			r, ok := args[0].ToObjectOrNil().(io.Reader)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected parameter 1 to be io.Reader, got %T", args[0].ToObjectOrNil())
			}

			p, err := binary.Read(r)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(&program{prog: p}), nil
		},
	},
	{
		Name:      "bytecode.writeProgram",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object, sim.Object); err != nil {
				return sim.NullValue, err
			}

			w, ok := args[0].ToObjectOrNil().(io.Writer)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected parameter 1 to be io.Reader, got %T", args[0].ToObjectOrNil())
			}

			p, ok := args[1].ToObjectOrNil().(*program)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected parameter 2 to be a program, got %T", args[0].ToObjectOrNil())
			}

			if err := binary.Write(w, p.prog); err != nil {
				return sim.NullValue, err
			}

			return sim.NullValue, nil
		},
	},
}
View Source
var Bytes = []sim.NativeFunction{
	{
		Name:      "bytes.newReader",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			r := args[0].ToBytes()

			s := bytes.NewReader(r)

			reader := NewReader(s)

			return sim.NewObject(reader), nil
		},
	},
	{
		Name:      "bytes.replace",
		Arguments: 4,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Bytes, sim.Bytes, sim.Int); err != nil {
				return sim.NullValue, err
			}

			b := bytes.Replace(args[0].ToBytes(), args[1].ToBytes(), args[2].ToBytes(), int(args[3].ToInt()))
			return sim.NewBytes(b), nil
		},
	},
	{
		Name:      "bytes.replaceAll",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Bytes, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			b := bytes.ReplaceAll(args[0].ToBytes(), args[1].ToBytes(), args[2].ToBytes())
			return sim.NewBytes(b), nil
		},
	},
	{
		Name:      "Bytes.prototype.copyAt",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if args[0].Type != sim.Int {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be int, got %s", args[0].TypeName())
			}

			switch args[1].Type {
			case sim.Bytes, sim.Array, sim.String:
			default:
				return sim.NullValue, fmt.Errorf("expected arg 2 to be bytes, got %s", args[1].TypeName())
			}

			a := this.ToBytes()
			start := int(args[0].ToInt())
			b := args[1].ToBytes()

			lenB := len(b)

			if lenB+start > len(a) {
				return sim.NullValue, fmt.Errorf("the array has not enough capacity")
			}

			for i := 0; i < lenB; i++ {
				a[i+start] = b[i]
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "Bytes.prototype.append",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if this.Type != sim.Bytes {
				return sim.NullValue, fmt.Errorf("expected byte array, got %s", this.TypeName())
			}
			a := this.ToBytes()

			b := args[0]
			if b.Type != sim.Bytes {
				return sim.NullValue, fmt.Errorf("expected array, got %s", b.TypeName())
			}

			c := append(a, b.ToBytes()...)

			return sim.NewBytes(c), nil
		},
	},
	{
		Name:      "Bytes.prototype.indexOf",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if this.Type != sim.Bytes {
				return sim.NullValue, fmt.Errorf("expected byte array, got %s", this.TypeName())
			}
			a := this.ToBytes()
			v := byte(args[0].ToInt())

			for i, j := range a {
				if j == v {
					return sim.NewInt(i), nil
				}
			}

			return sim.NewInt(-1), nil
		},
	},
	{
		Name: "Bytes.prototype.reverse",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if this.Type != sim.Bytes {
				return sim.NullValue, fmt.Errorf("expected byte array, got %s", this.TypeName())
			}
			a := this.ToBytes()
			l := len(a) - 1

			for i, k := 0, l/2; i <= k; i++ {
				a[i], a[l-i] = a[l-i], a[i]
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "Bytes.prototype.slice",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if this.Type != sim.Bytes {
				return sim.NullValue, fmt.Errorf("expected string array, got %s", this.TypeName())
			}
			a := this.ToBytes()
			l := len(a)

			switch len(args) {
			case 0:
				a = a[0:]
			case 1:
				a = a[int(args[0].ToInt()):]
			case 2:
				start := int(args[0].ToInt())
				if start < 0 || start > l {
					return sim.NullValue, fmt.Errorf("index out of range")
				}

				end := start + int(args[1].ToInt())
				if end < 0 || end > l {
					return sim.NullValue, fmt.Errorf("index out of range")
				}

				a = a[start:end]
			default:
				return sim.NullValue, fmt.Errorf("expected 0, 1 or 2 params, got %d", len(args))
			}

			return sim.NewBytes(a), nil
		},
	},
	{
		Name:      "Bytes.prototype.range",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if this.Type != sim.Bytes {
				return sim.NullValue, fmt.Errorf("expected array, called on %s", this.TypeName())
			}
			a := this.ToBytes()
			l := len(a)

			switch len(args) {
			case 0:
				a = a[0:]
			case 1:
				a = a[int(args[0].ToInt()):]
			case 2:
				start := int(args[0].ToInt())
				if start < 0 || start > l {
					return sim.NullValue, fmt.Errorf("index out of range")
				}

				end := int(args[1].ToInt())
				if end < 0 || end > l {
					return sim.NullValue, fmt.Errorf("index out of range")
				}

				a = a[start:end]
			default:
				return sim.NullValue, fmt.Errorf("expected 0, 1 or 2 params, got %d", len(args))
			}

			return sim.NewBytes(a), nil
		},
	},
}
View Source
var CSV = []sim.NativeFunction{
	{
		Name:      "csv.newReader",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			r, ok := args[0].ToObject().(io.Reader)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}

			reader := csv.NewReader(r)

			return sim.NewObject(&csvReader{reader}), nil
		},
	},
	{
		Name:      "csv.newWriter",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			w, ok := args[0].ToObject().(io.Writer)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}

			writer := csv.NewWriter(w)

			return sim.NewObject(&csvWriter{writer}), nil
		},
	},
}
View Source
var Caching = []sim.NativeFunction{
	{
		Name:      "caching.newCache",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := len(args)

			var d time.Duration

			switch l {
			case 0:
				d = 1 * time.Minute
			case 1:
				var a = args[0]
				switch a.Type {
				case sim.Int:
					dd, err := ToDuration(a)
					if err != nil {
						return sim.NullValue, err
					}
					d = dd
				case sim.Object:
					dur, ok := a.ToObject().(Duration)
					if !ok {
						return sim.NullValue, fmt.Errorf("expected duration, got %s", a.TypeName())
					}
					d = time.Duration(dur)
				}
			default:
				return sim.NullValue, fmt.Errorf("expected 0 or 1 arguments, got %d", l)
			}
			return sim.NewObject(newCacheObj(d)), nil
		},
	},
}
View Source
var Console = []sim.NativeFunction{
	{
		Name:      "console.debug",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return consoleLog(true, args, vm)
		},
	},
	{
		Name:      "console.enableDebug",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			debugEnabled = true
			return sim.NullValue, nil
		},
	},
	{
		Name:      "console.disableDebug",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			debugEnabled = false
			return sim.NullValue, nil
		},
	},
	{
		Name:      "console.log",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return consoleLog(false, args, vm)
		},
	},
	{
		Name:      "console.enableTrace",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			traceEnabled = true
			return sim.NullValue, nil
		},
	},
	{
		Name:      "console.disableTrace",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			traceEnabled = false
			return sim.NullValue, nil
		},
	},
}
View Source
var Convert = []sim.NativeFunction{
	{
		Name:      "parseInt",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 0, 1, 2); err != nil {
				return sim.NullValue, err
			}

			if len(args) == 0 {
				return sim.NewFloat(math.NaN()), nil
			}

			var a sim.Value
			var radix int

			switch len(args) {
			case 0:
				return sim.NewFloat(math.NaN()), nil

			case 1:
				a = args[0]
				radix = 10
			case 2:
				a = args[0]
				radix = int(args[1].ToInt())
			}

			if radix == 0 {
				radix = 10
			}
			if radix < 2 || radix > 36 {
				return sim.NewFloat(math.NaN()), nil
			}

			var str string
			switch a.Type {
			case sim.String:
				str = a.String()
			case sim.Int, sim.Float, sim.Rune:
				str = a.String()
			default:
				return sim.NewFloat(math.NaN()), nil
			}

			str = strings.TrimLeft(str, " \t\n\r\v\f")

			if str == "" {
				return sim.NewFloat(math.NaN()), nil
			}

			if radix == 10 && len(str) > 2 && strings.ToLower(str[:2]) == "0x" {
				radix = 16
				str = str[2:]
			}

			sign := 1
			switch str[0] {
			case '-':
				sign = -1
				str = str[1:]
			case '+':
				str = str[1:]
			}

			if str == "" {
				return sim.NewFloat(math.NaN()), nil
			}

			result := int64(0)
			parsedAnyDigit := false
			for _, char := range str {
				digit := -1

				if char >= '0' && char <= '9' {
					digit = int(char - '0')
				} else if char >= 'a' && char <= 'z' {
					digit = int(char - 'a' + 10)
				} else if char >= 'A' && char <= 'Z' {
					digit = int(char - 'A' + 10)
				}

				if digit == -1 || digit >= radix {
					break
				}

				parsedAnyDigit = true
				result = result*int64(radix) + int64(digit)
			}

			if !parsedAnyDigit {
				return sim.NewFloat(math.NaN()), nil
			}

			return sim.NewInt64(int64(sign) * result), nil
		},
	},
	{
		Name:      "parseFloat",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 1); err != nil {
				return sim.NullValue, err
			}

			a := args[0]
			var str string
			switch a.Type {
			case sim.String:
				str = a.String()
			case sim.Int, sim.Float, sim.Rune:
				str = a.String()
			default:
				return sim.NewFloat(math.NaN()), nil
			}

			str = strings.TrimLeft(str, " \t\n\r\v\f")

			if str == "" {
				return sim.NewFloat(math.NaN()), nil
			}

			if str == "Infinity" || str == "+Infinity" {
				return sim.NewFloat(math.Inf(1)), nil
			}
			if str == "-Infinity" {
				return sim.NewFloat(math.Inf(-1)), nil
			}
			if str == "NaN" {
				return sim.NewFloat(math.NaN()), nil
			}

			sign := 1.0
			if len(str) > 0 {
				switch str[0] {
				case '-':
					sign = -1
					str = str[1:]
				case '+':
					str = str[1:]
				}
			}

			if str == "" {
				return sim.NewFloat(math.NaN()), nil
			}

			hasDecimal := false
			hasExponent := false
			result := 0.0
			decimalPlaces := 0.0
			exponentPart := ""
			inExponent := false
			parsedAnyDigit := false

			for i, char := range str {
				if (char == 'e' || char == 'E') && !hasExponent && i > 0 && parsedAnyDigit {
					hasExponent = true
					inExponent = true
					continue
				}

				if inExponent {
					if char == '+' || char == '-' || (char >= '0' && char <= '9') {
						exponentPart += string(char)
						continue
					} else {
						break
					}
				}

				if char == '.' && !hasDecimal && !inExponent {
					hasDecimal = true
					continue
				}

				if char >= '0' && char <= '9' {
					parsedAnyDigit = true
					if hasDecimal {
						decimalPlaces++
						result = result + float64(char-'0')/math.Pow(10, decimalPlaces)
					} else {
						result = result*10 + float64(char-'0')
					}
				} else {

					if i == 0 {
						return sim.NewFloat(math.NaN()), nil
					}
					break
				}
			}

			if !parsedAnyDigit {
				return sim.NewFloat(math.NaN()), nil
			}

			if hasExponent && exponentPart != "" {
				if exp, err := strconv.ParseInt(exponentPart, 10, 64); err == nil {
					result *= math.Pow(10, float64(exp))
				}
			}

			return sim.NewFloat(sign * result), nil
		},
	},
	{
		Name:      "convert.toByte",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			var r sim.Value

			switch a.Type {
			case sim.String:
			default:
				return sim.NullValue, fmt.Errorf("can't convert %v to byte", a.Type)
			}

			s := a.String()
			if len(s) != 1 {
				return sim.NullValue, fmt.Errorf("can't convert %v to int", a.Type)
			}

			return r, nil
		},
	},
	{
		Name:      "convert.toRune",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]

			switch a.Type {
			case sim.String:
				s := a.String()
				if len(s) != 1 {
					return sim.NullValue, fmt.Errorf("can't convert %v to rune", s)
				}
				return sim.NewRune(rune(s[0])), nil
			case sim.Int:
				i := a.ToInt()
				if i > 255 {
					return sim.NullValue, fmt.Errorf("can't convert %v to rune", i)
				}
				return sim.NewRune(rune(i)), nil
			default:
				return sim.NullValue, fmt.Errorf("can't convert %v to byte", a.Type)
			}
		},
	},
	{
		Name:      "convert.toInt",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			var r sim.Value

			switch a.Type {
			case sim.Int:
				r = a
			case sim.Float:
				r = sim.NewInt64(a.ToInt())
			case sim.Rune:
				r = sim.NewInt64(a.ToInt())
			case sim.String:
				s := a.String()
				s = strings.Trim(s, " ")
				if len(s) > 1 {
					s = strings.TrimLeft(s, "0")
				}
				i, err := strconv.ParseInt(s, 0, 64)
				if err != nil {
					return sim.NullValue, err
				}
				r = sim.NewInt64(i)
			case sim.Func:
				r = sim.NewInt64(a.ToInt())
			default:
				return sim.NullValue, fmt.Errorf("can't convert %v to int", a.Type)
			}

			return r, nil
		},
	},
	{
		Name:      "convert.toFloat",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			switch a.Type {
			case sim.Int:
				return sim.NewFloat(a.ToFloat()), nil
			case sim.Float:
				return a, nil
			case sim.String:
				s := a.String()
				s = strings.Trim(s, " ")
				if len(s) > 1 {
					s = strings.TrimLeft(s, "0")
				}
				f, err := strconv.ParseFloat(s, 64)
				if err != nil {
					return sim.NullValue, err
				}
				return sim.NewFloat(f), nil
			default:
				return sim.NullValue, fmt.Errorf("can't convert %v to int", a.Type)
			}
		},
	},
	{
		Name:      "convert.toBool",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]

			switch a.Type {
			case sim.Bool:
				return a, nil

			case sim.Int:
				switch a.ToInt() {
				case 0:
					return sim.FalseValue, nil
				case 1:
					return sim.TrueValue, nil
				default:
					return sim.NullValue, fmt.Errorf("can't convert %v to bool", a.Type)
				}

			case sim.String:
				s := a.String()
				s = strings.Trim(s, " ")
				switch s {
				case "true", "1":
					return sim.TrueValue, nil
				case "false", "0":
					return sim.FalseValue, nil
				default:
					return sim.NullValue, fmt.Errorf("can't convert %v to bool", s)
				}

			case sim.Null, sim.Undefined:
				return sim.FalseValue, nil

			default:
				return sim.NullValue, fmt.Errorf("can't convert %v to bool", a.Type)

			}
		},
	},
	{
		Name:      "convert.toString",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			return sim.NewString(a.String()), nil
		},
	},
	{
		Name:      "convert.toBytes",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			var r sim.Value

			switch a.Type {
			case sim.String:
				r = sim.NewBytes(a.ToBytes())
			case sim.Bytes:
				r = a
			default:
				return sim.NullValue, fmt.Errorf("can't convert %v to int", a.Type)
			}

			return r, nil
		},
	},
	{
		Name:      "convert.toSafeString",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]

			switch a.Type {
			case sim.Bytes:
				encoder := base64.RawStdEncoding
				encoded := encoder.EncodeToString(a.ToBytes())
				return sim.NewString(encoded), nil

			case sim.Null, sim.Undefined:
				return sim.NewString(""), nil

			default:
				return sim.NewString(a.String()), nil
			}
		},
	},
}
View Source
var Crypt = []sim.NativeFunction{
	{
		Name:      "crypto.signSHA1_RSA_PCKS1",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			key := args[0].ToBytes()
			text := args[1].String()

			h := sha1.New()
			h.Write([]byte(text))
			sum := h.Sum(nil)

			block, _ := pem.Decode(key)
			if block == nil {
				return sim.NullValue, fmt.Errorf("error parsing private key")
			}

			privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
			if err != nil {
				return sim.NullValue, fmt.Errorf("error parsing private key: %w", err)
			}

			sig, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA1, sum)
			if err != nil {
				return sim.NullValue, fmt.Errorf("error signing: %w", err)
			}

			return sim.NewBytes(sig), nil
		},
	},
	{
		Name:      "crypto.signSHA1",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			s := args[0].String()
			h := sha1.New()
			h.Write([]byte(s))
			hash := hex.EncodeToString(h.Sum(nil))
			return sim.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.checkSignSHA1",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			s := args[0].String()
			h := sha1.New()
			h.Write([]byte(s))
			hash := hex.EncodeToString(h.Sum(nil))
			ok := hash == args[1].String()

			return sim.NewBool(ok), nil
		},
	},
	{
		Name:      "crypto.signSHA1Salted",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			s := args[0].String() + getGlobalPassword()
			h := sha1.New()
			h.Write([]byte(s))
			hash := hex.EncodeToString(h.Sum(nil))
			return sim.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.checkSignSHA1Salted",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			s := args[0].String() + getGlobalPassword()
			h := sha1.New()
			h.Write([]byte(s))
			hash := hex.EncodeToString(h.Sum(nil))
			ok := hash == args[1].String()

			return sim.NewBool(ok), nil
		},
	},
	{
		Name:        "crypto.signTempSHA1",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {

			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			s := args[0].String() + tempSignKey
			h := sha1.New()
			h.Write([]byte(s))
			hash := hex.EncodeToString(h.Sum(nil))
			return sim.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.checkTempSignSHA1",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			s := args[0].String() + tempSignKey
			h := sha1.New()
			h.Write([]byte(s))
			hash := hex.EncodeToString(h.Sum(nil))

			ok := hash == args[1].String()
			return sim.NewBool(ok), nil
		},
	},
	{
		Name:        "crypto.setGlobalPassword",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {

			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			setGlobalPassword(args[0].String())
			return sim.NullValue, nil
		},
	},
	{
		Name:      "crypto.hmacSHA256",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			msg := args[0].ToBytes()
			key := args[1].ToBytes()

			sig := hmac.New(sha256.New, key)
			sig.Write(msg)
			hash := sig.Sum(nil)

			return sim.NewBytes(hash), nil
		},
	},
	{
		Name:      "crypto.hmacSHA512",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			msg := args[0].ToBytes()
			key := args[1].ToBytes()

			sig := hmac.New(sha512.New, key)
			sig.Write(msg)
			hash := sig.Sum(nil)

			return sim.NewBytes(hash), nil
		},
	},
	{
		Name:      "crypto.hashSHA",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			h := sha1.New()
			h.Write([]byte(args[0].String()))
			hash := hex.EncodeToString(h.Sum(nil))
			return sim.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.hashSHA256",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			h := sha256.New()
			h.Write([]byte(args[0].String()))
			hash := hex.EncodeToString(h.Sum(nil))
			return sim.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.hashSHA512",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			h := sha512.New()
			h.Write([]byte(args[0].String()))
			hash := hex.EncodeToString(h.Sum(nil))
			return sim.NewString(hash), nil
		},
	},
	{
		Name:      "crypto.encryptString",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			var pwd string
			switch len(args) {
			case 0:
				return sim.NullValue, fmt.Errorf("expected 1 argument, got 0")
			case 1:
				pwd = getGlobalPassword()
				if pwd == "" {
					return sim.NullValue, fmt.Errorf("no password configured")
				}
			case 2:
				pwd = args[1].String()
			}

			s, err := Encrypts(args[0].String(), pwd)
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewString(s), nil
		},
	},
	{
		Name:      "crypto.decryptString",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			var pwd string
			switch len(args) {
			case 0:
				return sim.NullValue, fmt.Errorf("expected 1 argument, got 0")
			case 1:
				pwd = getGlobalPassword()
				if pwd == "" {
					return sim.NullValue, fmt.Errorf("no password configured")
				}
			case 2:
				pwd = args[1].String()
			}

			s, err := Decrypts(args[0].String(), pwd)
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewString(s), nil
		},
	},
	{
		Name:      "crypto.encrypt",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			var pwd string
			switch len(args) {
			case 0:
				return sim.NullValue, fmt.Errorf("expected 1 argument, got 0")
			case 1:
				pwd = getGlobalPassword()
				if pwd == "" {
					return sim.NullValue, fmt.Errorf("no password configured")
				}

			case 2:
				pwd = args[1].String()
			}

			b, err := Encrypt(args[0].ToBytes(), []byte(pwd))
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewBytes(b), nil
		},
	},
	{
		Name:      "crypto.decrypt",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			var pwd string
			switch len(args) {
			case 0:
				return sim.NullValue, fmt.Errorf("expected 1 argument, got 0")
			case 1:
				pwd = getGlobalPassword()
				if pwd == "" {
					return sim.NullValue, fmt.Errorf("no password configured")
				}

			case 2:
				pwd = args[1].String()
			}

			b, err := Decrypt(args[0].ToBytes(), []byte(pwd))
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewBytes(b), nil
		},
	},
	{
		Name:      "crypto.encryptTripleDES",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Bytes); err != nil {
				return sim.NullValue, err
			}
			b, err := EncryptTripleDESCBC(args[0].ToBytes(), args[1].ToBytes())
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewBytes(b), nil
		},
	},
	{
		Name:      "crypto.decryptTripleDES",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes, sim.Bytes); err != nil {
				return sim.NullValue, err
			}
			b, err := DecryptTripleDESCBC(args[0].ToBytes(), args[1].ToBytes())
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewBytes(b), nil
		},
	},
	{
		Name:      "crypto.hashPassword",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			s := HashPassword(args[0].String())
			return sim.NewString(s), nil
		},
	},
	{
		Name:      "crypto.compareHashAndPassword",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			ok := CheckHashPasword(args[0].String(), args[1].String())
			return sim.NewBool(ok), nil
		},
	},
	{
		Name:      "crypto.rand",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}
			ln := int(args[0].ToInt())
			v, err := rand.Int(rand.Reader, big.NewInt(int64(ln)))
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewInt64(v.Int64()), nil
		},
	},
	{
		Name:      "crypto.random",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			b := Random(int(args[0].ToInt()))
			return sim.NewBytes(b), nil
		},
	},
	{
		Name:      "crypto.randomAlphanumeric",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}
			ln := int(args[0].ToInt())
			if ln < 1 {
				return sim.NullValue, fmt.Errorf("invalid len: %d", ln)
			}
			s := RandomAlphanumeric(ln)
			return sim.NewString(s), nil
		},
	},
}
View Source
var Encoding = []sim.NativeFunction{
	{
		Name:      "encoding.newDecoderCP850",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d := charmap.CodePage850.NewDecoder()
			return sim.NewObject(&decoder{d}), nil
		},
	},
	{
		Name:      "encoding.newEncoderCP850",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d := charmap.CodePage850.NewEncoder()
			return sim.NewObject(&encoder{d}), nil
		},
	},
	{
		Name:      "encoding.newDecoderISO8859_1",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d := charmap.ISO8859_1.NewDecoder()
			return sim.NewObject(&decoder{d}), nil
		},
	},
	{
		Name:      "encoding.newEncoderISO8859_1",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d := charmap.ISO8859_1.NewEncoder()
			return sim.NewObject(&encoder{d}), nil
		},
	},
	{
		Name:      "encoding.newDecoderWindows1252",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d := charmap.Windows1252.NewDecoder()
			return sim.NewObject(&decoder{d}), nil
		},
	},
	{
		Name:      "encoding.newEncoderWindows1252",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d := charmap.Windows1252.NewEncoder()
			return sim.NewObject(&encoder{d}), nil
		},
	},
	{
		Name:      "encoding.newDecoderUTF16_LE",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder()
			return sim.NewObject(&decoder{d}), nil
		},
	},
	{
		Name:      "encoding.newEncoderUTF16_LE",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			e := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
			return sim.NewObject(&encoder{e}), nil
		},
	},
}
View Source
var ErrFileNotFound = errors.New("file not found")
View Source
var ErrInvalidType = errors.New("invalid value type")
View Source
var ErrNoFileSystem = errors.New("there is no filesystem")
View Source
var ErrReadOnly = errors.New("readonly property")
View Source
var ErrReadOnlyOrUndefined = errors.New("undefined or readonly property")
View Source
var ErrUnauthorized = errors.New("unauthorized")
View Source
var ErrUndefined = errors.New("undefined")
View Source
var Errors = []sim.NativeFunction{
	{
		Name:      "errors.action",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Map); err != nil {
				return sim.NullValue, err
			}

			var statusError int
			code, ok := args[0].ToMap().Map[sim.NewString("code")]
			if ok {
				if code.Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected code to be int, got %s", code.TypeName())
				}
				statusError = int(code.ToInt())
			} else {
				statusError = http.StatusBadRequest
			}

			wrap := make(map[sim.Value]sim.Value)
			wrap[sim.NewString("actionError")] = args[0]

			obj := sim.NewMapValues(wrap, false).ExportMarshal(0)

			buf := &bytes.Buffer{}

			encoder := json.NewEncoder(buf)

			if err := encoder.Encode(obj); err != nil {
				return sim.NullValue, err
			}

			buf.Truncate(buf.Len() - 1)

			err := sim.NewCodeError(statusError, buf.String())

			err.Kind = "ActionError"

			return sim.NewObject(err), nil
		},
	},
	{
		Name:      "errors.is",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object, sim.String); err != nil {
				return sim.NullValue, err
			}
			e, ok := args[0].ToObjectOrNil().(*sim.VMError)
			if !ok {
				return sim.FalseValue, nil
			}
			return sim.NewBool(e.Is(args[1].String())), nil
		},
	},
	{
		Name:      "errors.wrap",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}

			msg := args[0].String()

			e, ok := args[1].ToObjectOrNil().(error)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected arg 2 to be an error. Got %s", args[1].TypeName())
			}

			err := sim.Wrap(0, msg, e)

			return sim.NewObject(err), nil
		},
	},
	{
		Name:      "errors.wrapCode",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}

			code := args[0].ToInt()

			msg := args[1].String()

			e, ok := args[2].ToObjectOrNil().(error)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected arg 2 to be an error. Got %s", args[2].TypeName())
			}

			err := sim.Wrap(int(code), msg, e)

			return sim.NewObject(err), nil
		},
	},
	{
		Name:      "errors.unwrap",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			e, ok := args[0].ToObjectOrNil().(*sim.VMError)
			if !ok {
				return sim.FalseValue, nil
			}

			e = e.Wrapped

			if e == nil {
				return sim.NullValue, nil
			}

			return sim.NewObject(e), nil
		},
	},
	{
		Name:      "errors.rethrow",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			ln := len(args)

			if ln == 0 {
				return sim.NullValue, fmt.Errorf("expected at least one argument, got 0")
			}

			e, ok := args[0].ToObjectOrNil().(*sim.VMError)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected error, got %s", args[0].String())
			}

			if ln > 1 {
				a := args[1]
				if a.Type != sim.String {
					return sim.NullValue, fmt.Errorf("expected parameter 1 to be a string, got %s", a.Type)
				}
				details := a.String()
				if ln > 2 {
					values := make([]interface{}, ln-2)
					for i, a := range args[2:] {
						v := a.Export(0)
						if t, ok := v.(*sim.VMError); ok {

							v = t.ErrorMessage()
						}
						values[i] = v
					}
					details = fmt.Sprintf(details, values...)
				}

				if e.Details == "" {
					e.Details = details
				} else {
					e.Details += "\n" + details
				}
			}

			e.IsRethrow = true

			return sim.NullValue, e
		},
	},
	{
		Name:      "errors.newError",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			argsLen := len(args)
			if argsLen < 1 {
				return sim.NullValue, fmt.Errorf("expected at least 1 parameter, got %d", len(args))
			}

			m := args[0]
			if m.Type != sim.String {
				return sim.NullValue, fmt.Errorf("expected parameter 1 to be a string, got %s", m.Type)
			}

			return newCodeError(0, m.String(), args[1:], vm)
		},
	},
	{
		Name:      "errors.newCode",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			argsLen := len(args)
			if argsLen < 1 {
				return sim.NullValue, fmt.Errorf("expected at least 1 parameter, got %d", len(args))
			}

			code := args[0]
			if code.Type != sim.Int {
				return sim.NullValue, fmt.Errorf("expected parameter 1 to be a int, got %s", code.Type)
			}

			var msg string
			var fmtArgs []sim.Value

			if argsLen > 1 {
				m := args[1]
				if m.Type != sim.String {
					return sim.NullValue, fmt.Errorf("expected parameter 2 to be a string, got %s", m.Type)
				}
				msg = m.ToString()
				fmtArgs = args[2:]
			} else {
				msg = fmt.Sprintf("Error %d", code.ToInt())
				fmtArgs = args[1:]
			}

			return codeErrorf(int(code.ToInt()), msg, fmtArgs, vm)
		},
	},
	{
		Name:      "errors.notFound",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return newHTTPCodeError(404, args, vm)
		},
	},
	{
		Name:      "errors.badRequest",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return newHTTPCodeError(400, args, vm)
		},
	},
	{
		Name:      "errors.unauthorized",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return newHTTPCodeError(401, args, vm)
		},
	},
	{
		Name:      "errors.internalError",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return newHTTPCodeError(500, args, vm)
		},
	},
}
View Source
var FSNotify = []sim.NativeFunction{
	{
		Name:        "fsnotify.newWatcher",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]
			switch v.Type {
			case sim.Func:
			case sim.Object:
			default:
				return sim.NullValue, fmt.Errorf("%v is not a function", v.TypeName())
			}

			w, err := newFileWatcher(v, vm)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(w), nil
		},
	},
}
View Source
var FilePath = []sim.NativeFunction{
	{
		Name:      "filepath.clean",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			s := args[0].String()
			if s == "" {
				return args[0], nil
			}

			if s[0] != '/' {
				return sim.NullValue, fmt.Errorf("relative paths are not allowed")
			}

			v := filepath.Clean(s)
			return sim.NewString(v), nil
		},
	},
	{
		Name:      "filepath.join",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var parts []string

			for i, v := range args {
				if v.IsNilOrEmpty() {
					continue
				}
				if v.Type != sim.String {
					return sim.NullValue, fmt.Errorf("argument %d is not a string (%s)", i+1, v.TypeName())
				}
				parts = append(parts, v.String())
			}

			path := filepath.Join(parts...)
			return sim.NewString(path), nil
		},
	},
	{
		Name:      "filepath.joinAbs",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var parts []string

			for i, v := range args {
				if v.IsNilOrEmpty() {
					continue
				}
				if v.Type != sim.String {
					return sim.NullValue, fmt.Errorf("argument %d is not a string (%s)", i, v.TypeName())
				}
				s := v.String()
				if strings.HasPrefix(s, "/") {
					parts = nil
				}

				parts = append(parts, s)
			}

			path := filepath.Join(parts...)
			return sim.NewString(path), nil
		},
	},
	{
		Name:      "filepath.abs",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}

			path, err := fs.Abs(args[0].String())
			if err != nil {
				return sim.NullValue, fmt.Errorf("abs %s: %w", args[0].String(), err)
			}

			return sim.NewString(path), nil
		},
	},
	{
		Name:      "filepath.ext",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			path := args[0].String()
			ext := filepath.Ext(path)
			return sim.NewString(ext), nil
		},
	},
	{
		Name:      "filepath.base",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			path := args[0].String()
			name := filepath.Base(path)
			return sim.NewString(name), nil
		},
	},
	{
		Name:      "filepath.baseWithoutExt",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			path := args[0].String()
			name := filepath.Base(path)
			if i := strings.LastIndexByte(name, '.'); i != -1 {
				name = name[:i]
			}
			return sim.NewString(name), nil
		},
	},
	{
		Name:      "filepath.replaceExt",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			path := args[0].String()

			i := strings.LastIndexByte(path, '.')

			if i != -1 {
				path = path[:i] + args[1].String()
			} else {
				path += args[1].String()
			}

			return sim.NewString(path), nil
		},
	},
	{
		Name:      "filepath.dir",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			path := args[0].String()
			name := filepath.Dir(path)
			return sim.NewString(name), nil
		},
	},
}
View Source
var FileUtil = []sim.NativeFunction{
	{
		Name:      "fileutil.isDirEmpty",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}
			if err := ValidateArgRange(args, 1, 2); err != nil {
				return sim.NullValue, err
			}

			fs, ok := args[1].ToObject().(*FileSystemObj)
			if !ok {
				return sim.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[1])
			}

			name := args[0].String()

			f, err := fs.FS.Open(name)
			if err != nil {
				return sim.NullValue, err
			}
			defer f.Close()

			_, err = f.Readdir(1)
			if err != nil {
				if err == io.EOF {
					return sim.NewBool(true), nil
				}
				return sim.NullValue, err
			}

			return sim.NewBool(false), nil
		},
	},
	{
		Name:      "fileutil.copyFile",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return sim.NullValue, err
			}

			src := args[0].String()
			dst := args[1].String()

			var fs filesystem.FS

			if len(args) == 3 {
				ofs, ok := args[2].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return sim.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[2])
				}
				fs = ofs.FS
			}

			if fs == nil {
				fs = vm.FileSystem
				if fs == nil {
					return sim.NullValue, fmt.Errorf("no filesystem")
				}
			}

			r, err := fs.Open(src)
			if err != nil {
				return sim.NullValue, err
			}

			defer r.Close()

			w, err := fs.OpenForWrite(dst)
			if err != nil {
				return sim.NullValue, err
			}

			defer w.Close()

			if _, err := io.Copy(w, r); err != nil {
				return sim.NullValue, err
			}

			return sim.NullValue, nil
		},
	},
}
View Source
var GZIP = []sim.NativeFunction{
	{
		Name:      "gzip.newWriter",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			w, ok := args[0].ToObjectOrNil().(io.Writer)
			if !ok {
				return sim.NullValue, fmt.Errorf("exepected a Writer, got %s", args[0].TypeName())
			}

			g := gzip.NewWriter(w)
			v := &gzipWriter{g}
			return sim.NewObject(v), nil
		},
	},
	{
		Name:      "gzip.newReader",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			r, ok := args[0].ToObjectOrNil().(io.Reader)
			if !ok {
				return sim.NullValue, fmt.Errorf("exepected a reader, got %s", args[0].TypeName())
			}

			gr, err := gzip.NewReader(r)
			if err != nil {
				return sim.NullValue, err
			}
			v := &gzipReader{gr}
			return sim.NewObject(v), nil
		},
	},
}
View Source
var HASH = []sim.NativeFunction{
	{
		Name: "hash.newMD5",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			hash := md5.New()
			return sim.NewObject(hasher{hash}), nil
		},
	},
	{
		Name: "hash.newSHA256",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			hash := sha256.New()
			return sim.NewObject(hasher{hash}), nil
		},
	},
}
View Source
var HEX = []sim.NativeFunction{
	{
		Name:      "hex.encodeToString",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()
			s := hex.EncodeToString(b)
			return sim.NewString(s), nil
		},
	},
}
View Source
var HTML = []sim.NativeFunction{
	{
		Name:      "html.encode",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			switch a.Type {
			case sim.Null, sim.Undefined:
				return sim.NullValue, nil
			case sim.Bytes:
				encoder := base64.RawStdEncoding
				encoded := encoder.EncodeToString(a.ToBytes())
				return sim.NewString(encoded), nil
			case sim.String:
				return sim.NewString(html.EscapeString(a.String())), nil
			default:
				return sim.NewString(a.String()), nil
			}
		},
	},
	{
		Name:      "html.decode",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			switch a.Type {
			case sim.Null, sim.Undefined:
				return sim.NullValue, nil
			case sim.String:
				return sim.NewString(html.UnescapeString(a.String())), nil
			default:
				return sim.NullValue, fmt.Errorf("expected string, got %v", a.Type)
			}
		},
	},
}
View Source
var HTTP = []sim.NativeFunction{
	{
		Name: "->http.OK",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(200), nil
		},
	},
	{
		Name: "->http.REDIRECT",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(302), nil
		},
	},
	{
		Name: "->http.PERMANENT_REDIRECT",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(301), nil
		},
	},
	{
		Name: "->http.REDIRECT",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(302), nil
		},
	},
	{
		Name: "->http.BAD_REQUEST",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(400), nil
		},
	},
	{
		Name: "->http.UNAUTHORIZED",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(401), nil
		},
	},
	{
		Name: "->http.NOT_FOUND",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(404), nil
		},
	},
	{
		Name: "->http.TIMEOUT",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(408), nil
		},
	},
	{
		Name: "->http.INTERNAL_ERROR",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(500), nil
		},
	},
	{
		Name: "->http.UNAVAILABLE",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(503), nil
		},
	},
	{
		Name: "->http.FORM_ERROR",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(http.StatusBadRequest), nil
		},
	},
	{
		Name: "->http.SameSiteDefaultMode",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(http.SameSiteDefaultMode)), nil
		},
	},
	{
		Name: "->http.SameSiteDefaultMode",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(http.SameSiteDefaultMode)), nil
		},
	},

	{
		Name: "->http.SameSiteLaxMode",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(http.SameSiteLaxMode)), nil
		},
	},
	{
		Name: "->http.SameSiteStrictMode",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(http.SameSiteStrictMode)), nil
		},
	},
	{
		Name: "->http.SameSiteNoneMode",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(http.SameSiteNoneMode)), nil
		},
	},
	{
		Name:      "http.cacheBreaker",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			cacheMut.RLock()
			v := sim.NewString(cacheBreaker)
			cacheMut.RUnlock()
			return v, nil
		},
	},
	{
		Name:        "http.resetCacheBreaker",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			cacheMut.Lock()
			cacheBreaker = RandString(9)
			lastModifiedDate = time.Now()
			cacheMut.Unlock()
			return sim.NullValue, nil
		},
	},
	{
		Name:        "http.newServer",
		Arguments:   0,
		Permissions: []string{"netListen"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := &server{
				vm:                vm,
				handler:           -1,
				readTimeout:       10 * time.Second,
				writeTimeout:      10 * time.Second,
				readHeaderTimeout: 10 * time.Second,
				idleTimeout:       100 * time.Second,
			}

			return sim.NewObject(s), nil
		},
	},
	{
		Name:      "http.newResponseRecorder",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			r, ok := args[0].ToObjectOrNil().(*request)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected a request, got %v", args[0].TypeName())
			}

			w := &responseWriter{
				writer:  httptest.NewRecorder(),
				request: r.request,
			}

			return sim.NewObject(w), nil
		},
	},
	{
		Name:      "http.newCookie",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			c := &cookie{}
			return sim.NewObject(c), nil
		},
	},
	{
		Name:      "http.encodeURIComponent",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			v := args[0].String()
			u := url.QueryEscape(v)
			return sim.NewString(u), nil
		},
	},
	{
		Name:      "http.decodeURIComponent",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			v := args[0].String()
			u, err := url.QueryUnescape(v)
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewString(u), nil
		},
	},
	{
		Name:      "http.newClient",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			c := &client{client: &http.Client{}}
			return sim.NewObject(c), nil
		},
	},
	{
		Name:        "http.newRequest",
		Arguments:   -1,
		Permissions: []string{"networking"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return sim.NullValue, err
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected argument 1 to be string, got %v", args[0].Type)
			}

			if !isStringLike(args[1]) {
				return sim.NullValue, fmt.Errorf("expected argument 2 to be string, got %v", args[1].Type)
			}

			var method string
			var urlStr string
			var queryMap map[sim.Value]sim.Value
			var reader io.Reader
			var contentType string

			switch len(args) {
			case 2:
				method = args[0].String()
				urlStr = args[1].String()
			case 3:
				method = args[0].String()
				urlStr = args[1].String()
				form := url.Values{}

				v := args[2]

				switch v.Type {
				case sim.Null, sim.Undefined:
				case sim.String:
					switch method {
					case "POST", "PUT", "PATCH":
					default:
						return sim.NullValue, fmt.Errorf("can only pass a data string with POST, PUT or PATCH")
					}
					reader = strings.NewReader(v.String())
					contentType = "application/json; charset=UTF-8"
				case sim.Map:
					m := v.ToMap()
					if method == "GET" {
						queryMap = m.Map
					} else {
						m.RLock()
						for k, v := range m.Map {
							if v.IsNilOrEmpty() {
								continue
							}
							vs, err := serialize(v)
							if err != nil {
								return sim.NullValue, fmt.Errorf("error serializing parameter: %v", v.Type)
							}
							form.Add(k.String(), vs)
						}
						m.RUnlock()
						reader = strings.NewReader(form.Encode())
						contentType = "application/x-www-form-urlencoded"
					}
				case sim.Object:
					r, ok := v.ToObject().(io.Reader)
					if !ok {
						return sim.NullValue, fmt.Errorf("invalid argument 3 type: got %v", v.TypeName())
					}
					reader = r
				default:
					return sim.NullValue, fmt.Errorf("expected argument 3 to be object, got %v", v.Type)
				}
			}

			r, err := http.NewRequest(method, urlStr, reader)
			if err != nil {
				return sim.NullValue, err
			}

			switch method {
			case "GET":
				if queryMap != nil {
					q := r.URL.Query()
					for k, v := range queryMap {
						if v.IsNilOrEmpty() {
							continue
						}
						vs, err := serialize(v)
						if err != nil {
							return sim.NullValue, fmt.Errorf("error serializing parameter: %v", v.Type)
						}
						q.Add(k.String(), vs)
					}
					r.URL.RawQuery = q.Encode()
				}
			}

			return sim.NewObject(&request{request: r, defaultContentType: contentType}), nil
		},
	},
	{
		Name:        "http.get",
		Arguments:   -1,
		Permissions: []string{"networking"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			client := &http.Client{}
			timeout := 20 * time.Second

			ln := len(args)

			if ln == 0 {
				return sim.NullValue, fmt.Errorf("expected 1 to 3 arguments, got %d", len(args))
			}

			a := args[0]
			if a.Type != sim.String {
				return sim.NullValue, fmt.Errorf("expected argument 0 to be string, got %s", a.TypeName())
			}
			url := a.String()

			if ln == 0 {
			} else if ln > 1 {
				a := args[1]
				switch a.Type {
				case sim.Undefined, sim.Null:
				case sim.Int, sim.Object:
					var err error
					timeout, err = ToDuration(args[1])
					if err != nil {
						return sim.NullValue, err
					}
				default:
					return sim.NullValue, fmt.Errorf("expected argument 1 to be duration")
				}
			}

			if ln > 2 {
				b := args[2]
				switch b.Type {
				case sim.Null, sim.Undefined:
				case sim.Object:
					t, ok := args[2].ToObjectOrNil().(*tlsConfig)
					if !ok {
						return sim.NullValue, fmt.Errorf("expected argument 2 to be tls.Config")
					}
					client.Transport = getTransport(t.conf)
				default:
					return sim.NullValue, fmt.Errorf("expected argument 2 to be string, got %s", b.TypeName())
				}
			}

			client.Timeout = timeout
			resp, err := client.Get(url)
			if err != nil {
				return sim.NullValue, err
			}

			b, err := io.ReadAll(resp.Body)

			err2 := resp.Body.Close()

			if err != nil {
				return sim.NullValue, err
			}

			if err2 != nil {
				return sim.NullValue, err2
			}

			if !isHTTPSuccess(resp.StatusCode) {
				return sim.NullValue, fmt.Errorf("http Error %d: %v", resp.StatusCode, string(b))
			}

			return sim.NewString(string(b)), nil
		},
	},
	{
		Name:        "http.post",
		Arguments:   -1,
		Permissions: []string{"networking"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 1, 2, 3, 4); err != nil {
				return sim.NullValue, err
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected argument 0 to be string, got %s", args[0].TypeName())
			}

			u := args[0].String()

			data := url.Values{}

			ln := len(args)

			if ln > 1 {
				a := args[1]
				switch a.Type {
				case sim.Undefined, sim.Null:
				case sim.Map:
					m := args[1].ToMap()
					m.RLock()
					for k, v := range m.Map {
						data.Add(k.String(), v.String())
					}
					m.RUnlock()
				default:
					return sim.NullValue, fmt.Errorf("expected argument 1 to be an object, got %s", args[1].TypeName())
				}
			}

			client := &http.Client{}
			timeout := 20 * time.Second

			if ln > 2 {
				a := args[2]
				switch a.Type {
				case sim.Undefined, sim.Null:
				case sim.Int, sim.Object:
					var err error
					timeout, err = ToDuration(args[2])
					if err != nil {
						return sim.NullValue, err
					}
				default:
					return sim.NullValue, fmt.Errorf("expected argument 1 to be duration")
				}
			}

			if ln > 3 {
				b := args[3]
				switch b.Type {
				case sim.Null, sim.Undefined:
				case sim.Object:
					t, ok := args[3].ToObjectOrNil().(*tlsConfig)
					if !ok {
						return sim.NullValue, fmt.Errorf("expected argument 2 to be tls.Config")
					}
					client.Transport = getTransport(t.conf)
				default:
					return sim.NullValue, fmt.Errorf("expected argument 2 to be string, got %s", b.TypeName())
				}
			}

			client.Timeout = timeout

			resp, err := client.PostForm(u, data)
			if err != nil {
				return sim.NullValue, err
			}

			b, err := io.ReadAll(resp.Body)
			resp.Body.Close()
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewString(string(b)), nil
		},
	},
	{
		Name:      "http.sendFile",
		Arguments: 6,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String, sim.String, sim.String, sim.String, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			url := args[0].String()
			user := args[1].String()
			password := args[2].String()
			param := args[3].String()
			name := args[4].String()
			data := args[5].ToBytes()

			body := &bytes.Buffer{}
			w := multipart.NewWriter(body)

			part, err := w.CreateFormFile(param, filepath.Base(name))
			if err != nil {
				return sim.NullValue, err
			}

			if _, err := part.Write(data); err != nil {
				return sim.NullValue, err
			}

			w.Close()

			r, err := http.NewRequest("POST", url, body)
			if err != nil {
				return sim.NullValue, err
			}

			r.SetBasicAuth(user, password)

			r.Header.Add("Content-Type", w.FormDataContentType())

			client := &http.Client{}
			res, err := client.Do(r)
			if err != nil {
				return sim.NullValue, err
			}

			defer res.Body.Close()

			resBuf, err := io.ReadAll(res.Body)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewBytes(resBuf), nil
		},
	},
	{
		Name:        "http.getJSON",
		Arguments:   1,
		Permissions: []string{"networking"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			url := args[0].String()

			resp, err := http.Get(url)
			if err != nil {
				return sim.NullValue, err
			}

			b, err := io.ReadAll(resp.Body)
			resp.Body.Close()
			if err != nil {
				return sim.NullValue, err
			}

			v, err := unmarshal(b)
			if err != nil {
				return sim.NullValue, err
			}

			return v, nil
		},
	},
	{
		Name:      "http.parseURL",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			if len(args) == 0 {
				u := &url.URL{}
				return sim.NewObject(&URL{url: u}), nil
			}

			rawURL := args[0].String()
			u, err := url.Parse(rawURL)
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewObject(&URL{u}), nil
		},
	},

	{
		Name:      "http.escapeQuery",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			str := url.QueryEscape(args[0].String())
			return sim.NewString(str), nil
		},
	},
	{
		Name:      "http.unescapeQuery",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			str, err := url.QueryUnescape(args[0].String())
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewString(str), nil
		},
	},
}
View Source
var HTTPUTIL = []sim.NativeFunction{
	{
		Name:      "httputil.newSingleHostReverseProxy",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			u, ok := a.ToObjectOrNil().(*URL)
			if !ok {
				return sim.NullValue, fmt.Errorf("invalid argument 1: expected http.URL, got %v", a.TypeName())
			}

			p := &reverseProxy{
				proxy: httputil.NewSingleHostReverseProxy(u.url),
			}

			return sim.NewObject(p), nil
		},
	},
}
View Source
var I18N = []sim.NativeFunction{
	{
		Name:      "T",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]

			switch a.Type {
			case sim.Null, sim.Undefined:
				return sim.NewString(""), nil
			case sim.Int, sim.Float, sim.Bool:
				return sim.NewString(a.ToString()), nil
			case sim.String:
			default:
				return sim.NullValue, fmt.Errorf("expected string as fist argument, got %s", a.TypeName())
			}

			text := a.ToString()

			if text == "" {
				return a, nil
			}

			lang := vm.Language

			value := text
			if vm.Translations != nil {
				value = vm.Translations.Translate(lang, text)
			} else {

				cleanText := text
				if strings.HasPrefix(text, "::") {
					cleanText = text[2:]
				}
				value = cleanText

				if i := strings.Index(value, "::"); i != -1 {
					value = value[i+2:]
				}
			}

			if len(args) > 1 {
				params := make([]interface{}, len(args)-1)
				for i, v := range args[1:] {
					params[i] = v.Export(0)
				}
				value = fmt.Sprintf(value, params...)
			}

			return sim.NewString(value), nil
		},
	},
	{
		Name:      "i18n.createStore",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			store := sim.NewTranslationStore()
			wrapper := &translationStoreWrapper{store}
			return sim.NewObject(wrapper), nil
		},
	},
	{
		Name:      "i18n.setCurrentStore",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if args[0].Type == sim.Null || args[0].Type == sim.Undefined {
				vm.Translations = nil
				return sim.NullValue, nil
			}

			if args[0].Type == sim.Object {
				if wrapper, ok := args[0].ToObjectOrNil().(*translationStoreWrapper); ok {
					vm.Translations = wrapper.store
					return sim.NullValue, nil
				}
			}

			return sim.NullValue, fmt.Errorf("expected TranslationStore or null, got %s", args[0].TypeName())
		},
	},
	{
		Name:      "i18n.getCurrentStore",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Translations == nil {
				return sim.NullValue, nil
			}

			wrapper := &translationStoreWrapper{vm.Translations}
			return sim.NewObject(wrapper), nil
		},
	},
	{
		Name:      "i18n.set",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Translations == nil {
				vm.Translations = sim.NewTranslationStore()
			}

			wrapper := &translationStoreWrapper{vm.Translations}
			return wrapper.set(args, vm)
		},
	},
	{
		Name:      "i18n.setBatch",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Translations == nil {
				vm.Translations = sim.NewTranslationStore()
			}

			wrapper := &translationStoreWrapper{vm.Translations}
			return wrapper.setBatch(args, vm)
		},
	},
	{
		Name:      "i18n.get",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Translations == nil {
				return sim.NewString(""), nil
			}

			wrapper := &translationStoreWrapper{vm.Translations}
			return wrapper.get(args, vm)
		},
	},
	{
		Name:      "i18n.clear",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Translations == nil {
				return sim.NullValue, nil
			}

			wrapper := &translationStoreWrapper{vm.Translations}
			return wrapper.clear(args, vm)
		},
	},
	{
		Name:      "i18n.languages",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Translations == nil {
				return sim.NewArrayValues([]sim.Value{}), nil
			}

			wrapper := &translationStoreWrapper{vm.Translations}
			return wrapper.languages(args, vm)
		},
	},
	{
		Name:      "i18n.hasLanguage",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Translations == nil {
				return sim.FalseValue, nil
			}

			wrapper := &translationStoreWrapper{vm.Translations}
			return wrapper.hasLanguage(args, vm)
		},
	},
	{
		Name:      "i18n.getLanguageData",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Translations == nil {
				return sim.NullValue, nil
			}

			wrapper := &translationStoreWrapper{vm.Translations}
			return wrapper.getLanguageData(args, vm)
		},
	},
}
View Source
var IO = []sim.NativeFunction{
	{
		Name:      "io.readAll",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			r := args[0].ToObject()

			reader, ok := r.(io.Reader)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected a io.Reader, got %v", args[0])
			}

			b, err := ReadAll(reader, vm)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewBytes(b), nil
		},
	},
	{
		Name:      "io.newBuffer",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewObject(NewBuffer()), nil
		},
	},
	{
		Name:      "io.copy",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object, sim.Object); err != nil {
				return sim.NullValue, err
			}

			dst, ok := args[0].ToObject().(io.Writer)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}

			src, ok := args[1].ToObject().(io.Reader)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}

			i, err := io.Copy(dst, src)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewInt64(i), nil
		},
	},
	{
		Name:      "io.newRootedFS",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}
			fs, ok := args[1].ToObject().(*FileSystemObj)
			if !ok {
				return sim.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[1])
			}
			root := args[0].String()
			rFS, err := filesystem.NewRootedFS(root, fs.FS)
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewObject(NewFileSystem(rFS)), nil
		},
	},
	{
		Name:      "io.newRestrictedFS",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			fs, ok := args[0].ToObject().(*FileSystemObj)
			if !ok {
				return sim.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[1])
			}

			rFS, err := filesystem.NewRestrictedFS(fs.FS)
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewObject(NewFileSystem(rFS)), nil
		},
	},
	{
		Name: "io.newVirtualFS",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args); err != nil {
				return sim.NullValue, err
			}

			fs := filesystem.NewVirtualFS()
			return sim.NewObject(NewFileSystem(fs)), nil
		},
	},
	{
		Name:      "io.newReadOnlyFS",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			fs, ok := args[0].ToObject().(*FileSystemObj)
			if !ok {
				return sim.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[1])
			}

			rfs := filesystem.NewReadOnlyFS(fs.FS)
			return sim.NewObject(NewFileSystem(rfs)), nil
		},
	},
}
View Source
var Image = []sim.NativeFunction{
	{
		Name:      "image.config",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 1); err != nil {
				return sim.NullValue, err
			}

			a := args[0]
			var r io.Reader

			switch a.Type {
			case sim.Object:
				var ok bool
				r, ok = a.ToObject().(io.Reader)
				if !ok {
					return sim.NullValue, ErrInvalidType
				}
			case sim.Bytes:
				r = bytes.NewBuffer(a.ToBytes())
			}

			conf, format, err := image.DecodeConfig(r)
			if err != nil {
				return sim.NullValue, err
			}

			obj := imageConfig{
				config: conf,
				format: format,
			}

			return sim.NewObject(obj), nil
		},
	},
	{
		Name:      "image.decode",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 1); err != nil {
				return sim.NullValue, err
			}

			a := args[0]
			var r io.Reader

			switch a.Type {
			case sim.Object:
				var ok bool
				r, ok = a.ToObject().(io.Reader)
				if !ok {
					return sim.NullValue, ErrInvalidType
				}
			case sim.Bytes:
				r = bytes.NewBuffer(a.ToBytes())
			}

			img, format, err := image.Decode(r)
			if err != nil {
				return sim.NullValue, err
			}

			obj := imageObj{
				img:    img,
				format: format,
			}

			return sim.NewObject(obj), nil
		},
	},
}
View Source
var JSON = []sim.NativeFunction{
	{
		Name:      "json.marshal",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			ln := len(args)
			if ln == 0 || ln > 3 {
				return sim.NullValue, fmt.Errorf("expected 1, 2 or 3 arguments, got %d", len(args))
			}

			var indent bool
			var escapeHTML bool

			if ln > 1 {
				v := args[1]
				if v.Type != sim.Bool {
					return sim.NullValue, fmt.Errorf("expected arg 2 to be boolean, got %s", v.TypeName())
				}
				indent = v.ToBool()
			}

			if ln > 2 {
				v := args[2]
				if v.Type != sim.Bool {
					return sim.NullValue, fmt.Errorf("expected arg 3 to be boolean, got %s", v.TypeName())
				}
				escapeHTML = v.ToBool()
			}

			obj := args[0].ExportMarshal(0)

			buf := &bytes.Buffer{}

			encoder := json.NewEncoder(buf)

			if indent {
				encoder.SetIndent("", "    ")
			}

			encoder.SetEscapeHTML(escapeHTML)

			if err := encoder.Encode(obj); err != nil {
				return sim.NullValue, err
			}

			buf.Truncate(buf.Len() - 1)

			return sim.NewString(buf.String()), nil
		},
	},
	{
		Name:      "json.unmarshal",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 1 {
				return sim.NullValue, fmt.Errorf("expected 1 argument, got %d", len(args))
			}

			a := args[0]

			switch a.Type {
			case sim.String, sim.Bytes:
			default:
				return sim.NullValue, fmt.Errorf("expected argument to be string or byte[], got %v", args[0].Type)
			}

			if a.String() == "" {
				return sim.NullValue, nil
			}

			v, err := unmarshal(a.ToBytes())
			if err != nil {
				return sim.NullValue, err
			}

			return v, nil
		},
	},
}
View Source
var JSRegex = []sim.NativeFunction{
	{
		Name:      "jsregex.match",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			result := jsregex.Match(args[0].String(), args[1].String())
			if result == nil {
				return sim.NullValue, nil
			}

			values := make([]sim.Value, len(result))
			for i, s := range result {
				values[i] = sim.NewString(s)
			}
			return sim.NewArrayValues(values), nil
		},
	},
	{
		Name:      "jsregex.matchAll",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			result := jsregex.MatchAll(args[0].String(), args[1].String())
			if result == nil {
				return sim.NullValue, nil
			}

			values := make([]sim.Value, len(result))
			for i, match := range result {
				matchValues := make([]sim.Value, len(match))
				for j, s := range match {
					matchValues[j] = sim.NewString(s)
				}
				values[i] = sim.NewArrayValues(matchValues)
			}
			return sim.NewArrayValues(values), nil
		},
	},
	{
		Name:      "jsregex.replace",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			result := jsregex.Replace(args[0].String(), args[1].String(), args[2].String())
			return sim.NewString(result), nil
		},
	},
	{
		Name:      "jsregex.replaceAll",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			result := jsregex.ReplaceAll(args[0].String(), args[1].String(), args[2].String())
			return sim.NewString(result), nil
		},
	},
	{
		Name:      "jsregex.search",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			result := jsregex.Search(args[0].String(), args[1].String())
			return sim.NewInt(result), nil
		},
	},
	{
		Name:      "jsregex.split",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return sim.NullValue, err
			}
			if err := ValidateOptionalArgs(args, sim.String, sim.String, sim.Int); err != nil {
				return sim.NullValue, err
			}

			var result []string
			if len(args) == 3 {
				limit := int(args[2].ToInt())
				result = jsregex.Split(args[0].String(), args[1].String(), limit)
			} else {
				result = jsregex.Split(args[0].String(), args[1].String())
			}

			values := make([]sim.Value, len(result))
			for i, s := range result {
				values[i] = sim.NewString(s)
			}
			return sim.NewArrayValues(values), nil
		},
	},
	{
		Name:      "jsregex.newRegExp",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			re, err := jsregex.NewJSRegExp(args[0].String())
			if err != nil {
				return sim.NullValue, err
			}

			wrapper := &jsRegExpWrapper{re: re}
			return sim.NewObject(wrapper), nil
		},
	},
	{
		Name:      "jsregex.newJSString",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			wrapper := &jsStringWrapper{text: jsregex.JSString(args[0].String())}
			return sim.NewObject(wrapper), nil
		},
	},
}
View Source
var JWT = []sim.NativeFunction{
	{
		Name:      "jwt.verify",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}

			tokenString := args[0].String()

			publicKey, ok := args[1].ToObjectOrNil().(*rsaPublicKey)
			if !ok {
				return sim.NullValue, errors.New("invalid public key")
			}

			token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
				if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
					return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
				}
				return publicKey.key, nil
			})

			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewBool(token.Valid), nil
		},
	},
	{
		Name:      "jwt.newWithClaims",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.Map); err != nil {
				return sim.NullValue, err
			}

			var signMethod jwt.SigningMethod

			switch args[0].String() {
			case "HS256":
				signMethod = jwt.SigningMethodHS256
			case "RS256":
				signMethod = jwt.SigningMethodRS256
			default:
				return sim.NullValue, fmt.Errorf("invalid signing method, got %s", args[0].String())
			}

			m := args[1].ToMap().Map

			claims := jwt.MapClaims{}

			for k, v := range m {
				claims[k.String()] = v.Export(0)
			}

			token := jwt.NewWithClaims(signMethod, claims)

			return sim.NewObject(&jwtToken{token: token}), nil
		},
	},
}
View Source
var Locale = []sim.NativeFunction{
	{
		Name:      "->locale.currentLocalizer",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			loc := vm.Localizer
			if loc == nil {
				loc = defaultLocalizer
			}
			c := sim.NewObject(loc)
			return c, nil
		},
	},
	{
		Name:      "->locale.currentLanguage",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := sim.NewString(vm.Language)
			return s, nil
		},
	},
	{
		Name:      "->locale.defaultLocalizer",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			c := sim.NewObject(defaultLocalizer)
			return c, nil
		},
	},
	{
		Name:        "locale.setDefaultLocalizer",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			loc, ok := args[0].ToObjectOrNil().(*localizer)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}
			defaultLocalizer = loc
			return sim.NullValue, nil
		},
	},
	{
		Name:        "locale.setCurrentLocalizer",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			loc, ok := args[0].ToObjectOrNil().(*localizer)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}
			vm.Localizer = loc
			return sim.NullValue, nil
		},
	},
	{
		Name:      "locale.setCurrentLanguage",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			vm.Language = args[0].String()
			return sim.NullValue, nil
		},
	},
	{
		Name:      "locale.newCulture",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			name := args[0].String()
			c := sim.NewObject(&culture{culture: locale.NewCulture(name)})
			return c, nil
		},
	},
	{
		Name:      "locale.newLocalizer",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			lt := sim.NewObject(&localizer{})
			return lt, nil
		},
	},
	{
		Name:      "locale.parseNumber",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]

			switch a.Type {
			case sim.Int, sim.Float:
				return a, nil
			case sim.String:
			default:
				return sim.NullValue, fmt.Errorf("expected string, got %d", a.Type)
			}

			loc := vm.Localizer
			if loc == nil {
				loc = defaultLocalizer
			}

			v, err := loc.ParseNumber(a.String())
			if err != nil {
				return sim.NullValue, err
			}

			if v == float64(int64(v)) {
				return sim.NewInt(int(v)), nil
			}
			return sim.NewFloat(v), nil
		},
	},
	{
		Name:      "locale.parseDate",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 1, 2); err != nil {
				return sim.NullValue, err
			}

			switch args[0].Type {
			case sim.String:
				break
			case sim.Int:
				return sim.NewObject(TimeObj(time.Unix(args[0].ToInt(), 0))), nil
			}

			value := args[0].String()

			var format string
			if len(args) == 2 {
				switch args[1].Type {
				case sim.Null, sim.Undefined:
					format = ""
				case sim.String:
					format = args[1].String()
				default:
					return sim.NullValue, ErrInvalidType
				}
			} else {
				if IsNumeric(value) {
					i, err := strconv.ParseInt(value, 10, 64)
					if err != nil {
						panic(err)
					}
					return sim.NewObject(TimeObj(time.Unix(i, 0))), nil
				}
				format = ""
			}

			loc := vm.Localizer
			if loc == nil {
				loc = defaultLocalizer
			}

			v, err := loc.ParseDate(value, format, vm.Location)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(TimeObj(v)), nil
		},
	},
	{
		Name:      "locale.format",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 2 {
				return sim.NullValue, fmt.Errorf("expected 2 arguments, got %d", len(args))
			}

			a := args[0]
			if a.Type != sim.String {
				return sim.NullValue, fmt.Errorf("expected argument 1 to be a string, got %v", a.TypeName())
			}

			loc := vm.Localizer
			if loc == nil {
				loc = defaultLocalizer
			}

			b := args[1].Export(0)
			s := loc.Format(vm.Language, a.String(), b, vm.Translations)
			return sim.NewString(s), nil
		},
	},
}
View Source
var LockManager = []sim.NativeFunction{
	{
		Name:      "lockManager.lock",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) < 1 || len(args) > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 arguments, got %d", len(args))
			}
			if err := ValidateOptionalArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			key := args[0].String()
			contextId := ""
			if len(args) > 1 {
				contextId = args[1].String()
			}
			lock := lockStore.getLock(key)
			lock.Lock(contextId)

			return sim.NullValue, nil
		},
	},
	{
		Name:      "lockManager.unlock",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) < 1 || len(args) > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 arguments, got %d", len(args))
			}
			if err := ValidateOptionalArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			key := args[0].String()
			contextId := ""
			if len(args) > 1 {
				contextId = args[1].String()
			}
			lock := lockStore.getLock(key)
			if err := lock.Unlock(contextId); err != nil {
				return sim.NullValue, err
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "lockManager.rLock",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) < 1 || len(args) > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 arguments, got %d", len(args))
			}
			if err := ValidateOptionalArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			key := args[0].String()
			contextId := ""
			if len(args) > 1 {
				contextId = args[1].String()
			}
			lock := lockStore.getLock(key)
			lock.RLock(contextId)

			return sim.NullValue, nil
		},
	},
	{
		Name:      "lockManager.rUnlock",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) < 1 || len(args) > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 arguments, got %d", len(args))
			}
			if err := ValidateOptionalArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			key := args[0].String()
			contextId := ""
			if len(args) > 1 {
				contextId = args[1].String()
			}
			lock := lockStore.getLock(key)
			if err := lock.RUnlock(contextId); err != nil {
				return sim.NullValue, err
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "lockManager.exec",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args[:1], sim.String); err != nil {
				return sim.NullValue, err
			}

			key := args[0].String()
			fn := args[1]

			lock := lockStore.getLock(key)
			lock.Lock("")
			defer func() {
				if err := lock.Unlock(""); err != nil {

					fmt.Printf("Error unlocking in exec: %v\n", err)
				}
			}()

			switch fn.Type {
			case sim.Func:
				return vm.RunFuncIndex(int(fn.ToFunction()))
			case sim.Object:
				closure, ok := fn.ToObject().(*sim.Closure)
				if !ok {
					return sim.NullValue, fmt.Errorf("expected function or closure, got %v", fn.TypeName())
				}
				return vm.RunClosure(closure)
			default:
				return sim.NullValue, fmt.Errorf("expected argument 2 to be function or closure, got %s", fn.TypeName())
			}
		},
	},
	{
		Name:      "lockManager.execReentrant",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args[:2], sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			key := args[0].String()
			contextId := args[1].String()
			fn := args[2]

			lock := lockStore.getLock(key)
			lock.Lock(contextId)
			defer func() {
				if err := lock.Unlock(contextId); err != nil {

					fmt.Printf("Error unlocking in execReentrant: %v\n", err)
				}
			}()

			switch fn.Type {
			case sim.Func:
				return vm.RunFuncIndex(int(fn.ToFunction()))
			case sim.Object:
				closure, ok := fn.ToObject().(*sim.Closure)
				if !ok {
					return sim.NullValue, fmt.Errorf("expected function or closure, got %v", fn.TypeName())
				}
				return vm.RunClosure(closure)
			default:
				return sim.NullValue, fmt.Errorf("expected argument 3 to be function or closure, got %s", fn.TypeName())
			}
		},
	},
	{
		Name:      "lockManager.freeze",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args); err != nil {
				return sim.NullValue, err
			}

			// Create a mutex and lock it twice, which will cause a permanent deadlock
			var mu sync.Mutex
			mu.Lock()
			mu.Lock()

			return sim.NullValue, nil
		},
	},
}
View Source
var Markdown = []sim.NativeFunction{
	{
		Name:      "markdown.toHTML",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			text := args[0].ToString()
			html := parseBasicMarkdown(text)
			return sim.NewString(html), nil
		},
	},
	{
		Name:      "markdown.toHTMLFull",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			text := args[0].ToString()

			htmlFlags := 0
			htmlFlags |= blackfriday.HTML_USE_XHTML
			htmlFlags |= blackfriday.HTML_USE_SMARTYPANTS
			htmlFlags |= blackfriday.HTML_SMARTYPANTS_FRACTIONS
			htmlFlags |= blackfriday.HTML_SMARTYPANTS_LATEX_DASHES

			extensions := 0
			extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
			extensions |= blackfriday.EXTENSION_TABLES
			extensions |= blackfriday.EXTENSION_FENCED_CODE
			extensions |= blackfriday.EXTENSION_AUTOLINK
			extensions |= blackfriday.EXTENSION_STRIKETHROUGH
			extensions |= blackfriday.EXTENSION_SPACE_HEADERS
			extensions |= blackfriday.EXTENSION_HEADER_IDS
			extensions |= blackfriday.EXTENSION_BACKSLASH_LINE_BREAK
			extensions |= blackfriday.EXTENSION_DEFINITION_LISTS

			renderer := blackfriday.HtmlRenderer(htmlFlags, "", "")
			output := blackfriday.MarkdownOptions([]byte(text), renderer, blackfriday.Options{
				Extensions: extensions,
			})

			return sim.NewString(string(output)), nil
		},
	},
}
View Source
var Math = []sim.NativeFunction{
	{
		Name:      "math.pow",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Float, sim.Float); err != nil {
				return sim.NullValue, err
			}
			v := math.Pow(args[0].ToFloat(), args[1].ToFloat())
			return sim.NewFloat(v), nil
		},
	},
	{
		Name:      "math.abs",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}
			v := math.Abs(args[0].ToFloat())
			return sim.NewFloat(v), nil
		},
	},
	{
		Name:      "math.floor",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}
			v := math.Floor(args[0].ToFloat())
			return sim.NewInt64(int64(v)), nil
		},
	},
	{
		Name:      "math.ceil",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}
			v := math.Ceil(args[0].ToFloat())
			return sim.NewInt64(int64(v)), nil
		},
	},
	{
		Name:      "math.round",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {

			l := len(args)
			if l > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 params, got %d", l)
			}

			f := args[0]
			switch f.Type {
			case sim.Float, sim.Int:
			default:
				return sim.NullValue, fmt.Errorf("expected parameter 1 to be a number, got %s", f.TypeName())
			}

			if l == 1 {
				v := math.Round(f.ToFloat())
				return sim.NewInt64(int64(v)), nil
			}

			d := args[1]
			if d.Type != sim.Int {
				return sim.NullValue, fmt.Errorf("expected parameter 2 to be int, got %s", d.TypeName())
			}

			i := math.Pow10(int(d.ToInt()))
			v := math.Round(f.ToFloat()*i) / i
			return sim.NewFloat(v), nil
		},
	},
	{
		Name:      "math.trunc",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {

			l := len(args)
			if l > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 params, got %d", l)
			}

			f := args[0]
			switch f.Type {
			case sim.Float, sim.Int:
			default:
				return sim.NullValue, fmt.Errorf("expected parameter 1 to be a number, got %s", f.TypeName())
			}

			if l == 1 {
				v := math.Trunc(f.ToFloat())
				return sim.NewInt64(int64(v)), nil
			}

			d := args[1]
			if d.Type != sim.Int {
				return sim.NullValue, fmt.Errorf("expected parameter 2 to be int, got %s", d.TypeName())
			}

			i := math.Pow10(int(d.ToInt()))
			v := math.Trunc(f.ToFloat()*i) / i
			return sim.NewFloat(v), nil
		},
	},
	{
		Name:      "math.rand",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}
			v := rand.Intn(int(args[0].ToInt()))
			return sim.NewInt(v), nil
		},
	},
	{
		Name:      "math.median",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			values := make([]float64, len(args))

			for i, v := range args {
				switch v.Type {
				case sim.Int, sim.Float:
					values[i] = v.ToFloat()
				default:
					return sim.NullValue, fmt.Errorf("element at %d is not a number: %s", i, v.TypeName())
				}
			}

			r := median(values)
			return sim.NewFloat(r), nil
		},
	},
	{
		Name:      "math.min",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var min float64
			var found bool

			for i, v := range args {
				switch v.Type {
				case sim.Null, sim.Undefined:

				case sim.Int, sim.Float:
					k := v.ToFloat()
					if !found {
						found = true
						min = k
					} else {
						if i == 0 {
							min = k
						} else if k < min {
							min = k
						}
					}

				default:
					return sim.NullValue, fmt.Errorf("element at %d is not a number: %s", i, v.TypeName())
				}
			}

			if !found {
				return sim.UndefinedValue, nil
			}

			return sim.NewFloat(min), nil
		},
	},
	{
		Name:      "math.max",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var max float64
			var found bool

			for i, v := range args {
				switch v.Type {
				case sim.Null, sim.Undefined:

				case sim.Int, sim.Float:
					k := v.ToFloat()
					if !found {
						found = true
						max = k
					} else {
						if i == 0 {
							max = k
						} else if k > max {
							max = k
						}
					}
				default:
					return sim.NullValue, fmt.Errorf("element at %d is not a number: %s", i, v.TypeName())
				}
			}

			if !found {
				return sim.UndefinedValue, nil
			}

			return sim.NewFloat(max), nil
		},
	},
	{
		Name:      "math.standardDev",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			values := make([]float64, len(args))
			for i, v := range args {
				switch v.Type {
				case sim.Int, sim.Float:
					values[i] = v.ToFloat()
				default:
					return sim.NullValue, fmt.Errorf("element at %d is not a number: %s", i, v.TypeName())
				}
			}

			m := median(values)
			d := stdDev(values, m)
			return sim.NewFloat(d), nil
		},
	},
}
View Source
var Multipart = []sim.NativeFunction{
	{
		Name:      "multipart.newWriter",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			r := args[0].ToObject()

			w, ok := r.(io.Writer)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected a io.Writer, got %v", args[0])
			}

			m := multipart.NewWriter(w)
			return sim.NewObject(&multipartWriter{m}), nil
		},
	},
}
View Source
var Net = []sim.NativeFunction{
	{
		Name:      "net.inCIDR",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			cidr := args[0].String()

			ip := net.ParseIP(args[1].String())

			_, ipnet, err := net.ParseCIDR(cidr)
			if err != nil {
				return sim.NullValue, err
			}

			v := ipnet.Contains(ip)

			return sim.NewBool(v), nil
		},
	},
	{
		Name:        "net.listen",
		Arguments:   2,
		Permissions: []string{"netListen"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			listener, err := newNetListener(args[0].String(), args[1].String(), vm)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(listener), nil
		},
	},
	{
		Name:        "net.listenTCP",
		Arguments:   2,
		Permissions: []string{"netListen"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}

			addr, ok := args[1].ToObject().(*tcpAddr)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected param 2 to be TCPAddr, got %s", args[1].TypeName())
			}

			listener, err := newTCPListener(args[0].String(), addr.addr, vm)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(listener), nil
		},
	},
	{
		Name:      "net.resolveTCPAddr",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			addr, err := net.ResolveTCPAddr(args[0].String(), args[1].String())
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(&tcpAddr{addr: addr}), nil
		},
	},
	{
		Name:      "net.dialTCP",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOrNilArgs(args, sim.String, sim.Object, sim.Object); err != nil {
				return sim.NullValue, err
			}

			network := args[0].String()

			var localAddr *net.TCPAddr

			lArg := args[1].ToObjectOrNil()
			if lArg != nil {
				ltcpAddr, ok := lArg.(*tcpAddr)
				if !ok {
					return sim.NullValue, fmt.Errorf("expected param 2 to be TCPAddr, got %s", args[1].TypeName())
				}
				localAddr = ltcpAddr.addr
			}

			remoteAddr, ok := args[2].ToObject().(*tcpAddr)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected param 3 to be TCPAddr, got %s", args[1].TypeName())
			}

			conn, err := net.DialTCP(network, localAddr, remoteAddr.addr)
			if err != nil {
				return sim.NullValue, err
			}

			tc := newTCPConn(conn, vm)

			return sim.NewObject(tc), nil
		},
	},
	{
		Name:      "net.dial",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}
			conn, err := net.Dial(args[0].String(), args[1].String())
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(newNetConn(conn, vm)), nil
		},
	},
	{
		Name:      "net.dialTimeout",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected param 1 to be string, got %s", args[0].TypeName())
			}
			if !isStringLike(args[1]) {
				return sim.NullValue, fmt.Errorf("expected param 2 to be string, got %s", args[1].TypeName())
			}

			d, err := ToDuration(args[2])
			if err != nil {
				return sim.NullValue, err
			}

			conn, err := net.DialTimeout(args[0].String(), args[1].String(), d)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(newNetConn(conn, vm)), nil
		},
	},
	{
		Name:        "net.getIPAddress",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			addrs, err := net.InterfaceAddrs()
			if err != nil {
				return sim.NullValue, err
			}

			for _, address := range addrs {
				if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
					if ipnet.IP.To4() != nil {
						return sim.NewString(ipnet.IP.String()), nil
					}
				}
			}

			return sim.NullValue, fmt.Errorf("no IP address found")
		},
	},
	{
		Name:        "net.getMacAddress",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			addrs, err := net.InterfaceAddrs()
			if err != nil {
				return sim.NullValue, err
			}

			var ip string

			for _, address := range addrs {
				if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
					if ipnet.IP.To4() != nil {
						ip = ipnet.IP.String()
						break
					}
				}
			}

			if ip == "" {
				return sim.NullValue, fmt.Errorf("no IP address found")
			}

			interfaces, err := net.Interfaces()
			if err != nil {
				return sim.NullValue, err
			}

			var hardwareName string

			for _, interf := range interfaces {
				if addrs, err := interf.Addrs(); err == nil {
					for _, addr := range addrs {

						if strings.Contains(addr.String(), ip) {
							hardwareName = interf.Name
							break
						}
					}
				}
			}

			if hardwareName == "" {
				return sim.NullValue, fmt.Errorf("no network hardware found")
			}

			netInterface, err := net.InterfaceByName(hardwareName)
			if err != nil {
				return sim.NullValue, err
			}

			macAddress := netInterface.HardwareAddr

			hwAddr, err := net.ParseMAC(macAddress.String())
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewString(hwAddr.String()), nil
		},
	},
}
View Source
var Number = []sim.NativeFunction{
	{
		Name: "->Number.MAX_VALUE",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewFloat(math.MaxFloat64), nil
		},
	},
	{
		Name: "->Number.MIN_VALUE",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewFloat(math.SmallestNonzeroFloat64), nil
		},
	},
	{
		Name: "->Number.NaN",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewFloat(math.NaN()), nil
		},
	},
	{
		Name: "->Number.NEGATIVE_INFINITY",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewFloat(math.Inf(-1)), nil
		},
	},
	{
		Name: "Number.POSITIVE_INFINITY",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewFloat(math.Inf(1)), nil
		},
	},
	{
		Name:      "Number.prototype.format",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			switch this.Type {
			case sim.Int, sim.Float:
				break
			default:
				return sim.NullValue, fmt.Errorf("expected byte array, got %s", this.TypeName())
			}

			format := args[0].ToString()

			loc := vm.Localizer
			if loc == nil {
				loc = defaultLocalizer
			}

			num := this.Export(0)

			s := loc.Format(vm.Language, format, num, vm.Translations)

			return sim.NewString(s), nil
		},
	},
	{
		Name:      "Number.prototype.toFixed",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			var precision int = 0

			if len(args) > 0 {
				precision = int(args[0].ToInt())
			}

			if precision < 0 || precision > 100 {
				return sim.NullValue, fmt.Errorf("toFixed() digits argument must be between 0 and 100")
			}

			// Convert to float64 to handle both int and float
			var num float64
			if this.Type == sim.Int {
				num = float64(this.ToInt())
			} else {
				num = this.ToFloat()
			}

			s := fmt.Sprintf("%."+strconv.Itoa(precision)+"f", num)
			return sim.NewString(s), nil
		},
	},
	{
		Name:      "Number.prototype.toString",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			radix := 10
			if len(args) > 0 {
				radix = int(args[0].ToInt())
			}

			if radix < 2 || radix > 36 {
				return sim.NullValue, fmt.Errorf("toString() radix argument must be between 2 and 36")
			}

			var result string
			if this.Type == sim.Int {
				result = strconv.FormatInt(this.ToInt(), radix)
			} else {
				if radix != 10 {
					return sim.NullValue, fmt.Errorf("toString() radix argument only supported for integers")
				}
				result = strconv.FormatFloat(this.ToFloat(), 'g', -1, 64)
			}

			return sim.NewString(result), nil
		},
	},
	{
		Name:      "Number.prototype.toExponential",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			var precision int = -1 // -1 means use as many digits as necessary

			if len(args) > 0 {
				precision = int(args[0].ToInt())
				if precision < 0 || precision > 100 {
					return sim.NullValue, fmt.Errorf("toExponential() fractionDigits argument must be between 0 and 100")
				}
			}

			// Convert to float64
			var num float64
			if this.Type == sim.Int {
				num = float64(this.ToInt())
			} else {
				num = this.ToFloat()
			}

			var result string
			if precision == -1 {
				result = strconv.FormatFloat(num, 'e', -1, 64)
			} else {
				result = strconv.FormatFloat(num, 'e', precision, 64)
			}

			return sim.NewString(result), nil
		},
	},
	{
		Name:      "Number.prototype.toPrecision",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			// Convert to float64
			var num float64
			if this.Type == sim.Int {
				num = float64(this.ToInt())
			} else {
				num = this.ToFloat()
			}

			if len(args) == 0 {
				result := strconv.FormatFloat(num, 'g', -1, 64)
				return sim.NewString(result), nil
			}

			precision := int(args[0].ToInt())
			if precision < 1 || precision > 100 {
				return sim.NullValue, fmt.Errorf("toPrecision() precision argument must be between 1 and 100")
			}

			result := strconv.FormatFloat(num, 'g', precision, 64)
			return sim.NewString(result), nil
		},
	},
	{
		Name: "Number.prototype.valueOf",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args); err != nil {
				return sim.NullValue, err
			}

			return this, nil
		},
	},
	{
		Name:      "Number",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 0, 1); err != nil {
				return sim.NullValue, err
			}

			if len(args) == 0 {
				return sim.NewInt(0), nil
			}

			arg := args[0]
			switch arg.Type {
			case sim.Int, sim.Float:
				return arg, nil
			case sim.String:
				str := strings.TrimSpace(arg.ToString())
				if str == "" {
					return sim.NewInt(0), nil
				}

				if str == "Infinity" || str == "+Infinity" {
					return sim.NewFloat(math.Inf(1)), nil
				}
				if str == "-Infinity" {
					return sim.NewFloat(math.Inf(-1)), nil
				}
				if str == "NaN" {
					return sim.NewFloat(math.NaN()), nil
				}

				str = strings.TrimLeft(str, " \t\n\r\v\f")

				if str == "" {
					return sim.NewInt(0), nil
				}

				sign := 1.0
				switch str[0] {
				case '-':
					sign = -1
					str = str[1:]
				case '+':
					str = str[1:]
				}

				if str == "" {
					return sim.NewFloat(math.NaN()), nil
				}

				hasDecimal := false
				result := 0.0
				decimalPlaces := 0.0

				for i, char := range str {
					if char == '.' && !hasDecimal {
						hasDecimal = true
						continue
					}

					if char >= '0' && char <= '9' {
						if hasDecimal {
							decimalPlaces++
							result = result + float64(char-'0')/math.Pow(10, decimalPlaces)
						} else {
							result = result*10 + float64(char-'0')
						}
					} else {

						if i == 0 {
							return sim.NewFloat(math.NaN()), nil
						}
						break
					}
				}

				result *= sign

				if !hasDecimal && result >= math.MinInt64 && result <= math.MaxInt64 {
					return sim.NewInt64(int64(result)), nil
				}
				return sim.NewFloat(result), nil
			case sim.Bool:
				if arg.ToBool() {
					return sim.NewInt(1), nil
				}
				return sim.NewInt(0), nil
			case sim.Null:
				return sim.NewInt(0), nil
			case sim.Undefined:
				return sim.NewFloat(math.NaN()), nil
			default:
				return sim.NewFloat(math.NaN()), nil
			}
		},
	},
	{
		Name:      "isNaN",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 1 {
				return sim.NullValue, fmt.Errorf("expected 1 argument, got %d", len(args))
			}

			value := args[0]

			switch value.Type {
			case sim.Float:
				return sim.NewBool(math.IsNaN(value.ToFloat())), nil
			case sim.Int:

				return sim.FalseValue, nil
			case sim.String:

				s := value.String()
				if s == "" {
					return sim.FalseValue, nil
				}
				if f, err := strconv.ParseFloat(s, 64); err != nil {

					return sim.TrueValue, nil
				} else {
					return sim.NewBool(math.IsNaN(f)), nil
				}
			case sim.Bool:

				return sim.FalseValue, nil
			case sim.Null:

				return sim.FalseValue, nil
			case sim.Undefined:

				return sim.TrueValue, nil
			default:

				s := value.String()
				if f, err := strconv.ParseFloat(s, 64); err != nil {
					return sim.TrueValue, nil
				} else {
					return sim.NewBool(math.IsNaN(f)), nil
				}
			}
		},
	},
	{
		Name:      "Number.isNaN",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 1 {
				return sim.NullValue, fmt.Errorf("expected 1 argument, got %d", len(args))
			}

			value := args[0]

			if value.Type == sim.Float {
				return sim.NewBool(math.IsNaN(value.ToFloat())), nil
			}

			return sim.FalseValue, nil
		},
	},
}
View Source
var OS = []sim.NativeFunction{
	{
		Name:        "->os.sharedCache",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sharedCache, nil
		},
	},
	{
		Name: "->os.ErrNotExist",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewString("no such file or directory"), nil
		},
	},
	{
		Name:        "os.hostName",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			name, err := os.Hostname()
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewString(name), nil
		},
	},
	{
		Name: "->os.pathSeparator",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewString(string(os.PathSeparator)), nil
		},
	},
	{
		Name:        "->os.userHomeDir",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d, err := os.UserHomeDir()
			if err != nil {
				return sim.NullValue, ErrUnauthorized
			}
			return sim.NewString(d), nil
		},
	},
	{
		Name:        "->os.stdout",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			f := &file{f: os.Stdout}
			return sim.NewObject(f), nil
		},
	},
	{
		Name:        "->os.stdin",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			f := &file{f: os.Stdin}
			return sim.NewObject(f), nil
		},
	},
	{
		Name:        "->os.stderr",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			f := &file{f: os.Stderr}
			return sim.NewObject(f), nil
		},
	},
	{
		Name:        "os.mapPath",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			p := args[0].String()

			if len(p) > 0 && p[0] == '~' {
				usr, err := user.Current()
				if err != nil {
					return sim.NullValue, err
				}
				p = filepath.Join(usr.HomeDir, p[1:])
			}

			return sim.NewString(p), nil
		},
	},
	{
		Name:        "os.exit",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			var exitCode int
			if len(args) > 0 {
				exitCode = int(args[0].ToInt())
			}

			os.Exit(exitCode)
			return sim.NullValue, nil
		},
	},
	{
		Name:        "os.exec",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := len(args)
			if l == 0 {
				return sim.NullValue, fmt.Errorf("expected at least 1 argument")
			}

			values := make([]string, l)
			for i, v := range args {
				values[i] = v.String()
			}

			cmd := exec.Command(values[0], values[1:]...)
			cmd.Stderr = os.Stderr
			cmd.Stdout = os.Stdout

			if err := cmd.Run(); err != nil {
				return sim.NullValue, err
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:        "os.newCommand",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := len(args)
			if l == 0 {
				return sim.NullValue, fmt.Errorf("expected at least 1 argument")
			}

			values := make([]string, l)
			for i, v := range args {
				values[i] = v.String()
			}

			cmd := newCommand(values[0], values[1:]...)

			return sim.NewObject(cmd), nil
		},
	},

	{
		Name:      "os.getWd",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}

			f := &FileSystemObj{fs}
			return f.getWd(args, vm)
		},
	},
	{
		Name:      "os.open",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.open(args, vm)
		},
	},
	{
		Name:      "os.openIfExists",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.openIfExists(args, vm)
		},
	},
	{
		Name:      "os.openForWrite",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.openForWrite(args, vm)
		},
	},
	{
		Name:      "os.openForAppend",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.openForAppend(args, vm)
		},
	},
	{
		Name:      "os.chdir",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.chdir(args, vm)
		},
	},
	{
		Name:      "os.exists",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.exists(args, vm)
		},
	},
	{
		Name:      "os.rename",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.rename(args, vm)
		},
	},
	{
		Name:      "os.removeAll",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.removeAll(args, vm)
		},
	},
	{
		Name:      "os.readAll",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readAll(args, vm)
		},
	},
	{
		Name:      "os.readAllIfExists",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readAllIfExists(args, vm)
		},
	},
	{
		Name:      "os.readString",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readString(args, vm)
		},
	},
	{
		Name:      "os.readStringIfExists",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readStringIfExists(args, vm)
		},
	},
	{
		Name:      "os.write",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.write(args, vm)
		},
	},
	{
		Name:      "os.append",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.append(args, vm)
		},
	},
	{
		Name:      "os.mkdir",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.mkdir(args, vm)
		},
	},
	{
		Name:      "os.stat",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.stat(args, vm)
		},
	},
	{
		Name:      "os.readDir",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readDir(args, vm)
		},
	},
	{
		Name:      "os.readNames",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			fs := vm.FileSystem
			if fs == nil {
				return sim.NullValue, ErrNoFileSystem
			}
			f := &FileSystemObj{fs}
			return f.readNames(args, vm)
		},
	},

	{
		Name:        "os.readLine",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {

			r := bufio.NewReader(os.Stdin)
			s, err := r.ReadString('\n')
			if err != nil {
				return sim.NullValue, err
			}

			s = s[:len(s)-1]

			return sim.NewString(s), nil
		},
	},
	{
		Name: "->os.fileSystem",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.FileSystem == nil {
				return sim.NullValue, nil
			}
			return sim.NewObject(NewFileSystem(vm.FileSystem)), nil
		},
	},
	{
		Name:        "os.getEnv",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			s := os.Getenv(args[0].String())
			return sim.NewString(s), nil
		},
	},
	{
		Name:        "os.setEnv",
		Arguments:   2,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			if err := os.Setenv(args[0].String(), args[1].String()); err != nil {
				return sim.NullValue, err
			}
			return sim.NullValue, nil
		},
	},
	{
		Name:        "os.newFile",
		Arguments:   2,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int, sim.String); err != nil {
				return sim.NullValue, err
			}

			f := os.NewFile(uintptr(args[0].ToInt()), args[1].String())
			ff := &file{f: f}
			return sim.NewObject(ff), nil
		},
	},
	{
		Name:      "->os.DevNull",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewString(os.DevNull), nil
		},
	},
}
View Source
var PDF = []sim.NativeFunction{
	{
		Name: "pdf.newConfig",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			conf := &gopdf.Config{
				PageSize: *gopdf.PageSizeA4,
			}
			return sim.NewObject(&pdfConfig{config: conf}), nil
		},
	},
	{
		Name:      "pdf.newPDF",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			var conf gopdf.Config

			if len(args) > 0 {
				cn, ok := args[0].ToObjectOrNil().(*pdfConfig)
				if !ok {
					return sim.NullValue, fmt.Errorf("expected arg 1 to be config, got %s", args[0].TypeName())
				}
				conf = *cn.config
			} else {
				conf = gopdf.Config{
					PageSize: *gopdf.PageSizeA4,
				}
			}

			p := &pdfDoc{pdf: &gopdf.GoPdf{}, lineWidth: 1}

			p.pdf.Start(conf)

			if err := p.pdf.AddTTFFontData("roboto", pdf.RobotoRegular); err != nil {
				return sim.NullValue, err
			}

			if err := p.pdf.AddTTFFontData("robotoBold", pdf.RobotoBold); err != nil {
				return sim.NullValue, err
			}

			p.width = conf.PageSize.W
			p.height = conf.PageSize.H
			p.fontFamily = "roboto"
			p.fontSize = 14
			p.lineHeight = lineHeight(14)

			if err := p.pdf.SetFont("roboto", "", p.fontSize); err != nil {
				return sim.NullValue, err
			}

			if p.textColor == nil {
				p.textColor = &pdfColor{}
			}

			if p.fillColor == nil {
				p.fillColor = &pdfColor{}
			}

			if p.strokeColor == nil {
				p.strokeColor = &pdfColor{}
			}

			return sim.NewObject(p), nil
		},
	},
	{
		Name: "pdf.newCellOption",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewObject(&pdfCellOption{opt: gopdf.CellOption{}}), nil
		},
	},
	{
		Name:      "pdf.newRect",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Float, sim.Float); err != nil {
				return sim.NullValue, err
			}

			rect := &gopdf.Rect{
				W: args[0].ToFloat(),
				H: args[1].ToFloat(),
			}

			return sim.NewObject(&pdfRect{rect}), nil
		},
	},
	{
		Name:      "pdf.write",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {

			writer, ok := args[0].ToObjectOrNil().(io.Writer)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected first parameter to be io.Writer, got %s", args[0].TypeName())
			}

			if err := ValidateArgs(args[1:2], sim.String); err != nil {
				return sim.NullValue, err
			}
			xmlStr := args[1].ToString()

			if err := pdfWriteDirect(writer, xmlStr); err != nil {
				return sim.NullValue, err
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "pdf.writeFile",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {

			if err := ValidateArgs(args[0:1], sim.String); err != nil {
				return sim.NullValue, err
			}
			filePath := args[0].ToString()

			if err := ValidateArgs(args[1:2], sim.String); err != nil {
				return sim.NullValue, err
			}
			xmlStr := args[1].ToString()

			if err := pdfWriteFileDirect(filePath, xmlStr); err != nil {
				return sim.NullValue, err
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "pdf.render",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) < 2 || len(args) > 3 {
				return sim.NullValue, fmt.Errorf("pdf.render expects 2 or 3 parameters, got %d", len(args))
			}

			writer, ok := args[0].ToObjectOrNil().(io.Writer)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected first parameter to be io.Writer, got %s", args[0].TypeName())
			}

			if err := ValidateArgs(args[1:2], sim.String); err != nil {
				return sim.NullValue, err
			}
			template := args[1].ToString()

			// Third parameter: optional data
			var data sim.Value = sim.NullValue
			if len(args) == 3 {
				data = args[2]
			}

			if err := pdfRender(writer, template, data, vm); err != nil {
				return sim.NullValue, err
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "pdf.renderFile",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) < 2 || len(args) > 3 {
				return sim.NullValue, fmt.Errorf("pdf.renderFile expects 2 or 3 parameters, got %d", len(args))
			}

			if err := ValidateArgs(args[0:1], sim.String); err != nil {
				return sim.NullValue, err
			}
			filePath := args[0].ToString()

			if err := ValidateArgs(args[1:2], sim.String); err != nil {
				return sim.NullValue, err
			}
			template := args[1].ToString()

			// Third parameter: optional data
			var data sim.Value = sim.NullValue
			if len(args) == 3 {
				data = args[2]
			}

			if err := pdfRenderFile(filePath, template, data, vm); err != nil {
				return sim.NullValue, err
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "pdf.newRenderer",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 1 {
				return sim.NullValue, errors.New("expected 1 argument")
			}

			xmlStr := args[0].ToString()

			xmlDoc := etree.NewDocument()
			if err := xmlDoc.ReadFromString(xmlStr); err != nil {
				return sim.NullValue, err
			}

			document, err := pdf.Parse(xmlDoc)
			if err != nil {
				return sim.NullValue, err
			}

			formatter := createNumberFormatter(vm)
			doc := pdf.SetLayout(document, formatter)
			if doc == nil {
				return sim.NullValue, fmt.Errorf("failed to set layout")
			}

			_, err = pdf.NewRenderer(doc, xmlStr)
			if err != nil {
				return sim.NullValue, err
			}

			obj := sim.NewObject(map[string]interface{}{})

			return obj, nil
		},
	},
}
View Source
var Png = []sim.NativeFunction{
	{
		Name:      "png.decode",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 1); err != nil {
				return sim.NullValue, err
			}

			a := args[0]
			var r io.Reader

			switch a.Type {
			case sim.Object:
				var ok bool
				r, ok = a.ToObject().(io.Reader)
				if !ok {
					return sim.NullValue, ErrInvalidType
				}
			case sim.Bytes:
				r = bytes.NewBuffer(a.ToBytes())
			}

			img, err := png.Decode(r)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(imageObj{img: img, format: "PNG"}), nil
		},
	},
	{
		Name:      "png.encode",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object, sim.Object); err != nil {
				return sim.NullValue, err
			}

			w, ok := args[0].ToObject().(io.Writer)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}

			i, ok := args[1].ToObject().(imageObj)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}

			err := png.Encode(w, i.img)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NullValue, nil
		},
	},
}
View Source
var Printing = []sim.NativeFunction{
	{
		Name:      "printing.listPrinters",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			list, err := printutil.ListPrinters()
			if err != nil {
				return sim.NullValue, err
			}

			values := make([]sim.Value, len(list))

			for i, name := range list {
				values[i] = sim.NewString((name))
			}

			return sim.NewArrayValues(values), nil
		},
	},
	{
		Name:      "printing.newPrinter",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.Bool); err != nil {
				return sim.NullValue, err
			}

			var name string
			var cups bool

			switch len(args) {
			case 0:
				return sim.NullValue, fmt.Errorf("expected at least one argument")

			case 1:
				name = args[0].ToString()

			case 2:
				name = args[0].ToString()
				cups = args[1].ToBool()
			}

			p := printutil.New(name, cups)

			return sim.NewObject(&printerObj{p}), nil
		},
	},
}
View Source
var Profiler = []sim.NativeFunction{}
View Source
var QRCode = []sim.NativeFunction{
	{
		Name:      "qrcode.encode",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String, sim.Int); err != nil {
				return sim.NullValue, err
			}

			value := args[0].ToString()

			var level qrcode.RecoveryLevel

			switch args[1].ToString() {
			case "low":
				level = qrcode.Low
			case "medium":
				level = qrcode.Medium
			case "high":
				level = qrcode.High
			case "highest":
				level = qrcode.Highest
			}

			size := int(args[2].ToInt())

			png, err := qrcode.Encode(value, level, size)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewBytes(png), nil
		},
	},
	{
		Name:      "qrcode.encodeVersion",
		Arguments: 4,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String, sim.Int, sim.Int); err != nil {
				return sim.NullValue, err
			}

			value := args[0].ToString()

			var level qrcode.RecoveryLevel

			switch args[1].ToString() {
			case "low":
				level = qrcode.Low
			case "medium":
				level = qrcode.Medium
			case "high":
				level = qrcode.High
			case "highest":
				level = qrcode.Highest
			}

			size := int(args[2].ToInt())

			version := int(args[3].ToInt())

			qr, err := qrcode.NewWithForcedVersion(value, version, level)
			if err != nil {
				return sim.NullValue, err
			}

			png, err := qr.PNG(size)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewBytes(png), nil
		},
	},
}
View Source
var RSA = []sim.NativeFunction{
	{
		Name:      "rsa.generateKey",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			reader := rand.Reader

			var bitSize int
			if len(args) == 0 {
				bitSize = 2048
			} else {
				bitSize = int(args[0].ToInt())
			}

			key, err := rsa.GenerateKey(reader, bitSize)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(&rsaPrivateKey{key}), nil
		},
	},
	{
		Name:      "rsa.decodePEMKey",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0].ToBytes()

			block, _ := pem.Decode(v)

			if block == nil {
				return sim.NullValue, fmt.Errorf("error decoding private key")
			}

			enc := x509.IsEncryptedPEMBlock(block)

			b := block.Bytes

			var err error
			if enc {

				b, err = x509.DecryptPEMBlock(block, nil)
				if err != nil {
					return sim.NullValue, fmt.Errorf("error decrypting private key")
				}
			}

			key, err := x509.ParsePKCS1PrivateKey(b)
			if err != nil {
				return sim.NullValue, fmt.Errorf("error parsing private key: %w", err)
			}

			return sim.NewObject(&rsaPrivateKey{key}), nil
		},
	},
	{
		Name:      "rsa.decodePublicPEMKey",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0].ToBytes()

			block, _ := pem.Decode(v)

			if block == nil {
				return sim.NullValue, fmt.Errorf("error decoding public key")
			}

			enc := x509.IsEncryptedPEMBlock(block)

			b := block.Bytes

			var err error
			if enc {

				b, err = x509.DecryptPEMBlock(block, nil)
				if err != nil {
					return sim.NullValue, fmt.Errorf("error decrypting public key")
				}
			}

			parsedKey, err := x509.ParsePKIXPublicKey(b)
			if err != nil {
				if cert, err := x509.ParseCertificate(block.Bytes); err == nil {
					parsedKey = cert.PublicKey
				} else {
					parsedKey, err = x509.ParsePKCS1PublicKey(block.Bytes)
					if err != nil {
						return sim.NullValue, fmt.Errorf("error parsing public key (2): %v", err)
					}
				}
			}

			key, ok := parsedKey.(*rsa.PublicKey)
			if !ok {
				return sim.NullValue, fmt.Errorf("not an RSA public key")
			}

			return sim.NewObject(&rsaPublicKey{key}), nil
		},
	},
	{
		Name:      "rsa.signPKCS1v15",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			key, ok := args[0].ToObjectOrNil().(*rsaPrivateKey)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected a rsa key, got %v", args[0].TypeName())
			}

			message := args[1].ToBytes()

			hashed := sha256.Sum256(message)

			rng := rand.Reader

			signature, err := rsa.SignPKCS1v15(rng, key.key, crypto.SHA256, hashed[:])
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewBytes(signature), nil
		},
	},
	{
		Name:      "rsa.verifyPKCS1v15",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			key, ok := args[0].ToObjectOrNil().(*rsaPublicKey)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected a rsa key, got %v", args[0].TypeName())
			}

			message := args[1].ToBytes()
			signature := args[2].ToBytes()

			hashed := sha256.Sum256(message)

			err := rsa.VerifyPKCS1v15(key.key, crypto.SHA256, hashed[:], signature)
			if err != nil {
				return sim.FalseValue, nil
			}

			return sim.TrueValue, err
		},
	},
}
View Source
var Reflect = []sim.NativeFunction{
	{
		Name:      "reflect.createInstance",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) == 0 {
				return sim.NullValue, fmt.Errorf("expected at least 1 parameter, got %d", len(args))
			}

			a := args[0]
			if a.Type != sim.String {
				return sim.NullValue, fmt.Errorf("argument 1 must be a string, got %s", a.TypeName())
			}

			instance, err := sim.NewInstance(a.String(), args[1:], vm)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(instance), nil
		},
	},
	{
		Name:      "reflect.nativeFunctions",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := getNativeFuncions(false)
			return v, nil
		},
	},
	{
		Name:      "reflect.nativeProperties",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := getNativeFuncions(true)
			return v, nil
		},
	},
	{
		Name:      "reflect.is",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0].TypeName()
			b := args[1]
			if b.Type != sim.String {
				return sim.NullValue, fmt.Errorf("argument 2 must be a string, got %s", b.TypeName())
			}
			return sim.NewBool(a == b.String()), nil
		},
	},
	{
		Name:      "reflect.isValue",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			switch args[0].Type {
			case sim.Int, sim.Float, sim.Bool, sim.String:
				return sim.FalseValue, nil
			}
			return sim.TrueValue, nil
		},
	},
	{
		Name:      "reflect.isNativeObject",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0].Type == sim.Object
			return sim.NewBool(v), nil
		},
	},
	{
		Name:      "reflect.isArray",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0].Type == sim.Array
			return sim.NewBool(v), nil
		},
	},
	{
		Name:      "reflect.isMap",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0].Type == sim.Map
			return sim.NewBool(v), nil
		},
	},
	{
		Name:      "reflect.typeOf",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]
			return sim.NewString(v.TypeName()), nil
		},
	},
	{
		Name:      "reflect.call",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) == 0 {
				return sim.NullValue, fmt.Errorf("expected the function name")
			}
			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("argument must be a string, got %s", args[0].TypeName())
			}

			return vm.RunFunc(args[0].String(), args[1:]...)
		},
	},
	{
		Name:      "reflect.getFunction",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("argument must be a string, got %s", args[0].TypeName())
			}

			name := args[0].String()
			fn, ok := vm.Program.Function(name)
			if !ok {
				return sim.NullValue, nil
			}

			v := sim.NewFunction(fn.Index)
			return v, nil
		},
	},
	{
		Name:      "reflect.getFunctionInfo",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Func); err != nil {
				return sim.NullValue, err
			}

			i := args[0].ToFunction()

			if i < 0 || i > len(vm.Program.Functions)-1 {
				return sim.NullValue, fmt.Errorf("index out of range")
			}

			f := vm.Program.Functions[i]

			p := program{vm.Program}

			return sim.NewObject(functionInfo{f, p}), nil
		},
	},
	{
		Name:      "reflect.findFunction",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			name := args[0].String()
			suffix := "/" + name

			for _, f := range vm.Program.Functions {
				if name == f.Name || strings.HasSuffix(f.Name, suffix) {
					p := program{vm.Program}
					fi := functionInfo{f, p}
					return sim.NewObject(fi), nil
				}
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "reflect.runFunc",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := len(args)
			if l < 1 {
				return sim.NullValue, fmt.Errorf("expected at least 1 parameter, got %d", l)
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("argument must be a string, got %s", args[0].TypeName())
			}

			name := args[0].String()

			v, err := vm.RunFunc(name, args[1:]...)
			if err != nil {
				return sim.NullValue, err
			}

			return v, nil
		},
	},
}
View Source
var Regex = []sim.NativeFunction{
	{
		Name:      "regex.match",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			ok, err := regexp.MatchString(args[0].String(), args[1].String())
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewBool(ok), nil
		},
	},
	{
		Name:      "regex.split",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			r, err := regexp.Compile(args[0].String())
			if err != nil {
				return sim.NullValue, err
			}

			matches := r.Split(args[1].String(), -1)

			ln := len(matches)
			result := make([]sim.Value, ln)
			for i := 0; i < ln; i++ {
				result[i] = sim.NewString(matches[i])
			}

			return sim.NewArrayValues(result), nil
		},
	},
	{
		Name:      "regex.findAllStringSubmatchIndex",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return sim.NullValue, err
			}
			if err := ValidateOptionalArgs(args, sim.String, sim.String, sim.Int); err != nil {
				return sim.NullValue, err
			}

			r, err := regexp.Compile(args[0].String())
			if err != nil {
				return sim.NullValue, err
			}

			var i int
			if len(args) == 3 {
				i = int(args[2].ToInt())
			} else {
				i = -1
			}

			matches := r.FindAllStringSubmatchIndex(args[1].String(), i)

			var result []sim.Value
			for _, v := range matches {
				ln := len(v)
				a := make([]sim.Value, ln)
				for i := 0; i < ln; i++ {
					a[i] = sim.NewInt(v[i])
				}

				result = append(result, sim.NewArrayValues(a))
			}

			return sim.NewArrayValues(result), nil
		},
	},
	{
		Name:      "regex.findAllString",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return sim.NullValue, err
			}
			if err := ValidateOptionalArgs(args, sim.String, sim.String, sim.Int); err != nil {
				return sim.NullValue, err
			}

			r, err := regexp.Compile(args[0].String())
			if err != nil {
				return sim.NullValue, err
			}

			var i int
			if len(args) == 3 {
				i = int(args[2].ToInt())
			} else {
				i = -1
			}

			matches := r.FindAllString(args[1].String(), i)

			var result []sim.Value

			for _, v := range matches {
				result = append(result, sim.NewString(v))
			}

			return sim.NewArrayValues(result), nil
		},
	},
	{
		Name:      "regex.findAllStringSubmatch",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return sim.NullValue, err
			}
			if err := ValidateOptionalArgs(args, sim.String, sim.String, sim.Int); err != nil {
				return sim.NullValue, err
			}

			r, err := regexp.Compile(args[0].String())
			if err != nil {
				return sim.NullValue, err
			}

			var i int
			if len(args) == 3 {
				i = int(args[2].ToInt())
			} else {
				i = -1
			}

			matches := r.FindAllStringSubmatch(args[1].String(), i)

			var result []sim.Value

			for _, v := range matches {
				var subResult []sim.Value
				for _, sv := range v {
					subResult = append(subResult, sim.NewString(sv))
				}
				result = append(result, sim.NewArrayValues(subResult))
			}

			return sim.NewArrayValues(result), nil
		},
	},
	{
		Name:      "regex.replaceAllString",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.String, sim.String); err != nil {
				return sim.NullValue, err
			}

			r, err := regexp.Compile(args[0].String())
			if err != nil {
				return sim.NullValue, err
			}

			result := r.ReplaceAllString(args[1].String(), args[2].String())

			return sim.NewString(result), nil
		},
	},
}
View Source
var Router = []sim.NativeFunction{
	{
		Name: "routing.newRouter",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			r := newRouter()
			return sim.NewObject(r), nil
		},
	},
}
View Source
var Runtime = []sim.NativeFunction{
	{
		Name: "->runtime.ErrFunctionNotExist",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewString(sim.ErrFunctionNotExist.Error()), nil
		},
	},
	{
		Name: "runtime.numGoroutine",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			n := runtime.NumGoroutine()
			return sim.NewInt(n), nil
		},
	},
	{
		Name: "runtime.memStats",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var stats runtime.MemStats
			runtime.ReadMemStats(&stats)
			return sim.NewObject(&memStats{stats}), nil
		},
	},
	{
		Name: "runtime.freeDiskSpace",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			percent, err := getSystemDiskFreePercent()
			return sim.NewInt64(int64(percent)), err
		},
	},
	{
		Name: "runtime.getUsedCPUPercent",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			percent, err := getSystemCPUUsedPercent()
			return sim.NewInt64(int64(percent)), err
		},
	},
	{
		Name: "runtime.usedMemoryPercent",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			percent, err := getSystemUsedMemoryPercent()
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewInt64(int64(percent)), nil
		},
	},
	{
		Name: "runtime.getSystemNetworkBytes",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			rx, tx, err := getSystemNetworkBytes()
			if err != nil {
				return sim.NullValue, err
			}
			m := make(map[sim.Value]sim.Value)
			m[sim.NewString("rx")] = sim.NewInt64(int64(rx))
			m[sim.NewString("tx")] = sim.NewInt64(int64(tx))
			return sim.NewMapValues(m, true), nil
		},
	},
	{
		Name: "runtime.startProfiler",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Profiler == nil {
				vm.Profiler = sim.NewProfiler()
			}
			vm.Profiler.Start()
			return sim.NullValue, nil
		},
	},
	{
		Name: "runtime.stopProfiler",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Profiler == nil {
				return sim.NullValue, fmt.Errorf("there is no profiler in the current context")
			}
			vm.Profiler.Stop()
			return sim.NullValue, nil
		},
	},
	{
		Name: "runtime.resetProfiler",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if vm.Profiler == nil {
				return sim.NullValue, fmt.Errorf("there is no profiler in the current context")
			}
			vm.Profiler.Reset()
			return sim.NullValue, nil
		},
	},
	{
		Name:      "runtime.printProfilerLines",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			if vm.Profiler == nil {
				return sim.NullValue, fmt.Errorf("there is no profiler in the current context")
			}

			var n int
			if len(args) == 0 {
				n = 50
			} else {
				n = int(args[0].ToInt())
			}

			vm.Profiler.PrintLines(n)
			return sim.NullValue, nil
		},
	},
	{
		Name:      "runtime.printProfilerFunctions",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			if vm.Profiler == nil {
				return sim.NullValue, fmt.Errorf("there is no profiler in the current context")
			}

			var n int
			if len(args) == 0 {
				n = 50
			} else {
				n = int(args[0].ToInt())
			}

			vm.Profiler.PrintFunctions(n)
			return sim.NullValue, nil
		},
	},
	{
		Name: "runtime.newProfiler",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewObject(&profilerObj{sim.NewProfiler()}), nil
		},
	},
	{
		Name:        "runtime.gc",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			runtime.GC()
			return sim.NullValue, nil
		},
	},
	{
		Name:        "panic",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			panic(args[0].String())
		},
	},
	{
		Name: "->runtime.version",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewString(sim.VERSION), nil
		},
	},
	{
		Name: "runtime.typeDefs",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args); err != nil {
				return sim.NullValue, err
			}
			s := sim.TypeDefs()
			return sim.NewString(s), nil
		},
	},
	{
		Name:        "runtime.runFunc",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) == 0 {
				return sim.NullValue, fmt.Errorf("expected at least the function name")
			}

			a := args[0]

			switch a.Type {
			case sim.String:
				return vm.RunFunc(a.String(), args[1:]...)
			case sim.Func:
				return vm.RunFuncIndex(a.ToFunction(), args[1:]...)
			default:
				return sim.NullValue, fmt.Errorf("invalid function argument type, got %v", a.Type)
			}
		},
	},
	{
		Name:        "->runtime.context",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return vm.Context, nil
		},
	},
	{
		Name:        "runtime.setContext",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			vm.Context = args[0]
			return sim.NullValue, nil
		},
	},
	{
		Name:        "runtime.attribute",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			return programAttribute(vm.Program, args[0].String()), nil
		},
	},
	{
		Name:        "runtime.hasAttribute",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			return programHasAttribute(vm.Program, args[0].String()), nil
		},
	},
	{
		Name:        "runtime.resources",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			res := vm.Program.Resources
			if res == nil {
				return sim.NewArray(0), nil
			}

			a := make([]sim.Value, len(res))

			i := 0
			for k := range res {
				a[i] = sim.NewString(k)
				i++
			}

			return sim.NewArrayValues(a), nil
		},
	},
	{
		Name:        "runtime.resource",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			name := args[0].String()

			res := vm.Program.Resources
			if res == nil {
				return sim.NullValue, nil
			}

			v, ok := res[name]
			if !ok {
				return sim.NullValue, nil
			}

			return sim.NewBytes(v), nil
		},
	},
	{
		Name:        "->runtime.hasResources",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			res := vm.Program.Resources
			if len(res) == 0 {
				return sim.FalseValue, nil
			}

			return sim.TrueValue, nil
		},
	},
	{
		Name:        "runtime.setFileSystem",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			fs, ok := args[0].ToObject().(*FileSystemObj)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected a fileSystem, got %s", args[0].TypeName())
			}
			vm.FileSystem = fs.FS
			return sim.NullValue, nil
		},
	},
	{
		Name:      "runtime.newFinalizable",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]

			fin, err := newFinalizable(v, vm)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(fin), nil
		},
	},
	{
		Name:      "defer",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]

			fin, err := newFinalizable(v, vm)
			if err != nil {
				return sim.NullValue, err
			}

			vm.SetFinalizer(fin)
			return sim.NullValue, nil
		},
	},
	{
		Name:      "runtime.setFinalizer",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]

			if v.Type != sim.Object {
				return sim.NullValue, fmt.Errorf("the value is not a finalizer")
			}

			fin, ok := v.ToObject().(sim.Finalizable)
			if !ok {
				return sim.NullValue, fmt.Errorf("the value is not a finalizer")
			}
			vm.SetFinalizer(fin)
			return sim.NullValue, nil
		},
	},
	{
		Name:        "->runtime.OS",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewString(runtime.GOOS), nil
		},
	},
	{
		Name:        "->runtime.executable",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewString(vm.Program.Name), nil
		},
	},
	{
		Name:        "->runtime.entryFile",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(vm.Program.Files) == 0 {
				return sim.NullValue, nil
			}
			return sim.NewString(vm.Program.Files[0]), nil
		},
	},
	{
		Name:        "->runtime.basePath",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewString(vm.Program.BasePath), nil
		},
	},
	{
		Name:        "->runtime.nativeExecutable",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			ex, err := os.Executable()
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewString(ex), nil
		},
	},
	{
		Name:      "runtime.newVM",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := len(args)
			if l == 0 || l > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 params, got %d", l)
			}

			if args[0].Type != sim.Object {
				return sim.NullValue, fmt.Errorf("argument 1 must be a program, got %s", args[0].TypeName())
			}
			p, ok := args[0].ToObject().(*program)
			if !ok {
				return sim.NullValue, fmt.Errorf("argument 1 must be a program, got %s", args[0].TypeName())
			}

			var m *sim.VM

			if l == 1 {
				m = sim.NewVM(p.prog)
			} else {
				switch args[1].Type {
				case sim.Undefined, sim.Null:
					m = sim.NewVM(p.prog)
				case sim.Array:
					m = sim.NewInitializedVM(p.prog, args[1].ToArray())
				default:
					return sim.NullValue, fmt.Errorf("argument 2 must be an array, got %s", args[1].TypeName())
				}
			}

			m.Parent = vm
			m.Stdout = vm.Stdout
			m.Stdin = vm.Stdin
			m.Stderr = vm.Stderr
			m.Now = vm.Now
			m.Profiler = vm.Profiler
			m.Localizer = vm.Localizer
			m.Language = vm.Language
			m.Location = vm.Location
			m.StatsEnabled = vm.StatsEnabled
			m.MaxAllocations = vm.MaxAllocations
			m.MaxFrames = vm.MaxFrames
			m.MaxSteps = vm.MaxSteps
			m.Translations = vm.Translations

			return sim.NewObject(&libVM{m}), nil
		},
	},
	{
		Name:        "->runtime.vm",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewObject(&libVM{vm}), nil
		},
	},
	{
		Name:        "runtime.resetSteps",
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			vm.ResetSteps()
			return sim.NullValue, nil
		},
	},
	{
		Name:      "runtime.stackTrace",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := strings.Join(vm.Stacktrace(), "\n")
			return sim.NewString(s), nil
		},
	},
}
View Source
var SFTP = []sim.NativeFunction{
	{
		Name:      "sftp.newClient",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}

			url := args[0].ToString()

			config, ok := args[1].ToObjectOrNil().(*sshConfig)
			if !ok {
				return sim.NullValue, fmt.Errorf("%v is not a ssh.Config", args[1].TypeName())
			}

			conn, err := ssh.Dial("tcp", url, config.c)
			if err != nil {
				return sim.NullValue, errors.Wrap(err, fmt.Sprintf("dialing to %s", url))
			}

			client, err := sftp.NewClient(conn)
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(&sftpClient{conn: conn, c: client}), nil
		},
	},
}
View Source
var SQL = []sim.NativeFunction{
	{
		Name:        "sql.open",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := len(args)
			if l < 2 || l > 3 {
				return sim.NullValue, fmt.Errorf("expected 2 or 3 parameters, got %d", l)
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("argument 1 must be a string, got %s", args[0].TypeName())
			}

			if !isStringLike(args[1]) {
				return sim.NullValue, fmt.Errorf("argument 2 must be a string, got %s", args[1].TypeName())
			}

			driver := args[0].String()
			connString := args[1].String()

			db, err := dbx.Open(driver, connString, vm.Clock())
			if err != nil {
				return sim.NullValue, err
			}

			db.SetMaxOpenConns(50)
			db.SetMaxIdleConns(10)
			db.SetConnMaxLifetime(2 * time.Minute)
			db.SetConnMaxIdleTime(30 * time.Second)

			if l == 3 {
				if !isStringLike(args[2]) {
					return sim.NullValue, fmt.Errorf("argument 3 must be a string, got %s", args[2].TypeName())
				}
				name := args[2].String()
				if err := validateDatabaseName(name); err != nil {
					return sim.NullValue, err
				}
				db = db.Open(name)
			}

			ldb := newDB(db)
			vm.SetGlobalFinalizer(ldb)
			return sim.NewObject(ldb), nil
		},
	},
	{
		Name:        "sql.setWhitelistFuncs",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Array); err != nil {
				return sim.NullValue, err
			}

			a := args[0].ToArray()

			sqx.ValidFuncs = make([]string, len(a))

			for i, v := range a {
				if v.Type != sim.String {
					return sim.NullValue, fmt.Errorf("invalid value at index %d. It's a %s", i, v.TypeName())
				}
				sqx.ValidFuncs[i] = v.String()
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "sql.getQueries",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			q, err := toQuery(args[0])
			if err != nil {
				return sim.NullValue, err
			}

			queries := sqx.GetQueries(q)

			values := make([]sim.Value, len(queries))

			for i, q := range queries {
				v, err := getQueryObject(q)
				if err != nil {
					return sim.NullValue, err
				}
				values[i] = v
			}

			return sim.NewArrayValues(values), nil
		},
	},
	{
		Name:      "sql.getMainTable",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			q, err := toQuery(args[0])
			if err != nil {
				return sim.NullValue, err
			}

			t := sqx.GetMainTable(q)

			if t == nil {

				return sim.NullValue, nil
			}

			return sim.NewObject(&sqxTable{t}), nil
		},
	},
	{
		Name:      "sql.hasFilterColumn",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object, sim.String); err != nil {
				return sim.NullValue, err
			}

			q, err := toQuery(args[0])
			if err != nil {
				return sim.NullValue, err
			}

			column := args[1].String()

			b := sqx.HasFilterColumn(q, column)
			return sim.NewBool(b), nil
		},
	},
	{
		Name:      "sql.validateSelect",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object, sim.Map); err != nil {
				return sim.NullValue, err
			}

			s, ok := args[0].ToObjectOrNil().(selectQuery)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected argument to be SelectQuery, got %v", args[0].TypeName())
			}

			opt := &sqx.ValidateOptions{}

			optMap := args[1].ToMap().Map

			tablesVal, ok := optMap[sim.NewString("tables")]
			if !ok {
				return sim.NullValue, fmt.Errorf("invalid options: expected tables")
			}

			if tablesVal.Type != sim.Map {
				return sim.NullValue, fmt.Errorf("invalid tables value: %v", tablesVal)
			}

			for k, v := range tablesVal.ToMap().Map {
				if k.Type != sim.String {
					return sim.NullValue, fmt.Errorf("invalid table name: %v", k)
				}

				if v.Type != sim.Array {
					return sim.NullValue, fmt.Errorf("invalid tables value for %s: %v", k, v)
				}

				colValues := v.ToArray()

				cols := make([]string, len(colValues))

				for i, c := range colValues {
					if c.Type != sim.String {
						return sim.NullValue, fmt.Errorf("invalid column value for %s: %v", k, c)
					}
					cols[i] = c.String()
				}

				opt.Tables = append(opt.Tables, &sqx.ValidateTable{
					Name:    k.String(),
					Columns: cols,
				})
			}

			err := sqx.ValidateSelect(s.query, opt)

			return sim.NullValue, err
		},
	},
	{
		Name:      "sql.newSelect",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := selectQuery{&sqx.SelectQuery{}}
			return sim.NewObject(s), nil
		},
	},
	{
		Name:      "sql.parse",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := len(args)
			if l == 0 {
				return sim.NullValue, fmt.Errorf("expected at least one argument, got %d", l)
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected argument to be a string, got %v", args[0].Type)
			}

			v := args[0].String()

			var params []interface{}
			if l > 1 {
				params = getSqlParams(args[1:])
			}

			q, err := sqx.Parse(v, params...)
			if err != nil {
				return sim.NullValue, err
			}

			obj, err := getQueryObject(q)
			if err != nil {
				return sim.NullValue, err
			}
			return obj, nil
		},
	},
	{
		Name:      "sql.select",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := len(args)
			switch l {
			case 0:
				s := selectQuery{&sqx.SelectQuery{}}
				return sim.NewObject(s), nil
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected argument to be a string, got %v", args[0].Type)
			}

			v := args[0].String()
			var params []interface{}
			if l > 1 {
				params = getSqlParams(args[1:])
			}

			q, err := sqx.Select(v, params...)
			if err != nil {
				return sim.NullValue, err
			}

			s := selectQuery{q}
			return sim.NewObject(s), nil
		},
	},
	{
		Name:      "sql.where",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := len(args)
			switch l {
			case 0:
				s := selectQuery{&sqx.SelectQuery{}}
				return sim.NewObject(s), nil
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected argument to be a string, got %v", args[0].Type)
			}

			v := args[0].String()

			var params []interface{}
			if l > 1 {
				params = make([]interface{}, l-1)
				for i, v := range args[1:] {
					params[i] = v.Export(0)
				}
			}

			q, err := sqx.Where(v, params...)
			if err != nil {
				return sim.NullValue, err
			}

			s := selectQuery{q}
			return sim.NewObject(s), nil
		},
	},
	{
		Name:      "sql.newAddFKQuery",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			q := addFKQuery{&sqx.AddFKQuery{}}
			return sim.NewObject(q), nil
		},
	},
	{
		Name:      "sql.parse",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) == 0 {
				return sim.NullValue, fmt.Errorf("expected at least 1 argument")
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected a string, got %v", args[0])
			}

			sQuery := args[0].String()

			var params []interface{}

			if len(args) > 1 {
				params = getSqlParams(args[1:])
			}

			q, err := sqx.Parse("", "", "", sQuery, params)
			if err != nil {
				return sim.NullValue, err
			}

			obj, err := getQueryObject(q)
			if err != nil {
				return sim.NullValue, err
			}

			return obj, nil
		},
	},
}
View Source
var SQLQuery = []sim.NativeFunction{
	{
		Name:      "sql.getQueries",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			q, err := toQuerySQLQuery(args[0])
			if err != nil {
				return sim.NullValue, err
			}

			queries := sqx.GetQueries(q)

			arr := make([]sim.Value, len(queries))
			for i, qq := range queries {
				v, err := getQueryObjectSQLQuery(qq)
				if err != nil {
					return sim.NullValue, err
				}
				arr[i] = v
			}

			return sim.NewArrayValues(arr), nil
		},
	},
	{
		Name:      "sql.getMainTable",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 1, 1); err != nil {
				return sim.NullValue, err
			}

			q, err := toQuerySQLQuery(args[0])
			if err != nil {
				return sim.NullValue, err
			}

			t := sqx.GetMainTable(q)

			if t == nil {

				return sim.NullValue, nil
			}

			return sim.NewObject(&sqxTableQuery{t}), nil
		},
	},
	{
		Name:      "sql.hasFilterColumn",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object, sim.String); err != nil {
				return sim.NullValue, err
			}

			q, err := toQuerySQLQuery(args[0])
			if err != nil {
				return sim.NullValue, err
			}

			column := args[1].String()

			b := sqx.HasFilterColumn(q, column)
			return sim.NewBool(b), nil
		},
	},
	{
		Name:      "sql.validateSelect",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object, sim.Map); err != nil {
				return sim.NullValue, err
			}

			s, ok := args[0].ToObjectOrNil().(selectQuery)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected argument to be SelectQuery, got %v", args[0].TypeName())
			}

			opt := &sqx.ValidateOptions{}

			optMap := args[1].ToMap().Map

			tablesVal, ok := optMap[sim.NewString("tables")]
			if !ok {
				return sim.NullValue, fmt.Errorf("invalid options: expected tables")
			}

			if tablesVal.Type != sim.Map {
				return sim.NullValue, fmt.Errorf("invalid tables value: %v", tablesVal)
			}

			for k, v := range tablesVal.ToMap().Map {
				if k.Type != sim.String {
					return sim.NullValue, fmt.Errorf("invalid table name: %v", k)
				}

				if v.Type != sim.Array {
					return sim.NullValue, fmt.Errorf("invalid tables value for %s: %v", k, v)
				}

				colValues := v.ToArray()

				cols := make([]string, len(colValues))

				for i, c := range colValues {
					if c.Type != sim.String {
						return sim.NullValue, fmt.Errorf("invalid column value for %s: %v", k, c)
					}
					cols[i] = c.String()
				}

				opt.Tables = append(opt.Tables, &sqx.ValidateTable{
					Name:    k.String(),
					Columns: cols,
				})
			}

			err := sqx.ValidateSelect(s.query, opt)

			return sim.NullValue, err
		},
	},
	{
		Name:      "sql.newSelect",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := selectQuery{&sqx.SelectQuery{}}
			return sim.NewObject(s), nil
		},
	},
	{
		Name:      "sql.parse",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) == 0 {
				return sim.NullValue, fmt.Errorf("expected at least 1 argument")
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected a string, got %v", args[0])
			}

			sQuery := args[0].String()

			var params []interface{}

			if len(args) > 1 {
				params = getSqlParamsSQLQuery(args[1:])
			}

			q, err := sqx.Parse("", "", "", sQuery, params)
			if err != nil {
				return sim.NullValue, err
			}

			return getQueryObjectSQLQuery(q)
		},
	},
	{
		Name:      "sql.select",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) == 0 {
				return sim.NullValue, fmt.Errorf("expected at least 1 argument")
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected a string, got %v", args[0])
			}

			sQuery := args[0].String()

			var params []interface{}

			if len(args) > 1 {
				params = getSqlParamsSQLQuery(args[1:])
			}

			q, err := sqx.Parse("", "", "", sQuery, params)
			if err != nil {
				return sim.NullValue, err
			}

			if selectQ, ok := q.(*sqx.SelectQuery); ok {
				return sim.NewObject(selectQuery{selectQ}), nil
			}

			return sim.NullValue, fmt.Errorf("query is not a SELECT statement")
		},
	},
	{
		Name:      "sql.where",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) == 0 {
				return sim.NullValue, fmt.Errorf("expected at least 1 argument")
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected a string, got %v", args[0])
			}

			whereClause := args[0].String()

			var params []interface{}
			if len(args) > 1 {
				params = getSqlParamsSQLQuery(args[1:])
			}

			sqlStr := "SELECT * FROM dual WHERE " + whereClause
			q, err := sqx.Parse("", "", "", sqlStr, params)
			if err != nil {
				return sim.NullValue, err
			}

			if selectQ, ok := q.(*sqx.SelectQuery); ok {
				return sim.NewObject(selectQuery{selectQ}), nil
			}

			return sim.NullValue, fmt.Errorf("failed to create WHERE query")
		},
	},
	{
		Name:      "sql.orderBy",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 1 {
				return sim.NullValue, fmt.Errorf("expected 1 argument, got %d", len(args))
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected a string, got %v", args[0])
			}

			orderByClause := args[0].String()

			sqlStr := "SELECT * FROM dual ORDER BY " + orderByClause
			q, err := sqx.Parse(sqlStr)
			if err != nil {
				return sim.NullValue, err
			}

			if selectQ, ok := q.(*sqx.SelectQuery); ok {
				return sim.NewObject(selectQuery{selectQ}), nil
			}

			return sim.NullValue, fmt.Errorf("failed to create ORDER BY query")
		},
	},
	{
		Name:      "sql.newAddFKQuery",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := addFKQuery{&sqx.AddFKQuery{}}
			return sim.NewObject(a), nil
		},
	},
}
View Source
var SSH = []sim.NativeFunction{
	{
		Name:      "ssh.newConfig",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			c := &ssh.ClientConfig{
				Timeout:         30 * time.Second,
				HostKeyCallback: ssh.InsecureIgnoreHostKey(),
			}
			return sim.NewObject(&sshConfig{c}), nil
		},
	},
	{
		Name:      "ssh.newClient",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}

			url := args[0].ToString()
			config, ok := args[1].ToObjectOrNil().(*sshConfig)
			if !ok {
				return sim.NullValue, fmt.Errorf("%v is not a ssh.Config", args[1].TypeName())
			}

			client, err := ssh.Dial("tcp", url, config.c)
			if err != nil {
				return sim.NullValue, fmt.Errorf("failed to connect to %s: %v", url, err)
			}

			return sim.NewObject(&sshClient{c: client}), nil
		},
	},
}
View Source
var STMP = []sim.NativeFunction{
	{
		Name:      "smtp.newMessage",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewObject(&SmtMessage{}), nil
		},
	},
	{
		Name:        "smtp.send",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {

			if len(args) < 5 || len(args) > 7 {
				return sim.NullValue, fmt.Errorf("expected 5-7 params, got %d", len(args))
			}

			msg, ok := args[0].ToObject().(*SmtMessage)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected a mail message, got %s", args[0].TypeName())
			}

			user := args[1].String()
			password := args[2].String()
			host := args[3].String()
			port := int(args[4].ToInt())

			var skipVerify bool = false
			var timeout time.Duration = 30 * time.Second // timeout por defecto

			switch len(args) {
			case 5:

			case 6:
				skipVerify = toBoolOrFalse(args[5])
			case 7:
				skipVerify = toBoolOrFalse(args[5])

				switch args[6].Type {
				case sim.Int:
					timeout = time.Duration(args[6].ToInt()) * time.Second
				case sim.Null, sim.Undefined:
				default:
					return sim.NullValue, fmt.Errorf("argument 7 must be integer (timeout in seconds)")
				}
			}

			err := msg.SendWithTimeout(user, password, host, port, skipVerify, timeout)
			return sim.NullValue, err
		},
	},
}
View Source
var Secure = []sim.NativeFunction{
	{
		Name:        "secure.newObject",
		Arguments:   -1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			ln := len(args)
			if ln < 2 || ln > 3 {
				return sim.NullValue, fmt.Errorf("expected 2 or 3 arguments, got %d", ln)
			}

			if args[0].Type != sim.Bool {
				return sim.NullValue, fmt.Errorf("expected argument 1 to be bool, got %s", args[0].Type)
			}

			if args[1].Type != sim.Bool {
				return sim.NullValue, fmt.Errorf("expected argument 2 to be bool, got %s", args[1].Type)
			}
			p := &SecureObject{
				values: make(map[string]sim.Value),
				read:   args[0].ToBool(),
				write:  args[1].ToBool(),
			}

			if ln == 3 {
				for k, v := range args[2].ToMap().Map {
					p.values[k.String()] = v
				}
			}

			return sim.NewObject(p), nil
		},
	},
}
View Source
var Strconv = []sim.NativeFunction{
	{
		Name:      "strconv.formatRef",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int, sim.Int); err != nil {
				return sim.NullValue, err
			}

			s := EncodeCustomBase34(uint64(args[0].ToInt()))

			var size int
			if len(args) > 1 {
				size = int(args[1].ToInt())
			} else {
				size = 15
			}

			if size > 0 {
				s += customBase34Delimiter + RandomAlphanumeric(size)
			}

			return sim.NewString(strings.ToUpper(s)), nil
		},
	},
	{
		Name:      "strconv.parseRef",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			s := args[0].String()

			i := strings.IndexRune(s, 'L')
			if i != -1 {
				s = s[:i]
			}

			v := DecodeCustomBase34(s)
			return sim.NewInt64(int64(v)), nil
		},
	},
	{
		Name:      "strconv.formatInt",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int, sim.Int); err != nil {
				return sim.NullValue, err
			}
			v := strconv.FormatInt(args[0].ToInt(), int(args[1].ToInt()))
			return sim.NewString(v), nil
		},
	},
	{
		Name:      "strconv.parseInt",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.Int, sim.Int); err != nil {
				return sim.NullValue, err
			}

			s := args[0].String()

			s = strings.Trim(s, " ")
			if len(s) > 1 {
				s = strings.TrimLeft(s, "0")
			}

			v, err := strconv.ParseInt(s, int(args[1].ToInt()), int(args[2].ToInt()))
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewInt64(v), nil
		},
	},
	{
		Name:      "strconv.formatCustomBase34",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}
			v := EncodeCustomBase34(uint64(args[0].ToInt()))
			return sim.NewString(v), nil
		},
	},
	{
		Name:      "strconv.parseCustomBase34",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			v := DecodeCustomBase34(args[0].String())
			return sim.NewInt64(int64(v)), nil
		},
	},
}
View Source
var Strings = []sim.NativeFunction{
	{
		Name:      "String",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int, sim.Float, sim.String, sim.Bool); err != nil {
				return sim.NullValue, err
			}

			if len(args) == 0 {
				return sim.NewString(""), nil
			}

			arg := args[0]
			switch arg.Type {
			case sim.String:
				return args[0], nil
			default:
				return sim.NewString(args[0].String()), nil
			}
		},
	},
	{
		Name:      "String.fromCharCode",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var code int64
			switch args[0].Type {
			case sim.Int:
				code = args[0].ToInt()
			case sim.Float:
				code = int64(args[0].ToFloat())
			default:
				return sim.NullValue, fmt.Errorf("expected number, got %s", args[0].TypeName())
			}

			code = code & 0xFFFF
			return sim.NewString(string(rune(code))), nil
		},
	},
	{
		Name:      "strings.sanitize",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.Bool); err != nil {
				return sim.NullValue, err
			}

			if err := ValidateArgRange(args, 1, 2); err != nil {
				return sim.NullValue, err
			}

			s := args[0].String()

			var dashes bool
			if len(args) == 2 {
				dashes = args[1].ToBool()
			}

			var lastDash bool
			buf := make([]rune, 0, len(s))
			for _, r := range s {
				if isAlphanumeric(r, 1) {
					buf = append(buf, r)
					lastDash = false
				} else {
					if dashes && !lastDash {
						buf = append(buf, '-')
					}
					lastDash = true
				}
			}

			return sim.NewString(string(buf)), nil
		},
	},
	{
		Name:      "strings.newReader",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			r := strings.NewReader(args[0].String())

			return sim.NewObject(&reader{r}), nil
		},
	},
	{
		Name:      "String.prototype.runeAt",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			if a.Type != sim.Int {
				return sim.NullValue, fmt.Errorf("expected int, got %s", a.Type)
			}

			i := int(a.ToInt())

			if i < 0 {
				return sim.NullValue, vm.NewError("Index out of range in string")
			}

			v := utf8string.NewString(this.String())

			if int(i) >= v.RuneCount() {
				return sim.NullValue, vm.NewError("Index out of range in string")
			}

			return sim.NewRune(v.At(int(i))), nil
		},
	},
	{
		Name:      "strings.equalFold",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			b := args[1]

			switch a.Type {
			case sim.Null, sim.Undefined:
				switch b.Type {
				case sim.Null, sim.Undefined:
					return sim.TrueValue, nil
				case sim.String:
					return sim.FalseValue, nil
				default:
					return sim.NullValue, fmt.Errorf("expected argument 2 to be string got %v", b.Type)
				}
			case sim.String:
			default:
				return sim.NullValue, fmt.Errorf("expected argument 1 to be string got %v", a.Type)
			}

			switch b.Type {
			case sim.Null, sim.Undefined:

				return sim.FalseValue, nil
			case sim.String:
			default:
				return sim.NullValue, fmt.Errorf("expected argument 2 to be string got %v", b.Type)
			}

			eq := strings.EqualFold(a.String(), b.String())
			return sim.NewBool(eq), nil
		},
	},
	{
		Name:      "strings.isIdent",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]
			switch v.Type {
			case sim.String, sim.Rune:
			default:
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", v.TypeName())
			}

			b := IsIdent(v.String())
			return sim.NewBool(b), nil
		},
	},
	{
		Name:      "strings.isAlphanumeric",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]
			switch v.Type {
			case sim.String, sim.Rune:
			default:
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", v.TypeName())
			}
			b := IsAlphanumeric(v.String())
			return sim.NewBool(b), nil
		},
	},
	{
		Name:      "strings.isAlphanumericIdent",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]
			switch v.Type {
			case sim.String, sim.Rune:
			default:
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", v.TypeName())
			}
			b := IsAlphanumericIdent(v.String())
			return sim.NewBool(b), nil
		},
	},
	{
		Name:      "strings.isNumeric",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]
			switch v.Type {
			case sim.String, sim.Rune:
			case sim.Int, sim.Float:
				return sim.TrueValue, nil
			default:
				return sim.FalseValue, nil
			}

			b := IsNumeric(v.String())
			return sim.NewBool(b), nil
		},
	},
	{
		Name:      "strings.isEmpty",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]
			switch v.Type {
			case sim.Null, sim.Undefined:
				return sim.TrueValue, nil
			case sim.String, sim.Rune:
				return sim.NewBool(v.String() == ""), nil
			default:
				return sim.FalseValue, nil
			}
		},
	},
	{
		Name:      "strings.isChar",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]
			switch v.Type {
			case sim.String, sim.Rune:
			default:
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}

			s := v.String()
			if len(s) != 1 {
				return sim.FalseValue, nil
			}

			r := rune(s[0])
			if 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' {
				return sim.TrueValue, nil
			}

			return sim.FalseValue, nil
		},
	},
	{
		Name:      "strings.isDigit",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			v := args[0]
			switch v.Type {
			case sim.String, sim.Rune:
			default:
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}

			s := v.String()
			if len(s) != 1 {
				return sim.FalseValue, nil
			}

			r := rune(s[0])
			if '0' <= r && r <= '9' {
				return sim.TrueValue, nil
			}

			return sim.FalseValue, nil
		},
	},
	{
		Name:      "strings.sort",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if args[0].Type != sim.Array {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be array, got %s", args[0].TypeName())
			}

			a := args[0].ToArray()

			s := make([]string, len(a))

			for i, v := range a {
				s[i] = v.String()
			}

			sort.Strings(s)

			for i, v := range s {
				a[i] = sim.NewString(v)
			}

			return sim.NullValue, nil
		},
	},
	{
		Name:      "strings.repeat",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String, sim.Int); err != nil {
				return sim.NullValue, err
			}

			a := args[0].String()
			b := int(args[1].ToInt())

			values := make([]string, b)

			for i := 0; i < b; i++ {
				values[i] = a
			}

			s := strings.Join(values, "")
			return sim.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.replaceRegex",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			exp := args[0].String()
			repl := args[1].String()
			s := this.String()
			r, err := regexp.Compile(exp)
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewString(r.ReplaceAllString(s, repl)), nil
		},
	},
	{
		Name: "String.prototype.toLowerCase",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := this.String()
			return sim.NewString(strings.ToLower(s)), nil
		},
	},
	{
		Name: "String.prototype.toUpperCase",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := this.String()
			return sim.NewString(strings.ToUpper(s)), nil
		},
	},
	{
		Name: "String.prototype.toTitle",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := this.String()
			if len(s) > 0 {
				s = strings.ToUpper(s[:1]) + s[1:]
			}
			return sim.NewString(s), nil
		},
	},
	{
		Name: "String.prototype.toUntitle",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := this.String()
			if len(s) > 0 {
				s = strings.ToLower(s[:1]) + s[1:]
			}
			return sim.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.fields",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := this.String()

			parts := strings.Fields(s)
			res := make([]sim.Value, len(parts))

			for i, v := range parts {
				res[i] = sim.NewString(v)
			}
			return sim.NewArrayValues(res), nil
		},
	},
	{
		Name:      "String.prototype.trim",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var cutset string
			switch len(args) {
			case 0:
				cutset = " \t\r\n"
			case 1:
				cutset = args[0].String()
			default:
				return sim.NullValue, fmt.Errorf("expected 0 or 1 arguments, got %d", len(args))
			}
			s := this.String()
			return sim.NewString(strings.Trim(s, cutset)), nil
		},
	},
	{
		Name:      "String.prototype.trimLeft",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var cutset string
			switch len(args) {
			case 0:
				cutset = " \t\r\n"
			case 1:
				cutset = args[0].String()
			default:
				return sim.NullValue, fmt.Errorf("expected 0 or 1 arguments, got %d", len(args))
			}
			s := this.String()
			return sim.NewString(strings.TrimLeft(s, cutset)), nil
		},
	},
	{
		Name:      "String.prototype.trimRight",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var cutset string
			switch len(args) {
			case 0:
				cutset = " \t\r\n"
			case 1:
				cutset = args[0].String()
			default:
				return sim.NullValue, fmt.Errorf("expected 0 or 1 arguments, got %d", len(args))
			}
			s := this.String()
			return sim.NewString(strings.TrimRight(s, cutset)), nil
		},
	},
	{
		Name:      "String.prototype.trimPrefix",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			s := this.String()
			prefix := args[0].String()
			s = strings.TrimPrefix(s, prefix)
			return sim.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.trimSuffix",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			s := this.String()
			prefix := args[0].String()
			s = strings.TrimSuffix(s, prefix)
			return sim.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.substring",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := this.String()

			switch len(args) {
			case 1:
				v1 := args[0]
				if v1.Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected int, got %s", v1.Type)
				}
				a := int(v1.ToInt())
				if a < 0 || a > len(s) {
					return sim.NullValue, fmt.Errorf("index out of range: %d of %d", a, len(s))
				}
				return sim.NewString(s[a:]), nil
			case 2:
				v1 := args[0]
				if v1.Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected int, got %s", v1.Type)
				}
				v2 := args[1]
				if v2.Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected int, got %s", v2.Type)
				}
				l := len(s)
				a := int(v1.ToInt())
				b := int(v2.ToInt())
				if a < 0 || a > l {
					return sim.NullValue, fmt.Errorf("start out of range")
				}
				if b < a || b > l {
					return sim.NullValue, fmt.Errorf("end out of range")
				}
				return sim.NewString(s[a:b]), nil
			}

			return sim.NullValue, fmt.Errorf("expected 1 or 2 parameters")
		},
	},
	{
		Name:      "String.prototype.runeSubstring",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := this.String()

			switch len(args) {
			case 1:
				v1 := args[0]
				if v1.Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected int, got %s", v1.Type)
				}
				a := int(v1.ToInt())
				if a < 0 || a > len(s) {
					return sim.NullValue, fmt.Errorf("index out of range: %d of %d", a, len(s))
				}
				return sim.NewString(substring(s, a, -1)), nil
			case 2:
				v1 := args[0]
				if v1.Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected int, got %s", v1.Type)
				}
				v2 := args[1]
				if v2.Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected int, got %s", v2.Type)
				}
				l := len(s)
				a := int(v1.ToInt())
				b := int(v2.ToInt())
				if a < 0 || a > l {
					return sim.NullValue, fmt.Errorf("start out of range")
				}
				if b < a || b > l {
					return sim.NullValue, fmt.Errorf("end out of range")
				}
				return sim.NewString(substring(s, a, b)), nil
			}

			return sim.NullValue, fmt.Errorf("expected 1 or 2 parameters")
		},
	},
	{
		Name:      "String.prototype.take",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if args[0].Type != sim.Int {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be int, got %s", args[0].TypeName())
			}

			s := this.String()
			i := int(args[0].ToInt())

			if i < 0 {
				return sim.NullValue, fmt.Errorf("index out of range: %d", i)
			}
			if len(s) > i {
				s = s[:i]
			}
			return sim.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.startsWith",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			v := args[0].String()
			s := this.String()
			return sim.NewBool(strings.HasPrefix(s, v)), nil
		},
	},
	{
		Name:      "String.prototype.endsWith",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			v := args[0].String()
			s := this.String()
			return sim.NewBool(strings.HasSuffix(s, v)), nil
		},
	}, {
		Name:      "String.prototype.cut",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			ln := len(args)

			s := this.String()
			var start int
			if len(args) > 1 {
				start = int(args[1].ToInt())
				if start < 0 || start > len(s) {
					res := make([]sim.Value, 2)
					res[0] = sim.NewString(s)
					res[1] = sim.NewString("")
					return sim.NewArrayValues(res), nil
				}
				s = s[start:]
			}

			if ln > 1 {
				if args[1].Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", args[1].TypeName())
				}
			}

			var width int
			var index int

			switch args[0].Type {
			case sim.String:
				separator := args[0].String()
				width = len(separator)
				index = strings.Index(s, separator) + start
			case sim.Rune:
				separator := args[0].ToRune()
				width = runewidth.RuneWidth(separator)
				if width == 0 {
					width = 1
				}
				index = strings.IndexRune(s, separator) + start
			default:
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}

			if index == -1 {
				res := make([]sim.Value, 2)
				res[0] = sim.NewString(s)
				res[1] = sim.NewString("")
				return sim.NewArrayValues(res), nil
			}

			res := make([]sim.Value, 2)
			res[0] = sim.NewString(s[0:index])
			res[1] = sim.NewString(s[index+width:])
			return sim.NewArrayValues(res), nil
		},
	},
	{
		Name:      "String.prototype.indexOfRelative",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {

			s := this.String()
			var i int
			if len(args) > 1 {
				vStart := args[1]
				if vStart.Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", vStart.TypeName())
				}
				i = int(vStart.ToInt())
				if i < 0 || i > len(s) {
					return sim.NullValue, fmt.Errorf("index out of range")
				}
				s = s[i:]
			}

			switch args[0].Type {
			case sim.String:
				return sim.NewInt(strings.Index(s, args[0].String())), nil
			case sim.Rune:
				return sim.NewInt(strings.IndexRune(s, args[0].ToRune())), nil
			default:
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
		},
	},
	{
		Name:      "String.prototype.indexOf",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := this.String()
			searchStr := ""
			fromIndex := 0

			switch args[0].Type {
			case sim.String:
				searchStr = args[0].String()
			case sim.Rune:
				searchStr = string(args[0].ToRune())
			default:
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}

			if len(args) > 1 {
				vStart := args[1]
				if vStart.Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", vStart.TypeName())
				}
				fromIndex = int(vStart.ToInt())
				if fromIndex < 0 {
					fromIndex = 0
				}
			}

			if fromIndex >= len(s) {
				return sim.NewInt(-1), nil
			}

			pos := strings.Index(s[fromIndex:], searchStr)
			if pos == -1 {
				return sim.NewInt(-1), nil
			}

			return sim.NewInt(pos + fromIndex), nil
		},
	},
	{
		Name:      "String.prototype.lastIndexOf",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			ln := len(args)

			if ln > 0 {
				if !isStringLike(args[0]) {
					return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
				}
			}

			if ln > 1 {
				if args[1].Type != sim.Int {
					return sim.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", args[1].TypeName())
				}
			}

			sep := args[0].String()
			s := this.String()

			if len(args) > 1 {
				i := int(args[1].ToInt())
				if i > len(s) {
					return sim.NullValue, fmt.Errorf("index out of range")
				}
				s = s[i:]
			}
			return sim.NewInt(strings.LastIndex(s, sep)), nil
		},
	},
	{
		Name:      "String.prototype.contains",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			switch args[0].Type {
			case sim.String, sim.Rune:
			default:
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}

			sep := args[0].String()
			s := this.String()
			return sim.NewBool(strings.Contains(s, sep)), nil
		},
	},
	{
		Name:      "String.prototype.rightPad",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			if args[1].Type != sim.Int {
				return sim.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", args[1].TypeName())
			}
			pad := args[0].String()
			if len(pad) != 1 {
				return sim.NullValue, fmt.Errorf("invalid pad size. Must be one character")
			}
			total := int(args[1].ToInt())
			s := this.String()
			return sim.NewString(rightPad(s, rune(pad[0]), total)), nil
		},
	},
	{
		Name:      "String.prototype.leftPad",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			if args[1].Type != sim.Int {
				return sim.NullValue, fmt.Errorf("expected arg 2 to be int, got %s", args[1].TypeName())
			}

			pad := args[0].String()
			if len(pad) != 1 {
				return sim.NullValue, fmt.Errorf("invalid pad size. Must be one character")
			}
			total := int(args[1].ToInt())
			s := this.String()
			return sim.NewString(leftPad(s, rune(pad[0]), total)), nil
		},
	},
	{
		Name:      "String.prototype.equalFold",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be string, got %s", args[0].TypeName())
			}
			eq := strings.EqualFold(this.String(), args[0].String())
			return sim.NewBool(eq), nil
		},
	},

	{
		Name:      "String.prototype.repeat",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			s := this.String()
			count := int(args[0].ToInt())

			if count < 0 {
				return sim.NullValue, fmt.Errorf("repeat count must be non-negative")
			}

			return sim.NewString(strings.Repeat(s, count)), nil
		},
	},
	{
		Name:      "String.prototype.at",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			s := this.String()
			index := int(args[0].ToInt())

			runes := []rune(s)
			length := len(runes)

			if index < 0 {
				index = length + index
			}

			if index < 0 || index >= length {
				return sim.NullValue, nil
			}

			return sim.NewString(string(runes[index])), nil
		},
	},
	{
		Name:      "String.prototype.charCodeAt",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			s := this.String()
			index := int(args[0].ToInt())

			if index < 0 || index >= len(s) {
				return sim.NewFloat(math.NaN()), nil
			}

			return sim.NewInt64(int64(s[index])), nil
		},
	},
	{
		Name:      "String.prototype.codePointAt",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			s := this.String()
			index := int(args[0].ToInt())

			if index < 0 || index >= len(s) {
				return sim.NullValue, nil
			}

			r, _ := utf8.DecodeRuneInString(s[index:])
			if r == utf8.RuneError {
				return sim.NullValue, nil
			}

			return sim.NewInt64(int64(r)), nil
		},
	},
	{
		Name:      "String.prototype.includes",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) < 1 || len(args) > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 arguments, got %d", len(args))
			}

			s := this.String()
			searchString := args[0].String()

			// Segundo parámetro opcional: posición desde donde empezar a buscar
			var startPos int
			if len(args) == 2 {
				startPos = int(args[1].ToInt())
				if startPos < 0 {
					startPos = 0
				}
				if startPos >= len(s) {
					return sim.FalseValue, nil
				}
				s = s[startPos:]
			}

			return sim.NewBool(strings.Contains(s, searchString)), nil
		},
	},
	{
		Name:      "String.prototype.slice",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) < 1 || len(args) > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 arguments, got %d", len(args))
			}

			s := this.String()
			runes := []rune(s)
			length := len(runes)

			start := int(args[0].ToInt())
			if start < 0 {
				start = length + start
			}
			if start < 0 {
				start = 0
			}
			if start > length {
				start = length
			}

			end := length
			if len(args) == 2 {
				end = int(args[1].ToInt())
				if end < 0 {
					end = length + end
				}
				if end < 0 {
					end = 0
				}
				if end > length {
					end = length
				}
			}

			if start >= end {
				return sim.NewString(""), nil
			}

			return sim.NewString(string(runes[start:end])), nil
		},
	},
	{
		Name:      "String.prototype.concat",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			s := this.String()

			for _, arg := range args {
				s += arg.String()
			}

			return sim.NewString(s), nil
		},
	},
	{
		Name:      "String.prototype.trimStart",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var cutset string
			switch len(args) {
			case 0:
				cutset = " \t\r\n"
			case 1:
				cutset = args[0].String()
			default:
				return sim.NullValue, fmt.Errorf("expected 0 or 1 arguments, got %d", len(args))
			}
			s := this.String()
			return sim.NewString(strings.TrimLeft(s, cutset)), nil
		},
	},
	{
		Name:      "String.prototype.trimEnd",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var cutset string
			switch len(args) {
			case 0:
				cutset = " \t\r\n"
			case 1:
				cutset = args[0].String()
			default:
				return sim.NullValue, fmt.Errorf("expected 0 or 1 arguments, got %d", len(args))
			}
			s := this.String()
			return sim.NewString(strings.TrimRight(s, cutset)), nil
		},
	},
	{
		Name:      "String.prototype.localeCompare",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) < 1 {
				return sim.NullValue, fmt.Errorf("expected at least 1 argument, got %d", len(args))
			}

			s1 := this.String()
			s2 := args[0].String()

			if s1 < s2 {
				return sim.NewInt(-1), nil
			} else if s1 > s2 {
				return sim.NewInt(1), nil
			}
			return sim.NewInt(0), nil
		},
	},
	{
		Name:      "String.prototype.match",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 1 {
				return sim.NullValue, fmt.Errorf("expected 1 argument, got %d", len(args))
			}

			text := this.String()

			if regexWrapper, ok := args[0].ToObjectOrNil().(*jsRegExpWrapper); ok {

				pattern := "/" + regexWrapper.re.Source() + "/" + regexWrapper.re.Flags()
				result := jsregex.Match(text, pattern)

				if result == nil {
					return sim.NullValue, nil
				}

				values := make([]sim.Value, len(result))
				for i, s := range result {
					values[i] = sim.NewString(s)
				}
				return sim.NewArrayValues(values), nil
			} else {

				pattern := args[0].String()
				result := jsregex.Match(text, pattern)

				if result == nil {
					return sim.NullValue, nil
				}

				values := make([]sim.Value, len(result))
				for i, s := range result {
					values[i] = sim.NewString(s)
				}
				return sim.NewArrayValues(values), nil
			}
		},
	},
	{
		Name:      "String.prototype.search",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 1 {
				return sim.NullValue, fmt.Errorf("expected 1 argument, got %d", len(args))
			}

			text := this.String()

			if regexWrapper, ok := args[0].ToObjectOrNil().(*jsRegExpWrapper); ok {

				pattern := "/" + regexWrapper.re.Source() + "/" + regexWrapper.re.Flags()
				result := jsregex.Search(text, pattern)
				return sim.NewInt(result), nil
			} else {

				pattern := args[0].String()
				result := jsregex.Search(text, pattern)
				return sim.NewInt(result), nil
			}
		},
	},
	{
		Name:      "String.prototype.replace",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 2 {
				return sim.NullValue, fmt.Errorf("expected 2 arguments, got %d", len(args))
			}

			text := this.String()
			replacement := args[1].String()

			if regexWrapper, ok := args[0].ToObjectOrNil().(*jsRegExpWrapper); ok {

				pattern := "/" + regexWrapper.re.Source() + "/" + regexWrapper.re.Flags()
				result := jsregex.Replace(text, pattern, replacement)
				return sim.NewString(result), nil
			} else {

				oldStr := args[0].String()
				result := strings.Replace(text, oldStr, replacement, 1)
				return sim.NewString(result), nil
			}
		},
	},
	{
		Name:      "String.prototype.replaceAll",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 2 {
				return sim.NullValue, fmt.Errorf("expected 2 arguments, got %d", len(args))
			}

			text := this.String()
			replacement := args[1].String()

			if regexWrapper, ok := args[0].ToObjectOrNil().(*jsRegExpWrapper); ok {

				pattern := "/" + regexWrapper.re.Source() + "/" + regexWrapper.re.Flags()
				result := jsregex.ReplaceAll(text, pattern, replacement)
				return sim.NewString(result), nil
			} else {

				oldStr := args[0].String()
				result := strings.ReplaceAll(text, oldStr, replacement)
				return sim.NewString(result), nil
			}
		},
	},
	{
		Name:      "String.prototype.splitClean",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			sep := args[0].String()

			s := this.String()

			parts := Split(s, sep)
			res := make([]sim.Value, len(parts))

			for i, v := range parts {
				res[i] = sim.NewString(v)
			}
			return sim.NewArrayValues(res), nil
		},
	},
	{
		Name:      "String.prototype.split",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) < 1 || len(args) > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 arguments, got %d", len(args))
			}

			text := this.String()

			if regexWrapper, ok := args[0].ToObjectOrNil().(*jsRegExpWrapper); ok {

				pattern := "/" + regexWrapper.re.Source() + "/" + regexWrapper.re.Flags()

				var result []string
				if len(args) == 2 {
					limit := int(args[1].ToInt())
					result = jsregex.Split(text, pattern, limit)
				} else {
					result = jsregex.Split(text, pattern)
				}

				values := make([]sim.Value, len(result))
				for i, s := range result {
					values[i] = sim.NewString(s)
				}
				return sim.NewArrayValues(values), nil
			} else {

				sep := args[0].String()

				if sep == "" {

					runes := []rune(text)
					values := make([]sim.Value, len(runes))
					for i, r := range runes {
						values[i] = sim.NewString(string(r))
					}
					return sim.NewArrayValues(values), nil
				}

				parts := strings.Split(text, sep)

				if len(args) == 2 {
					limit := int(args[1].ToInt())
					if limit > 0 && len(parts) > limit {
						parts = parts[:limit]
					}
				}

				values := make([]sim.Value, len(parts))
				for i, s := range parts {
					values[i] = sim.NewString(s)
				}
				return sim.NewArrayValues(values), nil
			}
		},
	},
	{
		Name:      "String.prototype.matchAll",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 1 {
				return sim.NullValue, fmt.Errorf("expected 1 argument, got %d", len(args))
			}

			text := this.String()

			if regexWrapper, ok := args[0].ToObjectOrNil().(*jsRegExpWrapper); ok {

				pattern := "/" + regexWrapper.re.Source() + "/" + regexWrapper.re.Flags()
				result := jsregex.MatchAll(text, pattern)

				if result == nil {
					return sim.NullValue, nil
				}

				values := make([]sim.Value, len(result))
				for i, match := range result {
					matchValues := make([]sim.Value, len(match))
					for j, s := range match {
						matchValues[j] = sim.NewString(s)
					}
					values[i] = sim.NewArrayValues(matchValues)
				}
				return sim.NewArrayValues(values), nil
			} else {

				pattern := args[0].String()
				result := jsregex.MatchAll(text, pattern)

				if result == nil {
					return sim.NullValue, nil
				}

				values := make([]sim.Value, len(result))
				for i, match := range result {
					matchValues := make([]sim.Value, len(match))
					for j, s := range match {
						matchValues[j] = sim.NewString(s)
					}
					values[i] = sim.NewArrayValues(matchValues)
				}
				return sim.NewArrayValues(values), nil
			}
		},
	},
}
View Source
var Sunrise = []sim.NativeFunction{
	{
		Name:      "astro.sunRiseSet",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Float, sim.Float, sim.Object); err != nil {
				return sim.NullValue, err
			}

			lat := args[0].ToFloat()
			long := args[1].ToFloat()

			t, ok := args[2].ToObject().(TimeObj)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}

			d := time.Time(t)

			rise, set := sunrise.SunriseSunset(lat, long, d.Year(), d.Month(), d.Day())

			loc := GetLocation(vm)

			m := make(map[sim.Value]sim.Value, 2)

			m[sim.NewString("rise")] = sim.NewObject(TimeObj(rise.In(loc)))
			m[sim.NewString("set")] = sim.NewObject(TimeObj(set.In(loc)))

			return sim.NewMapValues(m, false), nil

		},
	},
}
View Source
var Sync = []sim.NativeFunction{
	{
		Name:        "sync.withDeadline",
		Arguments:   2,
		Permissions: []string{"sync"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d, err := ToDuration(args[0])
			if err != nil {
				return sim.NullValue, err
			}

			v := args[1]
			switch v.Type {
			case sim.Func:
			case sim.Object:
			default:
				return sim.NullValue, fmt.Errorf("%v is not a function", v.TypeName())
			}

			err = WithDeadline(d, func(dl *Deadline) error {
				obj := sim.NewObject(dl)
				return runAsyncFuncOrClosure(vm, v, obj)
			})

			return sim.NullValue, err
		},
	},
	{
		Name:        "sync.newWaitGroup",
		Arguments:   -1,
		Permissions: []string{"sync"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			wg := &waitGroup{w: &sync.WaitGroup{}}

			if len(args) == 1 {
				concurrency := int(args[0].ToInt())
				wg.limit = make(chan bool, concurrency)
			}

			return sim.NewObject(wg), nil
		},
	},
	{
		Name:        "sync.newChannel",
		Arguments:   -1,
		Permissions: []string{"sync"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			var ch chan sim.Value
			var b int
			if len(args) > 0 {
				b = int(args[0].ToInt())
				ch = make(chan sim.Value, b)
			} else {
				ch = make(chan sim.Value)
			}

			c := &channel{buffer: b, c: ch}
			return sim.NewObject(c), nil
		},
	},
	{
		Name:        "sync.select",
		Arguments:   -1,
		Permissions: []string{"sync"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			argLen := len(args)
			if argLen == 0 || argLen > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 args, got %d", argLen)
			}

			a := args[0]
			if a.Type != sim.Array {
				return sim.NullValue, fmt.Errorf("expected arg 1 to be an array of channels, got %s", a.TypeName())
			}

			chans := a.ToArray()
			l := len(chans)
			cases := make([]reflect.SelectCase, l)
			for i, c := range chans {
				ch := c.ToObjectOrNil().(*channel)
				if ch == nil {
					return sim.NullValue, fmt.Errorf("invalid channel at index %d", i)
				}
				cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch.c)}
			}

			if argLen == 2 {
				b := args[1]
				if b.Type != sim.Bool {
					return sim.NullValue, fmt.Errorf("expected arg 2 to be a bool, got %s", b.TypeName())
				}
				if b.ToBool() {
					cases = append(cases, reflect.SelectCase{Dir: reflect.SelectDefault})
				}
			}

			i, value, ok := reflect.Select(cases)

			m := make(map[sim.Value]sim.Value, 3)
			m[sim.NewString("index")] = sim.NewInt(i)

			if value.IsValid() {
				m[sim.NewString("value")] = value.Interface().(sim.Value)
			}

			m[sim.NewString("receivedOK")] = sim.NewBool(ok)

			return sim.NewMapValues(m, true), nil
		},
	},
	{
		Name:        "sync.newMutex",
		Arguments:   0,
		Permissions: []string{"sync"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			m := &mutex{mutex: sync.Mutex{}}
			return sim.NewObject(m), nil
		},
	},
}
View Source
var TLS = []sim.NativeFunction{
	{
		Name:      "autocert.newCertManager",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 2, 3); err != nil {
				return sim.NullValue, err
			}

			var cache *autocertCache

			ln := len(args)
			if ln < 2 || ln > 3 {
				return sim.NullValue, fmt.Errorf("expected 2 or 3 arguments, got %d", ln)
			}

			if !isStringLike(args[0]) {
				return sim.NullValue, fmt.Errorf("invalid cache directory: %s", args[0].TypeName())
			}

			cacheDir := args[0].String()

			var hostPolicy autocert.HostPolicy
			switch args[1].Type {
			case sim.Array:
				domainValues := args[1].ToArray()
				domains := make([]string, len(domainValues))
				for i, v := range domainValues {
					domains[i] = v.String()
				}
				hostPolicy = autocert.HostWhitelist(domains...)

			case sim.Func:
				hostPolicy = func(ctx context.Context, host string) error {
					vm = vm.CloneInitialized(vm.Program, vm.Globals())
					vm.Async = true
					_, err := vm.RunFuncIndex(args[1].ToFunction(), sim.NewString(host))
					return err
				}

			case sim.Object:
				c, ok := args[1].ToObjectOrNil().(*sim.Closure)
				if !ok {
					return sim.NullValue, fmt.Errorf("%v is not a function", args[1].TypeName())
				}
				hostPolicy = func(ctx context.Context, host string) error {
					vm = vm.CloneInitialized(vm.Program, vm.Globals())
					vm.Async = true
					_, err := vm.RunClosure(c, sim.NewString(host))
					return err
				}

			default:
				return sim.NullValue, fmt.Errorf("invalid domains or hostPolicy: %s", args[1].TypeName())
			}

			if ln == 3 {
				var ok bool
				cache, ok = args[2].ToObjectOrNil().(*autocertCache)
				if !ok {
					return sim.NullValue, fmt.Errorf("invalid cache: %s", args[2].TypeName())
				}
			}

			if cache == nil {
				cache = &autocertCache{fs: vm.FileSystem}
			}

			cache.dir = cacheDir

			m := autocert.Manager{
				Cache:      cache,
				Prompt:     autocert.AcceptTOS,
				HostPolicy: hostPolicy,
			}

			cm := &certManager{&m}
			return sim.NewObject(cm), nil
		},
	},
	{
		Name:      "autocert.newFileSystemCache",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			fs, ok := args[0].ToObject().(*FileSystemObj)
			if !ok {
				return sim.NullValue, fmt.Errorf("invalid filesystem argument, got %v", args[0])
			}

			c := &autocertCache{fs: fs.FS}
			return sim.NewObject(c), nil
		},
	},
	{
		Name:      "tls.newConfig",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgRange(args, 0, 1); err != nil {
				return sim.NullValue, err
			}
			if err := ValidateOptionalArgs(args, sim.Bool); err != nil {
				return sim.NullValue, err
			}

			tc := &tlsConfig{
				conf: &tls.Config{
					MinVersion:               tls.VersionTLS12,
					CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
					PreferServerCipherSuites: true,
				},
			}

			if len(args) == 1 {
				tc.conf.InsecureSkipVerify = args[0].ToBool()
			}

			return sim.NewObject(tc), nil
		},
	},
	{
		Name:      "tls.generateCert",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
			if err != nil {
				log.Fatal(err)
			}

			template := x509.Certificate{
				SerialNumber: big.NewInt(1),
				Subject: pkix.Name{
					Organization: []string{"Acme Co"},
				},
				NotBefore: time.Now(),
				NotAfter:  time.Now().Add(time.Hour * 24 * 180),

				KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
				ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
				BasicConstraintsValid: true,
			}

			derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
			if err != nil {
				return sim.Value{}, fmt.Errorf("failed to create certificate: %s", err)
			}

			pubBuf := new(bytes.Buffer)
			err = pem.Encode(pubBuf, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
			if err != nil {
				return sim.Value{}, fmt.Errorf("failed to write data to cert.pem: %w", err)
			}

			privBuf := new(bytes.Buffer)
			privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
			if err != nil {
				return sim.Value{}, fmt.Errorf("unable to marshal private key: %w", err)
			}

			err = pem.Encode(privBuf, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
			if err != nil {
				return sim.Value{}, fmt.Errorf("failed to write data to key.pem: %w", err)
			}

			c := &certificate{
				cert: pubBuf.Bytes(),
				key:  privBuf.Bytes(),
			}

			return sim.NewObject(c), nil
		},
	},
}
View Source
var Templates = []sim.NativeFunction{
	{
		Name:      "templates.render",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return render("", args, vm)
		},
	},
	{
		Name:      "templates.renderHTML",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return render("html", args, vm)
		},
	},
	{
		Name:      "templates.renderXML",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return render("xml", args, vm)
		},
	},
}
View Source
var Terminal = []sim.NativeFunction{}/* 118 elements not displayed */
View Source
var Time = []sim.NativeFunction{
	{
		Name: "->time.Monday",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Monday)), nil
		},
	},
	{
		Name: "->time.Tuesday",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Tuesday)), nil
		},
	},
	{
		Name: "->time.Wednesday",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Wednesday)), nil
		},
	},
	{
		Name: "->time.Thursday",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Thursday)), nil
		},
	},
	{
		Name: "->time.Friday",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Friday)), nil
		},
	},
	{
		Name: "->time.Saturday",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Saturday)), nil
		},
	},
	{
		Name: "->time.Sunday",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Sunday)), nil
		},
	},

	{
		Name: "->time.SecMillis",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(secMillis)), nil
		},
	},
	{
		Name: "->time.MinMillis",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(minMillis)), nil
		},
	},
	{
		Name: "->time.HourMillis",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(hourMillis)), nil
		},
	},
	{
		Name: "->time.DayMillis",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(dayMillis)), nil
		},
	},
	{
		Name: "->time.Nanosecond",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Nanosecond)), nil
		},
	},
	{
		Name: "->time.Microsecond",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Microsecond)), nil
		},
	},
	{
		Name: "->time.Millisecond",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Millisecond)), nil
		},
	},
	{
		Name: "->time.Second",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt(int(time.Second)), nil
		},
	},
	{
		Name: "->time.Minute",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt64(int64(time.Minute)), nil
		},
	},
	{
		Name: "->time.Hour",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewInt64(int64(time.Hour)), nil
		},
	},
	{
		Name: "->time.RFC3339",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewString(time.RFC3339), nil
		},
	},
	{
		Name: "->time.DefaultDateFormat",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewString("2006-1-2"), nil
		},
	},
	{
		Name:      "time.date",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			loc := GetLocation(vm)
			return getDate(args, vm, loc)
		},
	},
	{
		Name:      "time.parseDaysOfWeek",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			s := args[0].String()

			values := make([]sim.Value, len(s))

			for i, r := range s {
				values[i] = sim.NewInt(int(r - '0'))
			}

			return sim.NewArrayValues(values), nil
		},
	},
	{
		Name:      "time.parseDuration",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]

			switch a.Type {
			case sim.Object:
				if _, ok := a.ToObject().(Duration); !ok {
					return sim.NullValue, fmt.Errorf("expected time.Duration, got %s", a.TypeName())
				}
				return a, nil

			case sim.Int:
				return sim.NewObject(Duration(a.ToInt() * int64(time.Millisecond))), nil

			case sim.String:
				v := a.String()

				if IsNumeric(v) {
					i, err := strconv.Atoi(v)
					if err != nil {
						return sim.NullValue, sim.NewCodeError(100005, "invalid format %s. Expected an int", v)
					}
					return sim.NewObject(Duration(int64(i) * int64(time.Millisecond))), nil
				}

				if strings.ContainsRune(v, ':') {
					d, err := parseTime(v)
					if err != nil {
						return sim.NullValue, err
					}
					return d, nil
				}

				return parseDuration(v)

			default:
				return sim.NullValue, fmt.Errorf("expected string, got %s", a.TypeName())
			}
		},
	},
	{
		Name:      "time.parseTime",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]

			switch a.Type {
			case sim.Object:
				if _, ok := a.ToObject().(Duration); !ok {
					return sim.NullValue, fmt.Errorf("expected time.Duration, got %s", a.TypeName())
				}
				return a, nil

			case sim.Int:
				return sim.NewObject(Duration(a.ToInt() * int64(time.Millisecond))), nil

			case sim.String:
				v := args[0].String()

				if IsNumeric(v) {
					i, err := strconv.Atoi(v)
					if err != nil {
						return sim.NullValue, sim.NewCodeError(100005, "invalid format %s. Expected an int", v)
					}
					return sim.NewObject(Duration(int64(i) * int64(time.Millisecond))), nil
				}

				parts := Split(v, ":")
				ln := len(parts)

				if ln < 2 || ln > 3 {
					return sim.NullValue, sim.NewCodeError(100005, "invalid time. Format is for example 18:30")
				}

				first, period, found := strings.Cut(parts[ln-1], " ")
				if found {
					switch period {
					case "am", "AM":
						parts[ln-1] = first

					case "pm", "PM":
						parts[ln-1] = first
						period = "pm"
					}
				}

				h, err := strconv.Atoi(parts[0])
				if err != nil {
					return sim.NullValue, sim.NewCodeError(100005, "invalid hour part %s. Expected an int", parts[0])
				}

				if period == "pm" && h < 12 {
					h += 12
				}

				m, err := strconv.Atoi(parts[1])
				if err != nil {
					return sim.NullValue, sim.NewCodeError(100005, "invalid min part %s. Expected an int", parts[1])
				}

				var s int
				if ln > 2 {
					s, err = strconv.Atoi(parts[2])
					if err != nil {
						return sim.NullValue, sim.NewCodeError(100005, "invalid sec part %s. Expected an int", parts[2])
					}
				}

				d := time.Duration(h)*time.Hour + time.Duration(m)*time.Minute + time.Duration(s)*time.Second

				return sim.NewObject(Duration(d)), nil

			default:
				return sim.NullValue, fmt.Errorf("expected string, got %s", a.TypeName())
			}
		},
	},
	{
		Name:      "time.durationNS",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			d, err := ToDuration(args[0])
			if err != nil {
				return sim.NullValue, err
			}

			return sim.NewObject(Duration(d)), nil
		},
	},
	{
		Name:      "time.toDuration",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int, sim.Int, sim.Int); err != nil {
				return sim.NullValue, err
			}

			l := len(args)

			if l == 0 {
				return sim.NullValue, fmt.Errorf("expected at least one parameter")
			}

			d := args[0].ToInt() * int64(time.Hour)

			if l > 1 {
				d += args[1].ToInt() * int64(time.Minute)
			}

			if l > 2 {
				d += args[2].ToInt() * int64(time.Second)
			}

			return sim.NewObject(Duration(d)), nil
		},
	},
	{
		Name:      "time.toMilliseconds",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int, sim.Int, sim.Int); err != nil {
				return sim.NullValue, err
			}

			l := len(args)

			if l == 0 {
				return sim.NullValue, fmt.Errorf("expected at least one parameter")
			}

			m := args[0].ToInt() * 60 * 60 * 1000

			if l > 1 {
				m += args[1].ToInt() * 60 * 1000
			}

			if l > 2 {
				m += args[2].ToInt() * 1000
			}

			return sim.NewInt64(m), nil
		},
	},
	{
		Name:      "time.newClock",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			loc, ok := args[0].ToObjectOrNil().(location)
			if !ok {
				return sim.NullValue, fmt.Errorf("expected Location, got %s", args[0].TypeName())
			}

			c := &clock.Clock{
				Location: loc.l,
				Now: func() time.Time {
					return time.Now().In(loc.l)
				},
			}

			return sim.NewObject(&Clock{c: c}), nil
		},
	},
	{
		Name:      "time.since",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			t, ok := args[0].ToObjectOrNil().(TimeObj)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}

			now := vm.Now
			if now.IsZero() {
				now = time.Now()
			}

			d := now.Sub(time.Time(t))

			return sim.NewObject(Duration(d)), nil
		},
	},
	{
		Name:      "time.unix",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}
			sec := args[0].ToInt()
			t := time.Unix(sec, 0)
			return sim.NewObject(TimeObj(t)), nil
		},
	},
	{
		Name:        "time.setDefaultLocation",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			name := args[0].String()

			l, err := time.LoadLocation(name)
			if err != nil {
				return sim.NullValue, fmt.Errorf("error loading timezone %s: %w", name, err)
			}

			time.Local = l

			return sim.NullValue, nil
		},
	},
	{
		Name:      "time.setLocation",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			name := args[0].String()

			l, err := time.LoadLocation(name)
			if err != nil {
				return sim.NullValue, fmt.Errorf("error loading timezone %s: %w", name, err)
			}

			vm.Location = l

			return sim.NullValue, nil
		},
	},
	{
		Name:        "time.setFixedNow",
		Arguments:   1,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, err
			}

			t, ok := args[0].ToObjectOrNil().(TimeObj)
			if !ok {
				return sim.NullValue, ErrInvalidType
			}

			vm.Now = time.Time(t)
			return sim.NullValue, nil
		},
	},
	{
		Name:        "time.unsetFixedNow",
		Arguments:   0,
		Permissions: []string{"trusted"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			vm.Now = time.Time{}
			return sim.NullValue, nil
		},
	},
	{
		Name: "time.now",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if !vm.Now.IsZero() {
				return sim.NewObject(TimeObj(vm.Now)), nil
			}
			loc := GetLocation(vm)
			t := time.Now().In(loc)
			return sim.NewObject(TimeObj(t)), nil
		},
	},
	{
		Name: "time.nowUTC",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			n := vm.Now
			if !n.IsZero() {
				return sim.NewObject(TimeObj(n.UTC())), nil
			}
			return sim.NewObject(TimeObj(time.Now().UTC())), nil
		},
	},
	{
		Name: "time.unixNano",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			n := vm.Now
			if !n.IsZero() {
				return sim.NewInt64(n.UnixNano()), nil
			}
			return sim.NewInt64(time.Now().UnixNano()), nil
		},
	},
	{
		Name:        "time.sleep",
		Arguments:   1,
		Permissions: []string{"sync"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if len(args) != 1 {
				return sim.NullValue, fmt.Errorf("expected 1 argument, got %d", len(args))
			}

			d, err := ToDuration(args[0])
			if err != nil {
				return sim.NullValue, err
			}

			time.Sleep(d)
			return sim.NullValue, nil
		},
	},
	{
		Name: "->time.utc",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			return sim.NewObject(location{time.UTC}), nil
		},
	},
	{
		Name: "->time.local",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := GetLocation(vm)
			return sim.NewObject(location{l}), nil
		},
	},
	{
		Name:      "time.loadLocation",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}
			l, err := time.LoadLocation(args[0].String())
			if err != nil {
				return sim.NullValue, err
			}
			return sim.NewObject(location{l}), nil
		},
	},
	{
		Name:      "time.parse",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := GetLocation(vm)
			return parseInLocation(l, args)
		},
	},
	{
		Name:      "time.parseInLocation",
		Arguments: 3,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			location, ok := args[2].ToObjectOrNil().(location)
			if !ok {
				return sim.NullValue, fmt.Errorf("invalid location, got %s", args[2].TypeName())
			}
			return parseInLocation(location.l, args)
		},
	},
	{
		Name:      "time.formatMinutes",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var min float64

			a := args[0]

			switch a.Type {
			case sim.Int, sim.Float:
				min = a.ToFloat()

			default:
				return sim.NullValue, fmt.Errorf("expected a number, got %v", a.TypeName())
			}

			negative := min < 0

			min = math.Abs(min)

			h := int(math.Floor(min / 60))
			m := int(min) % 60

			s := fmt.Sprintf("%02d:%02d", h, m)

			if negative {
				s = "-" + s
			}

			return sim.NewString(s), nil
		},
	},
	{
		Name:        "time.newTicker",
		Arguments:   2,
		Permissions: []string{"async"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d, err := ToDuration(args[0])
			if err != nil {
				return sim.NullValue, err
			}

			v := args[1]
			switch v.Type {
			case sim.Func:

			case sim.Object:
				if _, ok := v.ToObjectOrNil().(*sim.Closure); !ok {
					return sim.NullValue, fmt.Errorf("%v is not a function", v.TypeName())
				}

			default:
				return sim.NullValue, fmt.Errorf("%v is not a function", v.TypeName())
			}

			ticker := time.NewTicker(d)

			go func() {
				for range ticker.C {
					if err := runAsyncFuncOrClosure(vm, v); err != nil {
						fmt.Fprintln(vm.GetStderr(), err)
					}
				}
			}()

			return sim.NewObject(&tickerObj{ticker}), nil
		},
	},
	{
		Name:        "time.newTimer",
		Arguments:   2,
		Permissions: []string{"async"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			d, err := ToDuration(args[0])
			if err != nil {
				return sim.NullValue, fmt.Errorf("expected time.Duration, got: %s", args[0].TypeName())
			}

			v := args[1]
			switch v.Type {
			case sim.Func:
			case sim.Object:
			default:
				return sim.NullValue, fmt.Errorf("%v is not a function", v.TypeName())
			}

			timer := time.NewTimer(d)

			go func() {
				for range timer.C {
					if err := runAsyncFuncOrClosure(vm, v); err != nil {
						fmt.Fprintln(vm.GetStderr(), err)
					}
				}
			}()

			return sim.NewObject(&timerObj{timer}), nil
		},
	},
	{
		Name:      "time.after",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			l := len(args)
			if l == 0 || l > 2 {
				return sim.NullValue, fmt.Errorf("expected 1 or 2 args")
			}

			d, err := ToDuration(args[0])
			if err != nil {
				return sim.NullValue, fmt.Errorf("expected time.Duration, got: %s", args[0].TypeName())
			}

			ch := make(chan sim.Value)
			timer := time.NewTimer(d)

			if l == 1 {
				go func() {
					t := <-timer.C
					ch <- sim.NewObject(TimeObj(t))
				}()
			} else {
				go func() {
					<-timer.C
					ch <- args[1]
				}()
			}

			c := &channel{c: ch}
			return sim.NewObject(c), nil
		},
	},
}
View Source
var UUID = []sim.NativeFunction{
	{
		Name: "uuid.newID",
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			id := shortuuid.New()
			return sim.NewString(id), nil
		},
	},
	{
		Name:      "uuid.newRandomID",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Int); err != nil {
				return sim.NullValue, err
			}

			var n int
			if len(args) == 0 {
				n = 5
			} else {
				n = int(args[0].ToInt()/2) + 1
			}

			id := RandomAlphanumeric(int(n)) + shortuuid.New() + RandomAlphanumeric(int(n))

			return sim.NewString(id), nil
		},
	},
}
View Source
var WebSocket = []sim.NativeFunction{
	{
		Name:        "websocket.dial",
		Permissions: []string{"networking"},
		Arguments:   1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, nil
			}

			url := args[0].String()

			c, _, err := websocket.DefaultDialer.Dial(url, nil)
			if err != nil {
				return sim.NullValue, err
			}

			c.SetReadLimit(8192)

			return sim.NewObject(newWebsocketConn(c, vm)), nil
		},
	},
	{
		Name:        "websocket.newUpgrader",
		Permissions: []string{"networking"},
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			u := &websocket.Upgrader{
				HandshakeTimeout: 10 * time.Second,
				ReadBufferSize:   1024,
				WriteBufferSize:  1024,
			}
			return sim.NewObject(&upgrader{u}), nil
		},
	},
	{
		Name:      "websocket.isCloseError",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object); err != nil {
				return sim.NullValue, nil
			}

			e, ok := args[0].ToObject().(*websocket.CloseError)
			if !ok {
				return sim.FalseValue, nil
			}

			switch e.Code {
			case
				websocket.CloseNormalClosure,
				websocket.CloseGoingAway,
				websocket.CloseProtocolError,
				websocket.CloseUnsupportedData,
				websocket.CloseNoStatusReceived,
				websocket.CloseAbnormalClosure,
				websocket.CloseInvalidFramePayloadData,
				websocket.ClosePolicyViolation,
				websocket.CloseMessageTooBig,
				websocket.CloseMandatoryExtension,
				websocket.CloseInternalServerErr,
				websocket.CloseServiceRestart,
				websocket.CloseTryAgainLater,
				websocket.CloseTLSHandshake:
				return sim.TrueValue, nil
			default:
				return sim.FalseValue, nil
			}
		},
	},
}
View Source
var X509 = []sim.NativeFunction{
	{
		Name:      "x509.parsePEM",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			certPEM := args[0].ToBytes()

			block, _ := pem.Decode(certPEM)
			var certDER []byte
			if block != nil {
				certDER = block.Bytes
			} else {
				certDER = certPEM
			}

			cert, err := x509.ParseCertificate(certDER)
			if err != nil {
				return sim.NullValue, fmt.Errorf("error parsing certificate: %w", err)
			}

			return sim.NewObject(&x509Certificate{cert}), nil
		},
	},
}
View Source
var XLSX = []sim.NativeFunction{
	{
		Name:      "xlsx.openReaderAt",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object, sim.Int); err != nil {
				return sim.NullValue, err
			}

			r, ok := args[0].ToObjectOrNil().(io.ReaderAt)
			if !ok {
				return sim.NullValue, fmt.Errorf("invalid argument type. Expected a io.ReaderAt, got %s", args[0].TypeName())
			}

			size := args[1].ToInt()

			reader, err := xlsx.OpenReaderAt(r, size)
			if err != nil {
				return sim.NullValue, err
			}

			if vm.StatsEnabled {
				if err := vm.AddAllocations(int(size)); err != nil {
					return sim.NullValue, err
				}
			}

			return sim.NewObject(&xlsxFile{obj: reader}), nil
		},
	},
	{
		Name:      "xlsx.openBinary",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			b := args[0].ToBytes()

			reader, err := xlsx.OpenBinary(b)
			if err != nil {
				return sim.NullValue, err
			}

			if vm.StatsEnabled {
				if err := vm.AddAllocations(len(b)); err != nil {
					return sim.NullValue, err
				}
			}

			return sim.NewObject(&xlsxFile{obj: reader}), nil
		},
	},
	{
		Name:      "xlsx.openFile",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			var r io.ReaderAt
			var size int64

			a := args[0]

			switch a.Type {
			case sim.Object:
				f, ok := a.ToObject().(*file)
				if !ok {
					return sim.NullValue, fmt.Errorf("invalid argument type. Expected a io.ReaderAt, got %s", a.TypeName())
				}
				r = f
				st, err := f.Stat()
				if err != nil {
					return sim.NullValue, err
				}
				size = st.Size()

			case sim.String:
				f, err := vm.FileSystem.Open(a.String())
				if err != nil {
					return sim.NullValue, err
				}
				r = f
				st, err := f.Stat()
				if err != nil {
					return sim.NullValue, err
				}
				size = st.Size()

			default:
				return sim.NullValue, fmt.Errorf("invalid argument type. Expected a io.ReaderAt, got %s", a.TypeName())
			}

			reader, err := xlsx.OpenReaderAt(r, size)
			if err != nil {
				return sim.NullValue, err
			}

			if vm.StatsEnabled {
				if err := vm.AddAllocations(int(size)); err != nil {
					return sim.NullValue, err
				}
			}

			return sim.NewObject(&xlsxFile{obj: reader, path: a.String()}), nil
		},
	},
	{
		Name:      "xlsx.newFile",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args); err != nil {
				return sim.NullValue, err
			}

			file := xlsx.NewFile()
			return sim.NewObject(&xlsxFile{obj: file}), nil
		},
	},
	{
		Name:      "xlsx.newStyle",
		Arguments: 0,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args); err != nil {
				return sim.NullValue, err
			}

			s := xlsx.NewStyle()
			return sim.NewObject(&xlsxStyle{obj: s}), nil
		},
	},
}
View Source
var XML = []sim.NativeFunction{
	{
		Name:      "xml.newDocument",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.Bool, sim.String); err != nil {
				return sim.NullValue, err
			}

			doc := etree.NewDocument()
			doc.WriteSettings.CanonicalText = true
			doc.WriteSettings.CanonicalAttrVal = false

			ln := len(args)

			if ln == 1 && args[0].ToBool() {
				doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`)
			}

			if ln == 2 {
				a := args[1]

				doc.CreateProcInst("xml", a.ToString())

				if vm.StatsEnabled {
					if err := vm.AddAllocations(a.Size()); err != nil {
						return sim.NullValue, err
					}
				}
			} else {
				if vm.StatsEnabled {
					if err := vm.AddAllocations(1); err != nil {
						return sim.NullValue, err
					}
				}
			}

			return sim.NewObject(&xmlDoc{doc: doc}), nil
		},
	},
	{
		Name:      "xml.newCharData",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			a := args[0]

			d := etree.NewText(a.String())

			if vm.StatsEnabled {
				if err := vm.AddAllocations(a.Size()); err != nil {
					return sim.NullValue, err
				}
			}

			return sim.NewObject(&xmlCharData{data: d}), nil
		},
	},
	{
		Name:      "xml.newElement",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			a := args[0]

			e := etree.NewElement(a.String())

			if vm.StatsEnabled {
				if err := vm.AddAllocations(a.Size()); err != nil {
					return sim.NullValue, err
				}
			}

			return sim.NewObject(&xmlElement{element: e}), nil
		},
	},
	{
		Name:      "xml.read",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Bytes); err != nil {
				return sim.NullValue, err
			}

			doc := etree.NewDocument()
			doc.WriteSettings.CanonicalText = true
			doc.WriteSettings.CanonicalAttrVal = false

			a := args[0]

			if err := doc.ReadFromBytes(a.ToBytes()); err != nil {
				return sim.NullValue, err
			}

			if vm.StatsEnabled {
				if err := vm.AddAllocations(a.Size()); err != nil {
					return sim.NullValue, err
				}
			}

			return sim.NewObject(&xmlDoc{doc: doc}), nil
		},
	},
	{
		Name:      "xml.readString",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.String); err != nil {
				return sim.NullValue, err
			}

			doc := etree.NewDocument()
			doc.WriteSettings.CanonicalText = true
			doc.WriteSettings.CanonicalAttrVal = false

			a := args[0]

			if err := doc.ReadFromString(a.String()); err != nil {
				return sim.NullValue, err
			}

			if vm.StatsEnabled {
				if err := vm.AddAllocations(a.Size()); err != nil {
					return sim.NullValue, err
				}
			}

			return sim.NewObject(&xmlDoc{doc: doc}), nil
		},
	},
	{
		Name:      "xml.encode",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			a := args[0]
			switch a.Type {
			case sim.Null, sim.Undefined:
				return sim.NullValue, nil
			case sim.Bytes:
				encoder := base64.RawStdEncoding
				encoded := encoder.EncodeToString(a.ToBytes())
				return sim.NewString(encoded), nil
			default:
				s := encodeXML(args[0].String())
				return sim.NewString(s), nil
			}
		},
	},
}
View Source
var ZIP = []sim.NativeFunction{
	{
		Name:      "zip.newWriter",
		Arguments: 1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			w, ok := args[0].ToObjectOrNil().(io.Writer)
			if !ok {
				return sim.NullValue, fmt.Errorf("exepected a Writer, got %s", args[0].TypeName())
			}

			g := zip.NewWriter(w)
			v := &zipWriter{g}
			return sim.NewObject(v), nil
		},
	},
	{
		Name:      "zip.newReader",
		Arguments: 2,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateArgs(args, sim.Object, sim.Int); err != nil {
				return sim.NullValue, err
			}

			r, ok := args[0].ToObjectOrNil().(io.ReaderAt)
			if !ok {
				return sim.NullValue, fmt.Errorf("exepected a reader, got %s", args[0].TypeName())
			}

			size := args[1].ToInt()

			gr, err := zip.NewReader(r, size)
			if err != nil {
				return sim.NullValue, err
			}

			v := &zipReader{r: gr}
			return sim.NewObject(v), nil
		},
	},
	{
		Name:      "zip.open",
		Arguments: -1,
		Function: func(this sim.Value, args []sim.Value, vm *sim.VM) (sim.Value, error) {
			if err := ValidateOptionalArgs(args, sim.String, sim.Object); err != nil {
				return sim.NullValue, err
			}

			if err := ValidateArgRange(args, 1, 2); err != nil {
				return sim.NullValue, err
			}

			var fs filesystem.FS
			if len(args) == 2 {
				fsObj, ok := args[1].ToObjectOrNil().(*FileSystemObj)
				if !ok {
					return sim.NullValue, fmt.Errorf("exepected a FileSystem, got %s", args[1].TypeName())
				}
				fs = fsObj.FS
			} else {
				fs = vm.FileSystem
			}

			f, err := fs.Open(args[0].String())
			if err != nil {
				return sim.NullValue, err
			}

			fi, err := f.Stat()
			if err != nil {
				return sim.NullValue, err
			}

			size := fi.Size()

			gr, err := zip.NewReader(f, size)
			if err != nil {
				return sim.NullValue, err
			}

			v := &zipReader{gr, f}
			return sim.NewObject(v), nil
		},
	},
}

Functions

func CheckHashPasword

func CheckHashPasword(hash, pwd string) bool

func DecodeCustomBase34

func DecodeCustomBase34(s string) uint64

DecodeCustomBase34 decodes a base34-encoded string back to uint64

func Decrypt

func Decrypt(ciphertext, password []byte) ([]byte, error)

Decrypts decrypts the text.

func DecryptTripleDESCBC

func DecryptTripleDESCBC(encrypted, key []byte) ([]byte, error)

func Decrypts

func Decrypts(text, password string) (string, error)

Decrypts decrypts the text.

func EncodeCustomBase34

func EncodeCustomBase34(value uint64) string

EncodeCustomBase34 encodes a uint64 value to string in base34 format

func Encrypt

func Encrypt(plaintext, password []byte) ([]byte, error)

Encrypts encrypts the text.

func EncryptTripleDESCBC

func EncryptTripleDESCBC(decrypted, key []byte) ([]byte, error)

func Encrypts

func Encrypts(text, password string) (string, error)

Encrypts encrypts the text.

func GetLocation

func GetLocation(vm *sim.VM) *time.Location

func HashPassword

func HashPassword(pwd string) string

func IsAlphanumeric

func IsAlphanumeric(s string) bool

func IsAlphanumericIdent

func IsAlphanumericIdent(s string) bool

func IsDecimal

func IsDecimal(r rune) bool

IsDecimal returns true if r is a digit

func IsIdent

func IsIdent(s string) bool

IsIdent returns if s is a valid identifier.

func IsNumeric

func IsNumeric(s string) bool

IsNumeric returns true if s contains only digits

func NewReader

func NewReader(r io.Reader) *reader

func NewRoute

func NewRoute(url string) *httpRoute

func NewWriter

func NewWriter(w io.Writer) *writer

func Random

func Random(n int) []byte

GenerateRandomBytes returns securely generated random bytes. It will return an error if the system's secure random number generator fails to function correctly, in which case the caller should not continue.

func RandomAlphanumeric

func RandomAlphanumeric(size int) string

func ReadAll

func ReadAll(reader io.Reader, vm *sim.VM) ([]byte, error)

func ReadNames

func ReadNames(fs filesystem.FS, dirname string, recursive bool) ([]string, error)

ReadNames reads the directory and file names contained in dirname.

func SendMailWithTimeout

func SendMailWithTimeout(addr string, a Auth, from string, to []string, msg []byte, insecureSkipVerify bool, timeout time.Duration) error

SendMail connects to the server at addr, switches to TLS if possible, authenticates with the optional mechanism a if possible, and then sends an email from address from, to addresses to, with message msg. The addr must include a port, as in "mail.example.com:smtp".

The addresses in the to parameter are the SMTP RCPT addresses.

The msg parameter should be an RFC 822-style email with headers first, a blank line, and then the message body. The lines of msg should be CRLF terminated. The msg headers should usually include fields such as "From", "To", "Subject", and "Cc". Sending "Bcc" messages is accomplished by including an email address in the to parameter but not including it in the msg headers.

The SendMail function and the the net/smtp package are low-level mechanisms and provide no support for DKIM signing, MIME attachments (see the mime/multipart package), or other mail functionality. Higher-level packages exist outside of the standard library.

func Split

func Split(s, sep string) []string

func ToDuration

func ToDuration(v sim.Value) (time.Duration, error)

func ValidateArgRange

func ValidateArgRange(args []sim.Value, counts ...int) error

func ValidateArgs

func ValidateArgs(args []sim.Value, t ...interface{}) error

validate the number of args ant type

func ValidateOptionalArgs

func ValidateOptionalArgs(args []sim.Value, t ...sim.Type) error

validate that if present, args are of type t

func ValidateOrNilArgs

func ValidateOrNilArgs(args []sim.Value, t ...interface{}) error

validate the number of args ant type

func ValidatePermissions

func ValidatePermissions(p *sim.Program, vm *sim.VM) error

func WithDeadline

func WithDeadline(d time.Duration, fn func(dl *Deadline) error) error

func Write

func Write(w io.Writer, v sim.Value, vm *sim.VM) error

func WriteAt

func WriteAt(w io.WriterAt, v sim.Value, off int64, vm *sim.VM) error

func ZeroPadding

func ZeroPadding(ciphertext []byte, blockSize int) []byte

func ZeroUnPadding

func ZeroUnPadding(origData []byte) []byte

Types

type Addr

type Addr struct {
	// contains filtered or unexported fields
}

func (*Addr) GetMethod

func (a *Addr) GetMethod(name string) sim.NativeMethod

func (*Addr) String

func (a *Addr) String() string

func (*Addr) Type

func (*Addr) Type() string

type Auth

type Auth interface {
	// Start begins an authentication with a server.
	// It returns the name of the authentication protocol
	// and optionally data to include in the initial AUTH message
	// sent to the server. It can return proto == "" to indicate
	// that the authentication should be skipped.
	// If it returns a non-nil error, the SMTP client aborts
	// the authentication attempt and closes the connection.
	Start(server *ServerInfo) (proto string, toServer []byte, err error)

	// Next continues the authentication. The server has just sent
	// the fromServer data. If more is true, the server expects a
	// response, which Next should return as toServer; otherwise
	// Next should return toServer == nil.
	// If Next returns a non-nil error, the SMTP client aborts
	// the authentication attempt and closes the connection.
	Next(fromServer []byte, more bool) (toServer []byte, err error)
}

Auth is implemented by an SMTP authentication mechanism.

func CRAMMD5Auth

func CRAMMD5Auth(username, secret string) Auth

CRAMMD5Auth returns an Auth that implements the CRAM-MD5 authentication mechanism as defined in RFC 2195. The returned Auth uses the given username and secret to authenticate to the server using the challenge-response mechanism.

func LoginAuth

func LoginAuth(username, password string) Auth

loginAuth returns an Auth that implements the LOGIN authentication mechanism as defined in RFC 4616.

func PlainAuth

func PlainAuth(identity, username, password, host string) Auth

PlainAuth returns an Auth that implements the PLAIN authentication mechanism as defined in RFC 4616. The returned Auth uses the given username and password to authenticate on TLS connections to host and act as identity. Usually identity will be left blank to act as username.

type Buffer

type Buffer struct {
	Buf *bytes.Buffer
}

func NewBuffer

func NewBuffer() Buffer

func (Buffer) GetField

func (b Buffer) GetField(name string, vm *sim.VM) (sim.Value, error)

func (Buffer) GetMethod

func (b Buffer) GetMethod(name string) sim.NativeMethod

func (Buffer) Read

func (b Buffer) Read(p []byte) (n int, err error)

func (Buffer) Type

func (b Buffer) Type() string

func (Buffer) Write

func (b Buffer) Write(p []byte) (n int, err error)

type Client

type Client struct {
	Text *textproto.Conn
	// contains filtered or unexported fields
}

func Dial

func Dial(addr string) (*Client, error)

Dial returns a new Client connected to an SMTP server at addr. The addr must include a port, as in "mail.example.com:smtp".

func DialTimeout

func DialTimeout(addr string, timeout time.Duration) (*Client, error)

func NewClient

func NewClient(conn net.Conn, host string) (*Client, error)

NewClient returns a new Client using an existing connection and host as a server name to be used when authenticating.

func (*Client) Auth

func (c *Client) Auth(a Auth) error

Auth authenticates a client using the provided authentication mechanism. A failed authentication closes the connection. Only servers that advertise the AUTH extension support this function.

func (*Client) Close

func (c *Client) Close() error

Close closes the connection.

func (*Client) Data

func (c *Client) Data() (io.WriteCloser, error)

Data issues a DATA command to the server and returns a writer that can be used to write the mail headers and body. The caller should close the writer before calling any more methods on c. A call to Data must be preceded by one or more calls to Rcpt.

func (*Client) Extension

func (c *Client) Extension(ext string) (bool, string)

Extension reports whether an extension is support by the server. The extension name is case-insensitive. If the extension is supported, Extension also returns a string that contains any parameters the server specifies for the extension.

func (*Client) Hello

func (c *Client) Hello(localName string) error

Hello sends a HELO or EHLO to the server as the given host name. Calling this method is only necessary if the client needs control over the host name used. The client will introduce itself as "localhost" automatically otherwise. If Hello is called, it must be called before any of the other methods.

func (*Client) Mail

func (c *Client) Mail(from string) error

Mail issues a MAIL command to the server using the provided email address. If the server supports the 8BITMIME extension, Mail adds the BODY=8BITMIME parameter. This initiates a mail transaction and is followed by one or more Rcpt calls.

func (*Client) Quit

func (c *Client) Quit() error

Quit sends the QUIT command and closes the connection to the server.

func (*Client) Rcpt

func (c *Client) Rcpt(to string) error

Rcpt issues a RCPT command to the server using the provided email address. A call to Rcpt must be preceded by a call to Mail and may be followed by a Data call or another Rcpt call.

func (*Client) Reset

func (c *Client) Reset() error

Reset sends the RSET command to the server, aborting the current mail transaction.

func (*Client) StartTLS

func (c *Client) StartTLS(config *tls.Config) error

StartTLS sends the STARTTLS command and encrypts all further communication. Only servers that advertise the STARTTLS extension support this function.

func (*Client) TLSConnectionState

func (c *Client) TLSConnectionState() (state tls.ConnectionState, ok bool)

TLSConnectionState returns the client's TLS connection state. The return values are their zero values if StartTLS did not succeed.

func (*Client) Verify

func (c *Client) Verify(addr string) error

Verify checks the validity of an email address on the server. If Verify returns nil, the address is valid. A non-nil return does not necessarily indicate an invalid address. Many servers will not verify addresses for security reasons.

type Clock

type Clock struct {
	// contains filtered or unexported fields
}

func (*Clock) GetField

func (c *Clock) GetField(name string, vm *sim.VM) (sim.Value, error)

func (*Clock) GetMethod

func (c *Clock) GetMethod(name string) sim.NativeMethod

func (*Clock) Size

func (c *Clock) Size() int

func (*Clock) Type

func (c *Clock) Type() string

type Deadline

type Deadline struct {
	// contains filtered or unexported fields
}

func (*Deadline) Cancel

func (dl *Deadline) Cancel()

func (*Deadline) Extend

func (dl *Deadline) Extend(d time.Duration)

func (*Deadline) GetMethod

func (dl *Deadline) GetMethod(name string) sim.NativeMethod

func (*Deadline) Type

func (dl *Deadline) Type() string

type Duration

type Duration time.Duration

func (Duration) Export

func (t Duration) Export(recursionLevel int) interface{}

func (Duration) GetField

func (t Duration) GetField(name string, vm *sim.VM) (sim.Value, error)

func (Duration) GetMethod

func (t Duration) GetMethod(name string) sim.NativeMethod

func (Duration) MarshalJSON

func (t Duration) MarshalJSON() ([]byte, error)

func (Duration) Size

func (t Duration) Size() int

func (Duration) String

func (t Duration) String() string

func (Duration) Type

func (t Duration) Type() string

type FileSystemObj

type FileSystemObj struct {
	FS filesystem.FS
}

func NewFileSystem

func NewFileSystem(fs filesystem.FS) *FileSystemObj

func (*FileSystemObj) GetMethod

func (f *FileSystemObj) GetMethod(name string) sim.NativeMethod

func (*FileSystemObj) Type

func (f *FileSystemObj) Type() string

type IP

type IP struct {
	// contains filtered or unexported fields
}

func (*IP) GetMethod

func (ip *IP) GetMethod(name string) sim.NativeMethod

func (*IP) String

func (ip *IP) String() string

func (*IP) Type

func (*IP) Type() string

type QueryStat

type QueryStat struct {
	Query string
	Count int
	Total time.Duration
	Avg   time.Duration
}

type ResponseWriterCounter

type ResponseWriterCounter struct {
	http.ResponseWriter
	BytesWritten int64
}

func (*ResponseWriterCounter) Write

func (rwc *ResponseWriterCounter) Write(data []byte) (int, error)

func (*ResponseWriterCounter) WriteHeader

func (rwc *ResponseWriterCounter) WriteHeader(statusCode int)

También necesitas envolver WriteHeader si quieres interceptarlo

type SecureObject

type SecureObject struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func (*SecureObject) GetField

func (p *SecureObject) GetField(key string, vm *sim.VM) (sim.Value, error)

func (*SecureObject) SetField

func (p *SecureObject) SetField(key string, v sim.Value, vm *sim.VM) error

func (*SecureObject) Type

func (*SecureObject) Type() string

type ServerInfo

type ServerInfo struct {
	Name string
	Auth []string
	TLS  bool
}

ServerInfo records information about an SMTP server.

type SmtMessage

type SmtMessage struct {
	Attachments map[string]*attachment
	From        mail.Address
	To          sim.Value
	Bcc         sim.Value
	Cc          sim.Value
	ReplyTo     string
	Subject     string
	Body        string
	Html        bool
}

Message represents a smtp message.

func (*SmtMessage) AllRecipients

func (m *SmtMessage) AllRecipients() []string

Tolist returns all the recipients of the email

func (*SmtMessage) AttachBuffer

func (m *SmtMessage) AttachBuffer(filename string, buf []byte, inline bool) error

AttachBuffer attaches a binary attachment.

func (*SmtMessage) BccList

func (m *SmtMessage) BccList() []string

func (*SmtMessage) Bytes

func (m *SmtMessage) Bytes() []byte

Bytes returns the mail data

func (*SmtMessage) CcList

func (m *SmtMessage) CcList() []string

func (*SmtMessage) ContentType

func (m *SmtMessage) ContentType() string

func (*SmtMessage) GetField

func (m *SmtMessage) GetField(key string, vm *sim.VM) (sim.Value, error)

func (*SmtMessage) GetMethod

func (m *SmtMessage) GetMethod(name string) sim.NativeMethod

func (*SmtMessage) SendWithTimeout

func (m *SmtMessage) SendWithTimeout(user, password, host string, port int, insecureSkipVerify bool, timeout time.Duration) error

func (*SmtMessage) SetField

func (m *SmtMessage) SetField(key string, v sim.Value, vm *sim.VM) error

func (*SmtMessage) ToList

func (m *SmtMessage) ToList() []string

func (SmtMessage) Type

func (SmtMessage) Type() string

type SqlProfiler

type SqlProfiler struct {
	// contains filtered or unexported fields
}

func NewSQLProfiler

func NewSQLProfiler() *SqlProfiler

func (*SqlProfiler) Add

func (p *SqlProfiler) Add(query string, duration time.Duration)

func (*SqlProfiler) Report

func (p *SqlProfiler) Report(maxLines int)

func (*SqlProfiler) ReportStats

func (p *SqlProfiler) ReportStats(maxLines int) []QueryStat

func (*SqlProfiler) Reset

func (p *SqlProfiler) Reset()

func (*SqlProfiler) Start

func (p *SqlProfiler) Start()

func (*SqlProfiler) Stop

func (p *SqlProfiler) Stop()

type TimeObj

type TimeObj time.Time

func (TimeObj) Compare

func (t TimeObj) Compare(v sim.Value) int

func (TimeObj) Equals

func (t TimeObj) Equals(v interface{}) bool

func (TimeObj) Export

func (t TimeObj) Export(recursionLevel int) interface{}

func (TimeObj) GetField

func (t TimeObj) GetField(name string, vm *sim.VM) (sim.Value, error)

func (TimeObj) GetMethod

func (t TimeObj) GetMethod(name string) sim.NativeMethod

func (TimeObj) MarshalJSON

func (t TimeObj) MarshalJSON() ([]byte, error)

func (TimeObj) Size

func (t TimeObj) Size() int

func (TimeObj) String

func (t TimeObj) String() string

func (TimeObj) Type

func (t TimeObj) Type() string

type URL

type URL struct {
	// contains filtered or unexported fields
}

func (*URL) GetField

func (u *URL) GetField(name string, vm *sim.VM) (sim.Value, error)

func (*URL) GetMethod

func (u *URL) GetMethod(name string) sim.NativeMethod

func (*URL) SetField

func (u *URL) SetField(name string, v sim.Value, vm *sim.VM) error

func (*URL) String

func (u *URL) String() string

func (*URL) Type

func (*URL) Type() string

type VMNumberFormatter

type VMNumberFormatter struct {
	// contains filtered or unexported fields
}

VMNumberFormatter implements pdf.NumberFormatter interface using VM's locale system

func (*VMNumberFormatter) FormatNumber

func (f *VMNumberFormatter) FormatNumber(format string, value float64) string

FormatNumber formats a number using the VM's localizer or culture

func (*VMNumberFormatter) ParseNumber

func (f *VMNumberFormatter) ParseNumber(text string) (float64, error)

ParseNumber parses a number using the VM's localizer or culture

Directories

Path Synopsis
Package jsregex provides JavaScript-compatible regular expression functionality for Go.
Package jsregex provides JavaScript-compatible regular expression functionality for Go.
Package templates generates source code for templates.
Package templates generates source code for templates.
Package etree provides XML services through an Element Tree abstraction.
Package etree provides XML services through an Element Tree abstraction.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL