add buffer and byte objects, making socket read and write faster

This commit is contained in:
2023-06-24 10:30:34 +01:00
parent f63229c6f8
commit 4ca158cc96
8 changed files with 354 additions and 50 deletions

View File

@@ -8,6 +8,10 @@ func AnyToArValid(arr any) any {
return ArString(arr) return ArString(arr)
case anymap: case anymap:
return Map(arr) return Map(arr)
case []byte:
return ArBuffer(arr)
case byte:
return ArByte(arr)
default: default:
return arr return arr
} }

194
src/buffer.go Normal file
View File

@@ -0,0 +1,194 @@
package main
import "fmt"
func ArByte(Byte byte) ArObject {
obj := ArObject{
obj: anymap{
"__name__": "byte",
"__value__": Byte,
},
}
obj.obj["__string__"] = builtinFunc{
"__string__",
func(a ...any) (any, ArErr) {
return "<byte>", ArErr{}
},
}
obj.obj["__repr__"] = builtinFunc{
"__repr__",
func(a ...any) (any, ArErr) {
return "<byte>", ArErr{}
},
}
obj.obj["number"] = builtinFunc{
"number",
func(a ...any) (any, ArErr) {
return newNumber().SetInt64(int64(Byte)), ArErr{}
},
}
obj.obj["from"] = builtinFunc{
"from",
func(a ...any) (any, ArErr) {
if len(a) == 0 {
return nil, ArErr{
TYPE: "TypeError",
message: "expected at least 1 argument, got 0",
EXISTS: true,
}
}
a[0] = ArValidToAny(a[0])
switch x := a[0].(type) {
case number:
if x.Denom().Cmp(one.Denom()) != 0 {
return nil, ArErr{
TYPE: "TypeError",
message: "expected integer, got " + fmt.Sprint(x),
EXISTS: true,
}
}
n := x.Num().Int64()
if n > 255 || n < 0 {
return nil, ArErr{
TYPE: "ValueError",
message: "expected number between 0 and 255, got " + fmt.Sprint(floor(x).Num().Int64()),
EXISTS: true,
}
}
Byte = byte(n)
case string:
if len(x) != 1 {
return nil, ArErr{
TYPE: "ValueError",
message: "expected string of length 1, got " + fmt.Sprint(len(x)),
EXISTS: true,
}
}
Byte = byte(x[0])
default:
return nil, ArErr{
TYPE: "TypeError",
message: "expected number or string, got " + typeof(x),
EXISTS: true,
}
}
return obj, ArErr{}
},
}
return obj
}
func ArBuffer(buf []byte) ArObject {
obj := ArObject{
obj: anymap{
"__name__": "buffer",
"__value__": buf,
"length": newNumber().SetInt64(int64(len(buf))),
},
}
obj.obj["__string__"] = builtinFunc{
"__string__",
func(a ...any) (any, ArErr) {
return "<buffer>", ArErr{}
},
}
obj.obj["__repr__"] = builtinFunc{
"__repr__",
func(a ...any) (any, ArErr) {
return "<buffer>", ArErr{}
},
}
obj.obj["from"] = builtinFunc{
"from",
func(a ...any) (any, ArErr) {
if len(a) == 0 {
return nil, ArErr{
TYPE: "TypeError",
message: "expected at least 1 argument, got 0",
EXISTS: true,
}
}
a[0] = ArValidToAny(a[0])
switch x := a[0].(type) {
case string:
buf = []byte(x)
case []byte:
buf = x
case []any:
outputbuf := []byte{}
for _, v := range x {
switch y := v.(type) {
case number:
if y.Denom().Cmp(one.Denom()) != 0 {
return nil, ArErr{
TYPE: "TypeError",
message: "Cannot convert non-integer to byte",
EXISTS: true,
}
}
outputbuf = append(outputbuf, byte(y.Num().Int64()))
default:
return nil, ArErr{
TYPE: "TypeError",
message: "Cannot convert " + typeof(v) + " to byte",
EXISTS: true,
}
}
}
buf = outputbuf
default:
return nil, ArErr{
TYPE: "TypeError",
message: "expected string or []byte, got " + typeof(x),
EXISTS: true,
}
}
obj.obj["__value__"] = buf
obj.obj["length"] = newNumber().SetInt64(int64(len(buf)))
return obj, ArErr{}
},
}
obj.obj["to"] = builtinFunc{
"to",
func(a ...any) (any, ArErr) {
if len(a) != 1 {
return nil, ArErr{
TYPE: "TypeError",
message: "expected 1 argument, got " + fmt.Sprint(len(a)),
EXISTS: true,
}
}
if typeof(a[0]) != "string" {
return nil, ArErr{
TYPE: "TypeError",
message: "expected string, got " + typeof(a[0]),
EXISTS: true,
}
}
Type := ArValidToAny(a[0]).(string)
switch Type {
case "string":
return ArString(string(buf)), ArErr{}
case "bytes":
output := []any{}
for _, v := range buf {
output = append(output, ArByte(v))
}
return ArArray(output), ArErr{}
case "array":
output := []any{}
for _, v := range buf {
output = append(output, newNumber().SetInt64(int64(v)))
}
return ArArray(output), ArErr{}
default:
return nil, ArErr{
TYPE: "TypeError",
message: "expected string, bytes or array, got '" + Type + "'",
EXISTS: true,
}
}
},
}
return obj
}

