Add file operations
This commit is contained in:
@@ -45,6 +45,11 @@ var Builtins = map[string]*object.Builtin{
|
||||
"max": {Name: "max", Fn: Max},
|
||||
"sorted": {Name: "sorted", Fn: Sorted},
|
||||
"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 ...
|
||||
|
||||
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)}
|
||||
}
|
||||
Reference in New Issue
Block a user