more builtins

This commit is contained in:
Chuck Smith
2024-03-24 16:03:08 -04:00
parent b4ba660704
commit a08fc1520c
12 changed files with 243 additions and 3 deletions

20
builtins/abs.go Normal file
View File

@@ -0,0 +1,20 @@
package builtins
import "monkey/object"
// Abs ...
func Abs(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("wrong number of arguments. got=%d, want=1",
len(args))
}
if i, ok := args[0].(*object.Integer); ok {
value := i.Value
if value < 0 {
value = value * -1
}
return &object.Integer{Value: value}
}
return newError("argument to `abs` not supported, got %s", args[0].Type())
}

20
builtins/bin.go Normal file
View File

@@ -0,0 +1,20 @@
package builtins
import (
"fmt"
"monkey/object"
"strconv"
)
// Bin ...
func Bin(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("wrong number of arguments. got=%d, want=1",
len(args))
}
if i, ok := args[0].(*object.Integer); ok {
return &object.String{Value: fmt.Sprintf("0b%s", strconv.FormatInt(i.Value, 2))}
}
return newError("argument to `bin` not supported, got %s", args[0].Type())
}

View File

@@ -31,6 +31,16 @@ var Builtins = map[string]*object.Builtin{
"read": {Name: "read", Fn: Read},
"write": {Name: "write", Fn: Write},
"ffi": {Name: "ffi", Fn: FFI},
"abs": {Name: "abs", Fn: Abs},
"bin": {Name: "bin", Fn: Bin},
"hex": {Name: "hex", Fn: Hex},
"ord": {Name: "ord", Fn: Ord},
"chr": {Name: "chr", Fn: Chr},
"divmod": {Name: "divmod", Fn: Divmod},
"hash": {Name: "hash", Fn: HashOf},
"id": {Name: "id", Fn: IdOf},
"oct": {Name: "oct", Fn: Oct},
"pow": {Name: "pow", Fn: Pow},
}
// BuiltinsIndex ...

19
builtins/chr.go Normal file
View File

@@ -0,0 +1,19 @@
package builtins
import (
"fmt"
"monkey/object"
)
// Chr ...
func Chr(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("wrong number of arguments. got=%d, want=1",
len(args))
}
if i, ok := args[0].(*object.Integer); ok {
return &object.String{Value: fmt.Sprintf("%c", rune(i.Value))}
}
return newError("argument to `chr` not supported, got %s", args[0].Type())
}

24
builtins/divmod.go Normal file
View File

@@ -0,0 +1,24 @@
package builtins
import "monkey/object"
// Divmod ...
func Divmod(args ...object.Object) object.Object {
if len(args) != 2 {
return newError("wrong number of arguments. got=%d, want=2",
len(args))
}
if a, ok := args[0].(*object.Integer); ok {
if b, ok := args[1].(*object.Integer); ok {
elements := make([]object.Object, 2)
elements[0] = &object.Integer{Value: a.Value / b.Value}
elements[1] = &object.Integer{Value: a.Value % b.Value}
return &object.Array{Elements: elements}
} else {
return newError("expected argument #2 to `divmod` to be `int` got=%s", args[1].Type())
}
} else {
return newError("expected argument #1 to `divmod` to be `int` got=%s", args[0].Type())
}
}

16
builtins/hash.go Normal file
View File

@@ -0,0 +1,16 @@
package builtins
import "monkey/object"
// HashOf ...
func HashOf(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("wrong number of arguments. got=%d, want=1",
len(args))
}
if hash, ok := args[0].(object.Hashable); ok {
return &object.Integer{Value: int64(hash.HashKey().Value)}
}
return newError("argument #1 to `hash()` is not hashable: %s", args[0].Inspect())
}

20
builtins/hex.go Normal file
View File

@@ -0,0 +1,20 @@
package builtins
import (
"fmt"
"monkey/object"
"strconv"
)
// Hex ...
func Hex(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("wrong number of arguments. got=%d, want=1",
len(args))
}
if i, ok := args[0].(*object.Integer); ok {
return &object.String{Value: fmt.Sprintf("0x%s", strconv.FormatInt(i.Value, 16))}
}
return newError("argument to `hex` not supported, got %s", args[0].Type())
}

38
builtins/id.go Normal file
View File