View File

@@ -63,6 +63,12 @@ func makeGlobal() ArObject {
} }
return nil, ArErr{TYPE: "TypeError", message: "Cannot convert '" + typeof(a[0]) + "' to hex", EXISTS: true} return nil, ArErr{TYPE: "TypeError", message: "Cannot convert '" + typeof(a[0]) + "' to hex", EXISTS: true}
}} }}
vars["buffer"] = builtinFunc{"buffer", func(a ...any) (any, ArErr) {
if len(a) != 0 {
return nil, ArErr{TYPE: "TypeError", message: "expected 0 arguments, got " + fmt.Sprint(len(a)), EXISTS: true}
}
return ArBuffer([]byte{}), ArErr{}
}}
vars["throwError"] = builtinFunc{"throwError", ArThrowError} vars["throwError"] = builtinFunc{"throwError", ArThrowError}
vars["array"] = builtinFunc{"array", func(a ...any) (any, ArErr) { vars["array"] = builtinFunc{"array", func(a ...any) (any, ArErr) {
if len(a) == 0 { if len(a) == 0 {

View File

@@ -67,16 +67,30 @@ func ArRead(args ...any) (any, ArErr) {
} }
return mimetype.String(), ArErr{} return mimetype.String(), ArErr{}
}}, }},
"bytes": builtinFunc{"bytes", func(...any) (any, ArErr) { "buffer": builtinFunc{"buffer", func(args ...any) (any, ArErr) {
if len(args) > 1 {
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "buffer takes 0 or 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
}
if len(args) == 1 {
if typeof(args[0]) != "number" {
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "buffer takes a number not type '" + typeof(args[0]) + "'", EXISTS: true}
}
size := args[0].(number)
if size.Denom().Int64() != 1 {
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "buffer takes an integer not type '" + typeof(args[0]) + "'", EXISTS: true}
}
buf := make([]byte, size.Num().Int64())
n, err := file.Read(buf)
if err != nil {
return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
}
return ArBuffer(buf[:n]), ArErr{}
}
bytes, err := readbinary(file) bytes, err := readbinary(file)
if err != nil { if err != nil {
return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true} return ArObject{}, ArErr{TYPE: "Runtime Error", message: err.Error(), EXISTS: true}
} }
ArBinary := []any{} return ArBuffer(bytes), ArErr{}
for _, b := range bytes {
ArBinary = append(ArBinary, newNumber().SetInt64(int64(b)))
}
return ArBinary, ArErr{}
}}, }},
}), ArErr{} }), ArErr{}
} }
@@ -105,6 +119,17 @@ func ArWrite(args ...any) (any, ArErr) {
file.Write([]byte(args[0].(string))) file.Write([]byte(args[0].(string)))
return nil, ArErr{} return nil, ArErr{}
}}, }},
"buffer": builtinFunc{"buffer", func(args ...any) (any, ArErr) {
if len(args) != 1 {
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "buffer takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}
}
if typeof(args[0]) != "buffer" {
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "buffer takes a buffer not type '" + typeof(args[0]) + "'", EXISTS: true}
}
args[0] = ArValidToAny(args[0])
file.Write(args[0].([]byte))
return nil, ArErr{}
}},
"json": builtinFunc{"json", func(args ...any) (any, ArErr) { "json": builtinFunc{"json", func(args ...any) (any, ArErr) {
if len(args) != 1 { if len(args) != 1 {
return ArObject{}, ArErr{TYPE: "Runtime Error", message: "json takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true} return ArObject{}, ArErr{TYPE: "Runtime Error", message: "json takes 1 argument, got " + fmt.Sprint(len(args)), EXISTS: true}

View File

@@ -216,7 +216,7 @@ func runVal(line any, stack stack, stacklevel int) (any, ArErr) {
break break
} }
return runTryCatch(x, stack, stacklevel+1) return runTryCatch(x, stack, stacklevel+1)
case bool, ArObject, number, nil, Callable: case bool, ArObject, number, nil, Callable, builtinFunc, anymap:
return x, ArErr{} return x, ArErr{}
} }
if stackoverflow { if stackoverflow {

View File

@@ -3,6 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"net" "net"
"time"
) )
func ArSocket(args ...any) (any, ArErr) { func ArSocket(args ...any) (any, ArErr) {
@@ -46,6 +47,13 @@ func ArSocket(args ...any) (any, ArErr) {
"accept": builtinFunc{ "accept": builtinFunc{
"accept", "accept",
func(args ...any) (any, ArErr) { func(args ...any) (any, ArErr) {
if ln == nil {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Socket is closed",
EXISTS: true,
}
}
conn, err := ln.Accept() conn, err := ln.Accept()
if err != nil { if err != nil {
return ArObject{}, ArErr{ return ArObject{}, ArErr{
@@ -61,13 +69,14 @@ func ArSocket(args ...any) (any, ArErr) {
if len(args) != 1 { if len(args) != 1 {
return ArObject{}, ArErr{ return ArObject{}, ArErr{
TYPE: "SocketError", TYPE: "SocketError",
message: "Socket.read() takes exactly 1 argument", message: "Socket.readData() takes exactly 1 argument",
EXISTS: true, EXISTS: true,
} }
} else if typeof(args[0]) != "number" { }
if conn == nil {
return ArObject{}, ArErr{ return ArObject{}, ArErr{
TYPE: "SocketError", TYPE: "SocketError",
message: "Socket.read() argument must be a number", message: "Connection is closed",
EXISTS: true, EXISTS: true,
} }
} }
@@ -80,33 +89,7 @@ func ArSocket(args ...any) (any, ArErr) {
EXISTS: true, EXISTS: true,
} }
} }
return ArString(string(buf[:n])), ArErr{} return ArBuffer(buf[:n]), ArErr{}
},
},
"writeData": builtinFunc{
"writeData",
func(args ...any) (any, ArErr) {
if len(args) != 1 {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Socket.writeData() takes exactly 1 argument",
EXISTS: true,
}
}
data := ArValidToAny(args[0])
switch x := data.(type) {
case []any:
bytes := []byte{}
for _, v := range x {
bytes = append(bytes, byte(v.(number).Num().Int64()))
}
conn.Write(bytes)
return nil, ArErr{}
}
return nil, ArErr{
TYPE: "SocketError",
message: "Socket.writeData() argument must be a array of numbers",
}
}, },
}, },
"write": builtinFunc{ "write": builtinFunc{
@@ -115,24 +98,53 @@ func ArSocket(args ...any) (any, ArErr) {
if len(args) != 1 { if len(args) != 1 {
return ArObject{}, ArErr{ return ArObject{}, ArErr{
TYPE: "SocketError", TYPE: "SocketError",
message: "Socket.write() takes exactly 1 argument", message: "Socket.writeData() takes exactly 1 argument",
EXISTS: true, EXISTS: true,
} }
} else if typeof(args[0]) != "string" { }
if conn == nil {
return ArObject{}, ArErr{ return ArObject{}, ArErr{
TYPE: "SocketError", TYPE: "SocketError",
message: "Socket.write() argument must be a string", message: "Connection is closed",
EXISTS: true, EXISTS: true,
} }
} }
data := ArValidToAny(args[0]).(string) data := ArValidToAny(args[0])
conn.Write([]byte(data)) switch x := data.(type) {
case []any:
bytes := []byte{}
for _, v := range x {
if typeof(v) != "number" && v.(number).Denom().Int64() != 1 {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Socket.writeData() argument must be a array of integers",
EXISTS: true,
}
}
bytes = append(bytes, byte(v.(number).Num().Int64()))
}
conn.Write(bytes)
return nil, ArErr{} return nil, ArErr{}
case []byte:
conn.Write(x)
return nil, ArErr{}
}
return nil, ArErr{
TYPE: "SocketError",
message: "Socket.writeData() argument must be a array of numbers",
}
}, },
}, },
"close": builtinFunc{ "close": builtinFunc{
"close", "close",
func(args ...any) (any, ArErr) { func(args ...any) (any, ArErr) {
if conn == nil {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Connection is already closed",
EXISTS: true,
}
}
conn.Close() conn.Close()
conn = nil conn = nil
return nil, ArErr{} return nil, ArErr{}
@@ -141,12 +153,31 @@ func ArSocket(args ...any) (any, ArErr) {
"isClosed": builtinFunc{ "isClosed": builtinFunc{
"isClosed", "isClosed",
func(args ...any) (any, ArErr) { func(args ...any) (any, ArErr) {
return conn == nil, ArErr{} if conn == nil {
return true, ArErr{}
}
conn.SetWriteDeadline(time.Now().Add(1 * time.Millisecond))
_, err := conn.Write([]byte{})
conn.SetWriteDeadline(time.Time{})
if err != nil {
conn.Close()
conn = nil
return true, ArErr{}
}
return false, ArErr{}
}, },
}, },
"RemoteAddr": builtinFunc{ "RemoteAddr": builtinFunc{
"RemoteAddr", "RemoteAddr",
func(args ...any) (any, ArErr) { func(args ...any) (any, ArErr) {
if conn == nil {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Connection is closed",
EXISTS: true,
}
}
return ArString(conn.RemoteAddr().String()), ArErr{} return ArString(conn.RemoteAddr().String()), ArErr{}
}, },
}, },
@@ -162,6 +193,13 @@ func ArSocket(args ...any) (any, ArErr) {
"close": builtinFunc{ "close": builtinFunc{
"close", "close",
func(args ...any) (any, ArErr) { func(args ...any) (any, ArErr) {
if ln == nil {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Socket is already closed",
EXISTS: true,
}
}
ln.Close() ln.Close()
ln = nil ln = nil
return nil, ArErr{} return nil, ArErr{}

View File

@@ -2,10 +2,12 @@ package main
import ( import (
"fmt" "fmt"
"sync"
"time" "time"
) )
var timing = anymap{} var timing = anymap{}
var timingSync = sync.RWMutex{}
var ArTerm = Map(anymap{ var ArTerm = Map(anymap{
"log": builtinFunc{"log", func(args ...any) (any, ArErr) { "log": builtinFunc{"log", func(args ...any) (any, ArErr) {
@@ -100,7 +102,9 @@ var ArTerm = Map(anymap{
if len(args) > 0 { if len(args) > 0 {
id = ArValidToAny(args[0]) id = ArValidToAny(args[0])
} }
timingSync.Lock()
timing[id] = time.Now() timing[id] = time.Now()
timingSync.Unlock()
return nil, ArErr{} return nil, ArErr{}
}, },
}, },
@@ -109,11 +113,15 @@ var ArTerm = Map(anymap{
if len(args) > 0 { if len(args) > 0 {
id = ArValidToAny(args[0]) id = ArValidToAny(args[0])
} }
timingSync.RLock()
if _, ok := timing[id]; !ok { if _, ok := timing[id]; !ok {
return nil, ArErr{TYPE: "TypeError", message: "Cannot find timer with id '" + fmt.Sprint(id) + "'", EXISTS: true} return nil, ArErr{TYPE: "TypeError", message: "Cannot find timer with id '" + fmt.Sprint(id) + "'", EXISTS: true}
} }
timesince := time.Since(timing[id].(time.Time)) timesince := time.Since(timing[id].(time.Time))
timingSync.RUnlock()
timingSync.Lock()
delete(timing, id) delete(timing, id)
timingSync.Unlock()
if id == nil { if id == nil {
id = "Timer" id = "Timer"
} }

View File

@@ -12,7 +12,6 @@ import (
) )
func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored bool, plain int) string { func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored bool, plain int) string {
x = ArValidToAny(x)
output := []string{} output := []string{}
maybenewline := "" maybenewline := ""
if plain == 1 { if plain == 1 {
@@ -75,7 +74,37 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored
output = append(output, "\x1b[0m") output = append(output, "\x1b[0m")
} }
case ArObject: case ArObject:
if callable, ok := x.obj["__string__"]; ok && !quote {
val, err := runCall(
call{
callable: callable,
args: []any{},
},
stack{},
0,
)
if !err.EXISTS {
output = append(output, anyToArgon(val, false, simplify, depth, indent, colored, plain))
break
}
} else if callable, ok := x.obj["__repr__"]; ok {
val, err := runCall(
call{
callable: callable,
args: []any{},
},
stack{},
0,
)
if !err.EXISTS {
output = append(output, anyToArgon(val, false, simplify, depth, indent, colored, plain))
break
}
} else if val, ok := x.obj["__value__"]; ok {
output = append(output, anyToArgon(val, quote, simplify, depth, indent, colored, plain))
break
}
output = append(output, "<object>")
case anymap: case anymap:
if len(x) == 0 { if len(x) == 0 {
return "{}" return "{}"