Add file operations
This commit is contained in:
@@ -45,6 +45,11 @@ var Builtins = map[string]*object.Builtin{
|
|||||||
"max": {Name: "max", Fn: Max},
|
"max": {Name: "max", Fn: Max},
|
||||||
"sorted": {Name: "sorted", Fn: Sorted},
|
"sorted": {Name: "sorted", Fn: Sorted},
|
||||||
"reversed": {Name: "reversed", Fn: Reversed},
|
"reversed": {Name: "reversed", Fn: Reversed},
|
||||||
|
"open": {Name: "open", Fn: Open},
|
||||||
|
"close": {Name: "close", Fn: Close},
|
||||||
|
"write": {Name: "write", Fn: Write},
|
||||||
|
"read": {Name: "read", Fn: Read},
|
||||||
|
"seek": {Name: "seek", Fn: Seek},
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuiltinsIndex ...
|
// BuiltinsIndex ...
|
||||||
|
|||||||
27
builtins/close.go
Normal file
27
builtins/close.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"monkey/object"
|
||||||
|
"monkey/typing"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Close ...
|
||||||
|
func Close(args ...object.Object) object.Object {
|
||||||
|
if err := typing.Check(
|
||||||
|
"close", args,
|
||||||
|
typing.ExactArgs(1),
|
||||||
|
typing.WithTypes(object.INTEGER_OBJ),
|
||||||
|
); err != nil {
|
||||||
|
return newError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
fd := int(args[0].(*object.Integer).Value)
|
||||||
|
|
||||||
|
err := syscall.Close(syscall.Handle(fd))
|
||||||
|
if err != nil {
|
||||||
|
return newError("IOError: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &object.Null{}
|
||||||
|
}
|
||||||
86
builtins/open.go
Normal file
86
builtins/open.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"monkey/object"
|
||||||
|
"monkey/typing"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Close ...
|
||||||
|
func parseMode(mode string) (int, error) {
|
||||||
|
var flag int
|
||||||
|
for _, c := range mode {
|
||||||
|
switch c {
|
||||||
|
case 'r':
|
||||||
|
if (flag & os.O_WRONLY) != 0 {
|
||||||
|
flag |= os.O_RDWR
|
||||||
|
} else {
|
||||||
|
log.Printf("r2")
|
||||||
|
flag |= os.O_RDONLY
|
||||||
|
}
|
||||||
|
case 'w':
|
||||||
|
if (flag & os.O_RDONLY) != 0 {
|
||||||
|
flag |= os.O_RDWR
|
||||||
|
} else {
|
||||||
|
flag |= os.O_WRONLY
|
||||||
|
}
|
||||||
|
case 'a':
|
||||||
|
flag |= os.O_APPEND
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("ValueError: mode string must be one of 'r', 'w', 'a', not '%c'", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag&os.O_WRONLY) != 0 || (flag&os.O_RDWR) != 0 {
|
||||||
|
log.Printf("c1")
|
||||||
|
flag |= os.O_CREATE
|
||||||
|
if (flag & os.O_APPEND) == 0 {
|
||||||
|
log.Printf("t1")
|
||||||
|
flag |= os.O_TRUNC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !((flag == os.O_RDONLY) || (flag&os.O_WRONLY != 0) || (flag&os.O_RDWR != 0)) {
|
||||||
|
return 0, fmt.Errorf("ValueError: mode string must be at least one of 'r', 'w', or 'rw'")
|
||||||
|
}
|
||||||
|
|
||||||
|
return flag, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open ...
|
||||||
|
func Open(args ...object.Object) object.Object {
|
||||||
|
if err := typing.Check(
|
||||||
|
"open", args,
|
||||||
|
typing.RangeOfArgs(1, 2),
|
||||||
|
typing.WithTypes(object.STRING_OBJ, object.STRING_OBJ),
|
||||||
|
); err != nil {
|
||||||
|
return newError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
filename string
|
||||||
|
mode = "r"
|
||||||
|
perm uint32 = 0640
|
||||||
|
)
|
||||||
|
|
||||||
|
filename = args[0].(*object.String).Value
|
||||||
|
|
||||||
|
if len(args) == 2 {
|
||||||
|
mode = args[1].(*object.String).Value
|
||||||
|
}
|
||||||
|
|
||||||
|
flag, err := parseMode(mode)
|
||||||
|
if err != nil {
|
||||||
|
return newError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := syscall.Open(filename, flag, perm)
|
||||||
|
if err != nil {
|
||||||
|
return newError("IOError: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &object.Integer{Value: int64(fd)}
|
||||||
|
}
|
||||||
40
builtins/read.go
Normal file
40
builtins/read.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"monkey/object"
|
||||||
|
"monkey/typing"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultBufferSize is the default buffer size
|
||||||
|
const DefaultBufferSize = 4096
|
||||||
|
|
||||||
|
// Read ...
|
||||||
|
func Read(args ...object.Object) object.Object {
|
||||||
|
if err := typing.Check(
|
||||||
|
"read", args,
|
||||||
|
typing.RangeOfArgs(1, 2),
|
||||||
|
typing.WithTypes(object.INTEGER_OBJ, object.INTEGER_OBJ),
|
||||||
|
); err != nil {
|
||||||
|
return newError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
fd int
|
||||||
|
n = DefaultBufferSize
|
||||||
|
)
|
||||||
|
|
||||||
|
fd = int(args[0].(*object.Integer).Value)
|
||||||
|
|
||||||
|
if len(args) == 2 {
|
||||||
|
n = int(args[1].(*object.Integer).Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, n)
|
||||||
|
n, err := syscall.Read(syscall.Handle(fd), buf)
|
||||||
|
if err != nil {
|
||||||
|
return newError("IOError: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &object.String{Value: string(buf[:n])}
|
||||||
|
}
|
||||||
37
builtins/seek.go
Normal file
37
builtins/seek.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"monkey/object"
|
||||||
|
"monkey/typing"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Seek ...
|
||||||
|
func Seek(args ...object.Object) object.Object {
|
||||||
|
if err := typing.Check(
|
||||||
|
"seek", args,
|
||||||
|
typing.RangeOfArgs(1, 3),
|
||||||
|
typing.WithTypes(object.INTEGER_OBJ, object.INTEGER_OBJ, object.INTEGER_OBJ),
|
||||||
|
); err != nil {
|
||||||
|
return newError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
fd int
|
||||||
|
whence = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
fd = int(args[0].(*object.Integer).Value)
|
||||||
|
offset := args[1].(*object.Integer).Value
|
||||||
|
|
||||||
|
if len(args) == 3 {
|
||||||
|
whence = int(args[2].(*object.Integer).Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
offset, err := syscall.Seek(syscall.Handle(fd), offset, whence)
|
||||||
|
if err != nil {
|
||||||
|
return newError("IOError: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &object.Integer{Value: offset}
|
||||||
|
}
|
||||||
28
builtins/write.go
Normal file
28
builtins/write.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package builtins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"monkey/object"
|
||||||
|
"monkey/typing"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Write ...
|
||||||
|
func Write(args ...object.Object) object.Object {
|
||||||
|
if err := typing.Check(
|
||||||
|
"write", args,
|
||||||
|
typing.ExactArgs(2),
|
||||||
|
typing.WithTypes(object.INTEGER_OBJ, object.INTEGER_OBJ),
|
||||||
|
); err != nil {
|
||||||
|
return newError(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
fd := int(args[0].(*object.Integer).Value)
|
||||||
|
data := []byte(args[1].(*object.String).Value)
|
||||||
|
|
||||||
|
n, err := syscall.Write(syscall.Handle(fd), data)
|
||||||
|
if err != nil {
|
||||||
|
return newError("IOError: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &object.Integer{Value: int64(n)}
|
||||||
|
}
|
||||||
@@ -899,11 +899,11 @@ func TestBuiltins(t *testing.T) {
|
|||||||
`,
|
`,
|
||||||
expectedConstants: []interface{}{1},
|
expectedConstants: []interface{}{1},
|
||||||
expectedInstructions: []code.Instructions{
|
expectedInstructions: []code.Instructions{
|
||||||
code.Make(code.OpGetBuiltin, 18),
|
code.Make(code.OpGetBuiltin, 19),
|
||||||
code.Make(code.OpArray, 0),
|
code.Make(code.OpArray, 0),
|
||||||
code.Make(code.OpCall, 1),
|
code.Make(code.OpCall, 1),
|
||||||
code.Make(code.OpPop),
|
code.Make(code.OpPop),
|
||||||
code.Make(code.OpGetBuiltin, 27),
|
code.Make(code.OpGetBuiltin, 29),
|
||||||
code.Make(code.OpArray, 0),
|
code.Make(code.OpArray, 0),
|
||||||
code.Make(code.OpConstant, 0),
|
code.Make(code.OpConstant, 0),
|
||||||
code.Make(code.OpCall, 2),
|
code.Make(code.OpCall, 2),
|
||||||
@@ -914,7 +914,7 @@ func TestBuiltins(t *testing.T) {
|
|||||||
input: `fn() { return len([]) }`,
|
input: `fn() { return len([]) }`,
|
||||||
expectedConstants: []interface{}{
|
expectedConstants: []interface{}{
|
||||||
[]code.Instructions{
|
[]code.Instructions{
|
||||||
code.Make(code.OpGetBuiltin, 18),
|
code.Make(code.OpGetBuiltin, 19),
|
||||||
code.Make(code.OpArray, 0),
|
code.Make(code.OpArray, 0),
|
||||||
code.Make(code.OpCall, 1),
|
code.Make(code.OpCall, 1),
|
||||||
code.Make(code.OpReturn),
|
code.Make(code.OpReturn),
|
||||||
|
|||||||
Reference in New Issue
Block a user