@@ -0,0 +1,38 @@
package builtins
import (
"fmt"
"monkey/object"
)
// IdOf ...
func IdOf(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("wrong number of arguments. got=%d, want=1",
len(args))
}
arg := args[0]
if n, ok := arg.(*object.Null); ok {
return &object.String{Value: fmt.Sprintf("%p", n)}
} else if b, ok := arg.(*object.Boolean); ok {
return &object.String{Value: fmt.Sprintf("%p", b)}
} else if i, ok := arg.(*object.Integer); ok {
return &object.String{Value: fmt.Sprintf("%p", i)}
} else if s, ok := arg.(*object.String); ok {
return &object.String{Value: fmt.Sprintf("%p", s)}
} else if a, ok := arg.(*object.Array); ok {
return &object.String{Value: fmt.Sprintf("%p", a)}
} else if h, ok := arg.(*object.Hash); ok {
return &object.String{Value: fmt.Sprintf("%p", h)}
} else if f, ok := arg.(*object.Function); ok {
return &object.String{Value: fmt.Sprintf("%p", f)}
} else if c, ok := arg.(*object.Closure); ok {
return &object.String{Value: fmt.Sprintf("%p", c)}
} else if b, ok := arg.(*object.Builtin); ok {
return &object.String{Value: fmt.Sprintf("%p", b)}
} else {
return newError("argument 31 to `id()` unsupported got=%T", arg.Type())
}
}

20
builtins/oct.go Normal file
View File

@@ -0,0 +1,20 @@
package builtins
import (
"fmt"
"monkey/object"
"strconv"
)
// Oct ...
func Oct(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("wrong number of arguments. got=%d, want=1",
len(args))
}
if i, ok := args[0].(*object.Integer); ok {
return &object.String{Value: fmt.Sprintf("0%s", strconv.FormatInt(i.Value, 8))}
}
return newError("argument to `oct` not supported, got %s", args[0].Type())
}

19
builtins/ord.go Normal file
View File

@@ -0,0 +1,19 @@
package builtins
import "monkey/object"
// Ord ...
func Ord(args ...object.Object) object.Object {
if len(args) != 1 {
return newError("wrong number of arguments. got=%d, want=1",
len(args))
}
if s, ok := args[0].(*object.String); ok {
if len(s.Value) == 1 {
return &object.Integer{Value: int64(s.Value[0])}
}
return newError("`ord()` expected a character but got string of length %d", len(s.Value))
}
return newError("argument to `ord` not supported, got %s", args[0].Type())
}

34
builtins/pow.go Normal file
View File

@@ -0,0 +1,34 @@
package builtins
import "monkey/object"
func pow(x, y int64) int64 {
p := int64(1)
for y > 0 {
if y&1 != 0 {
p *= x
}
y >>= 1
x *= x
}
return p
}
// Pow ...
func Pow(args ...object.Object) object.Object {
if len(args) != 2 {
return newError("wrong number of arguments. got=%d, want=2",
len(args))
}
if x, ok := args[0].(*object.Integer); ok {
if y, ok := args[1].(*object.Integer); ok {
value := pow(x.Value, y.Value)
return &object.Integer{Value: value}
} else {
return newError("expected argument #2 to `pow` to be `int` got=%s", args[1].Type())
}
} else {
return newError("expected argument #1 to `pow` to be `int` got=%s", args[0].Type())
}
}

View File

@@ -879,11 +879,11 @@ func TestBuiltins(t *testing.T) {
`,
expectedConstants: []interface{}{1},
expectedInstructions: []code.Instructions{
code.Make(code.OpGetBuiltin, 11),
code.Make(code.OpGetBuiltin, 18),
code.Make(code.OpArray, 0),
code.Make(code.OpCall, 1),
code.Make(code.OpPop),
code.Make(code.OpGetBuiltin, 15),
code.Make(code.OpGetBuiltin, 25),
code.Make(code.OpArray, 0),
code.Make(code.OpConstant, 0),
code.Make(code.OpCall, 2),
@@ -894,7 +894,7 @@ func TestBuiltins(t *testing.T) {
input: `fn() { return len([]) }`,
expectedConstants: []interface{}{
[]code.Instructions{
code.Make(code.OpGetBuiltin, 11),
code.Make(code.OpGetBuiltin, 18),
code.Make(code.OpArray, 0),
code.Make(code.OpCall, 1),
code.Make(code.OpReturn),