add readUntil

This commit is contained in:
2023-06-29 00:57:52 +01:00
parent 9649c33217
commit af934e0429
18 changed files with 302 additions and 103 deletions

View File

@@ -1,6 +1,8 @@
package main
import "strings"
import (
"strings"
)
func anyToBool(x any) bool {
switch x := x.(type) {
@@ -16,8 +18,8 @@ func anyToBool(x any) bool {
if y, ok := x.obj["__Boolean__"]; ok {
val, err := runCall(
call{
callable: y,
args: []any{},
Callable: y,
Args: []any{},
}, stack{}, 0)
if err.EXISTS {
return false

View File

@@ -1,6 +1,8 @@
package main
import "fmt"
import (
"fmt"
)
func ArByte(Byte byte) ArObject {
obj := ArObject{

View File

@@ -192,8 +192,8 @@ func makeGlobal() ArObject {
if callable, ok := x.obj["__fraction__"]; ok {
resp, err := runCall(
call{
callable: callable,
args: []any{},
Callable: callable,
Args: []any{},
},
stack{},
0,

View File

@@ -8,11 +8,11 @@ import (
var callCompile = makeRegex("( *)(.|\n)+\\((.|\n)*\\)( *)")
type call struct {
callable any
args []any
code string
line int
path string
Callable any
Args []any
Code string
Line int
Path string
}
type Callable struct {
@@ -61,18 +61,18 @@ func parseCall(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool,
if !works {
return nil, false, ArErr{"Syntax Error", "invalid call", code.line, code.path, code.realcode, true}, 1
}
return call{callable: callable, args: arguments, line: code.line, code: code.realcode, path: code.path}, true, ArErr{}, 1
return call{Callable: callable, Args: arguments, Line: code.line, Code: code.realcode, Path: code.path}, true, ArErr{}, 1
}
func runCall(c call, stack stack, stacklevel int) (any, ArErr) {
var callable any = c.callable
switch x := c.callable.(type) {
var callable any = c.Callable
switch x := c.Callable.(type) {
case builtinFunc:
callable = x
case Callable:
callable = x
default:
callable_, err := runVal(c.callable, stack, stacklevel+1)
callable_, err := runVal(c.Callable, stack, stacklevel+1)
if err.EXISTS {
return nil, err
}
@@ -82,9 +82,9 @@ func runCall(c call, stack stack, stacklevel int) (any, ArErr) {
x,
[]any{"__call__"},
true,
c.line,
c.code,
c.path,
c.Line,
c.Code,
c.Path,
}, stack, stacklevel+1)
if !err.EXISTS {
callable = callable_
@@ -95,7 +95,7 @@ func runCall(c call, stack stack, stacklevel int) (any, ArErr) {
}
args := []any{}
level := append(stack, newscope())
for _, arg := range c.args {
for _, arg := range c.Args {
resp, err := runVal(arg, level, stacklevel+1)
if err.EXISTS {
return nil, err
@@ -109,20 +109,20 @@ func runCall(c call, stack stack, stacklevel int) (any, ArErr) {
resp = AnyToArValid(resp)
if err.EXISTS {
if err.line == 0 {
err.line = c.line
err.line = c.Line
}
if err.path == "" {
err.path = c.path
err.path = c.Path
}
if err.code == "" {
err.code = c.code
err.code = c.Code
}
}
return resp, err
case Callable:
debugPrintln(x.name, args)
if len(x.params) != len(args) {
return nil, ArErr{"Runtime Error", "expected " + fmt.Sprint(len(x.params)) + " arguments, got " + fmt.Sprint(len(args)), c.line, c.path, c.code, true}
return nil, ArErr{"Runtime Error", "expected " + fmt.Sprint(len(x.params)) + " arguments, got " + fmt.Sprint(len(args)), c.Line, c.Path, c.Code, true}
}
l := anymap{}
for i, param := range x.params {
@@ -131,7 +131,7 @@ func runCall(c call, stack stack, stacklevel int) (any, ArErr) {
resp, err := runVal(x.run, append(x.stack, Map(l)), stacklevel+1)
return ThrowOnNonLoop(openReturn(resp), err)
}
return nil, ArErr{"Runtime Error", "type '" + typeof(callable) + "' is not callable", c.line, c.path, c.code, true}
return nil, ArErr{"Runtime Error", "type '" + typeof(callable) + "' is not callable", c.Line, c.Path, c.Code, true}
}
func builtinCall(callable any, args []any) (any, ArErr) {

View File

@@ -15,11 +15,11 @@ var indexGetCompile = makeRegex(`(.|\n)+\[(.|\n)+\]( *)`)
type ArMapGet struct {
VAL any
args []any
includeConstuctors bool
line int
code string
path string
Args []any
IncludeConstuctors bool
Line int
Code string
Path string
}
func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) {
@@ -29,33 +29,33 @@ func mapGet(r ArMapGet, stack stack, stacklevel int) (any, ArErr) {
}
switch m := resp.(type) {
case ArObject:
if r.includeConstuctors {
if obj, ok := m.obj[r.args[0]]; ok {
if r.IncludeConstuctors {
if obj, ok := m.obj[r.Args[0]]; ok {
return obj, ArErr{}
}
}
if callable, ok := m.obj["__getindex__"]; ok {
resp, err := runCall(call{
callable: callable,
args: r.args,
line: r.line,
path: r.path,
code: r.code,
Callable: callable,
Args: r.Args,
Line: r.Line,
Path: r.Path,
Code: r.Code,
}, stack, stacklevel+1)
return resp, err
}
}
key, err := runVal(r.args[0], stack, stacklevel+1)
key, err := runVal(r.Args[0], stack, stacklevel+1)
if err.EXISTS {
return nil, err
}
return nil, ArErr{
"TypeError",
"cannot read " + anyToArgon(key, true, true, 3, 0, false, 0) + " from type '" + typeof(resp) + "'",
r.line,
r.path,
r.code,
r.Line,
r.Path,
r.Code,
true,
}
}

View File

@@ -11,7 +11,7 @@ import (
var imported = make(map[string]ArObject)
var importing = make(map[string]bool)
var modules_folder = "argon_modules"
const modules_folder = "argon_modules"
func FileExists(filename string) bool {
if _, err := os.Stat(filename); err == nil {
@@ -36,8 +36,10 @@ func readFile(path string) []UNPARSEcode {
// optionally, resize scanner's capacity for lines over 64K, see next example
output := []UNPARSEcode{}
line := 1
textOutput := []string{}
for scanner.Scan() {
text := scanner.Text()
textOutput = append(textOutput, text)
output = append(output, UNPARSEcode{text, text, line, path})
line++
}
@@ -102,8 +104,8 @@ func importMod(realpath string, origin string, main bool, global ArObject) (ArOb
}
importing[p] = true
codelines := readFile(p)
translated, translationerr := translate(codelines)
if translationerr.EXISTS {
return ArObject{}, translationerr
}

View File

@@ -12,6 +12,12 @@ type stack = []ArObject
const VERSION = "3.0.0"
// Example struct
type Person struct {
Name string
Age int
}
func newscope() ArObject {
return Map(anymap{})
}

View File

@@ -15,7 +15,7 @@ var octalCompile = makeRegex("( *)(-)?(0o[0-7]+(\\.[0-7]+)?(e((\\-|\\+)?([0-9]+(
type number = *big.Rat
// create a new number type
func newNumber() *big.Rat {
func newNumber() number {
return new(big.Rat)
}

View File

@@ -8,11 +8,11 @@ import (
var genericImportCompiled = makeRegex(`import( )+(.|\n)+(( )+as( )+([a-zA-Z_]|(\p{L}\p{M}*))([a-zA-Z0-9_]|(\p{L}\p{M}*))*)?( *)`)
type ArImport struct {
filePath any
values any
code string
line int
path string
FilePath any
Values any
Code string
Line int
Path string
}
func isGenericImport(code UNPARSEcode) bool {
@@ -75,26 +75,26 @@ func parseGenericImport(code UNPARSEcode, index int, codeline []UNPARSEcode) (Ar
}
func runImport(importOBJ ArImport, stack stack, stacklevel int) (any, ArErr) {
val, err := runVal(importOBJ.filePath, stack, stacklevel+1)
val, err := runVal(importOBJ.FilePath, stack, stacklevel+1)
val = ArValidToAny(val)
if err.EXISTS {
return nil, err
}
if typeof(val) != "string" {
return nil, ArErr{"Type Error", "import requires a string, got type '" + typeof(val) + "'", importOBJ.line, importOBJ.path, importOBJ.code, true}
return nil, ArErr{"Type Error", "import requires a string, got type '" + typeof(val) + "'", importOBJ.Line, importOBJ.Path, importOBJ.Code, true}
}
path := val.(string)
parent := filepath.Dir(importOBJ.path)
parent := filepath.Dir(importOBJ.Path)
stackMap, err := importMod(path, parent, false, stack[0])
if err.EXISTS {
if err.line == 0 {
err.line = importOBJ.line
err.line = importOBJ.Line
}
if err.path == "" {
err.path = importOBJ.path
err.path = importOBJ.Path
}
if err.code == "" {
err.code = importOBJ.code
err.code = importOBJ.Code
}
return nil, err
}
@@ -103,18 +103,18 @@ func runImport(importOBJ ArImport, stack stack, stacklevel int) (any, ArErr) {
return nil, ArErr{
"Import Error",
"could not find __setindex__ in module scope",
importOBJ.line,
importOBJ.path,
importOBJ.code,
importOBJ.Line,
importOBJ.Path,
importOBJ.Code,
true,
}
}
switch x := importOBJ.values.(type) {
switch x := importOBJ.Values.(type) {
case []string:
for _, v := range x {
val, ok := stackMap.obj[v]
if !ok {
return nil, ArErr{"Import Error", "could not find value " + anyToArgon(v, true, false, 3, 0, false, 0) + " in module " + anyToArgon(path, true, false, 3, 0, false, 0), importOBJ.line, importOBJ.path, importOBJ.code, true}
return nil, ArErr{"Import Error", "could not find value " + anyToArgon(v, true, false, 3, 0, false, 0) + " in module " + anyToArgon(path, true, false, 3, 0, false, 0), importOBJ.Line, importOBJ.Path, importOBJ.Code, true}
}
builtinCall(setindex, []any{v, val})
}

View File

@@ -1,6 +1,8 @@
package main
import "github.com/wadey/go-rounding"
import (
"github.com/wadey/go-rounding"
)
func floor(x number) number {

View File

@@ -18,9 +18,9 @@ func runVal(line any, stack stack, stacklevel int) (any, ArErr) {
return ArString(x), ArErr{}
case call:
if stackoverflow {
linenum = x.line
path = x.path
code = x.code
linenum = x.Line
path = x.Path
code = x.Code
break
}
return runCall(x, stack, stacklevel+1)
@@ -34,17 +34,17 @@ func runVal(line any, stack stack, stacklevel int) (any, ArErr) {
return runFactorial(x, stack, stacklevel+1)
case accessVariable:
if stackoverflow {
linenum = x.line
path = x.path
code = x.code
linenum = x.Line
path = x.Path
code = x.Code
break
}
return readVariable(x, stack)
case ArMapGet:
if stackoverflow {
linenum = x.line
path = x.path
code = x.code
linenum = x.Line
path = x.Path
code = x.Code
break
}
return mapGet(x, stack, stacklevel+1)
@@ -194,9 +194,9 @@ func runVal(line any, stack stack, stacklevel int) (any, ArErr) {
return runCreateMap(x, stack, stacklevel+1)
case ArImport:
if stackoverflow {
linenum = x.line
path = x.path
code = x.code
linenum = x.Line
path = x.Path
code = x.Code
break
}
return runImport(x, stack, stacklevel+1)

View File

@@ -1,6 +1,8 @@
package main
import "fmt"
import (
"fmt"
)
func ArSequence(a ...any) (any, ArErr) {
if len(a) < 1 || len(a) > 2 {

13
src/sha256.go Normal file
View File

@@ -0,0 +1,13 @@
package main
import (
"crypto/sha256"
"fmt"
)
func sha256Hash(s string) string {
h := sha256.New()
h.Write([]byte(s))
bs := h.Sum(nil)
return fmt.Sprintf("%x", bs)
}

View File

@@ -2,6 +2,7 @@ package main
import (
"fmt"
"io"
"net"
"time"
)
@@ -66,6 +67,59 @@ func ArSocketClient(args ...any) (any, ArErr) {
}
return ArBuffer(buf[:n]), ArErr{}
}},
"readUntil": builtinFunc{
"readUntil",
func(args ...any) (any, ArErr) {
if len(args) != 1 {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Socket.readUntil() takes exactly 1 argument",
EXISTS: true,
}
}
if conn == nil {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Connection is closed",
EXISTS: true,
}
}
value := ArValidToAny(args[0])
if typeof(value) != "buffer" {
return ArObject{}, ArErr{
TYPE: "TypeError",
message: fmt.Sprintf("Socket.readUntil() argument must be a buffer, not %s", typeof(value)),
EXISTS: true,
}
}
endBuf := value.([]byte)
reader := io.Reader(conn)
buf := make([]byte, len(endBuf))
var data []byte
for {
_, err := reader.Read(buf)
if err != nil {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: fmt.Sprintf("Socket read failed: %s", err.Error()),
EXISTS: true,
}
}
data = append(data, buf[0])
if len(data) >= len(endBuf) {
dataSlice := data[len(data)-len(endBuf):]
for i := 0; i < len(endBuf); i++ {
if dataSlice[i] != endBuf[i] {
break
}
if i == len(endBuf)-1 {
return ArBuffer(data), ArErr{}
}
}
}
}
}},
"write": builtinFunc{
"write",
func(args ...any) (any, ArErr) {
@@ -237,6 +291,120 @@ func ArSocketServer(args ...any) (any, ArErr) {
return ArBuffer(buf[:n]), ArErr{}
},
},
"readUntil": builtinFunc{
"readUntil",
func(args ...any) (any, ArErr) {
if len(args) != 1 {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Socket.readUntil() takes exactly 1 argument",
EXISTS: true,
}
}
if conn == nil {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Connection is closed",
EXISTS: true,
}
}
value := ArValidToAny(args[0])
if typeof(value) != "buffer" {
return ArObject{}, ArErr{
TYPE: "TypeError",
message: fmt.Sprintf("Socket.readUntil() argument must be a buffer, not %s", typeof(value)),
EXISTS: true,
}
}
endBuf := value.([]byte)
var data []byte
buf := make([]byte, 1)
lookingAt := 0
for {
n, err := io.ReadFull(conn, buf)
if err != nil {
return ArBuffer(data), ArErr{}
}
chunk := buf[:n]
data = append(data, chunk...)
for i := 0; i < n; i++ {
if chunk[i] == endBuf[lookingAt] {
lookingAt++
if lookingAt == len(endBuf) {
data = append(data, chunk...)
return ArBuffer(data), ArErr{}
}
} else {
lookingAt = 0
}
}
}
}},
"clearTimeout": builtinFunc{
"clearTimeout",
func(args ...any) (any, ArErr) {
if len(args) != 0 {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Socket.clearTimeout() takes exactly 0 arguments",
EXISTS: true,
}
}
if conn == nil {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Connection is closed",
EXISTS: true,
}
}
conn.SetDeadline(time.Time{})
return ArObject{}, ArErr{}
},
},
"setTimeout": builtinFunc{
"setTimeout",
func(args ...any) (any, ArErr) {
if len(args) != 1 {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Socket.setTimeout() takes exactly 1 argument",
EXISTS: true,
}
}
if typeof(args[0]) != "number" {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Socket timeout must be a number",
EXISTS: true,
}
}
if conn == nil {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Connection is closed",
EXISTS: true,
}
}
timeout := args[0].(number)
if timeout.Denom().Int64() != 1 {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: "Socket timeout must be an integer",
EXISTS: true,
}
}
err := conn.SetDeadline(time.Now().Add(time.Duration(timeout.Num().Int64()) * time.Millisecond))
if err != nil {
return ArObject{}, ArErr{
TYPE: "SocketError",
message: err.Error(),
EXISTS: true,
}
}
return ArObject{}, ArErr{}
},
},
"write": builtinFunc{
"write",
func(args ...any) (any, ArErr) {

View File

@@ -1,6 +1,8 @@
package main
import "fmt"
import (
"fmt"
)
type keyCache map[any]any
@@ -71,8 +73,8 @@ func compare(a, b any) (bool, error) {
if y, ok := x.obj["__LessThan__"]; ok {
resp, err := runCall(
call{
callable: y,
args: []any{b},
Callable: y,
Args: []any{b},
}, stack{}, 0)
if !err.EXISTS {
return anyToBool(resp), nil

View File

@@ -36,7 +36,7 @@ func ArThread(args ...any) (any, ArErr) {
}
hasrun = true
go func() {
resp, err = runCall(call{callable: tocall, args: []any{}}, nil, 0)
resp, err = runCall(call{Callable: tocall, Args: []any{}}, nil, 0)
wg <- true
}()
return nil, ArErr{}

View File

@@ -77,8 +77,8 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored
if callable, ok := x.obj["__string__"]; ok && !quote {
val, err := runCall(
call{
callable: callable,
args: []any{},
Callable: callable,
Args: []any{},
},
stack{},
0,
@@ -90,8 +90,8 @@ func anyToArgon(x any, quote bool, simplify bool, depth int, indent int, colored
} else if callable, ok := x.obj["__repr__"]; ok {
val, err := runCall(
call{
callable: callable,
args: []any{},
Callable: callable,
Args: []any{},
},
stack{},
0,

View File

@@ -37,10 +37,10 @@ var blockedVariableNames = map[string]bool{
}
type accessVariable struct {
name string
line int
code string
path string
Name string
Line int
Code string
Path string
}
type setVariable struct {
@@ -72,7 +72,7 @@ func isVariable(code UNPARSEcode) bool {
func parseVariable(code UNPARSEcode) (accessVariable, bool, ArErr, int) {
name := strings.TrimSpace(code.code)
return accessVariable{name: name, code: code.realcode, line: code.line, path: code.path}, true, ArErr{}, 1
return accessVariable{Name: name, Code: code.realcode, Line: code.line, Path: code.path}, true, ArErr{}, 1
}
func readVariable(v accessVariable, stack stack) (any, ArErr) {
@@ -81,7 +81,7 @@ func readVariable(v accessVariable, stack stack) (any, ArErr) {
if !ok {
continue
}
contains, err := builtinCall(callable, []any{v.name})
contains, err := builtinCall(callable, []any{v.Name})
if err.EXISTS {
return nil, err
}
@@ -90,10 +90,10 @@ func readVariable(v accessVariable, stack stack) (any, ArErr) {
if !ok {
continue
}
return builtinCall(callable, []any{v.name})
return builtinCall(callable, []any{v.Name})
}
}
return nil, ArErr{"Name Error", "variable \"" + v.name + "\" does not exist", v.line, v.path, v.code, true}
return nil, ArErr{"Name Error", "variable \"" + v.Name + "\" does not exist", v.Line, v.Path, v.Code, true}
}
func isSetVariable(code UNPARSEcode) bool {
@@ -220,14 +220,14 @@ func setVariableValue(v setVariable, stack stack, stacklevel int) (any, ArErr) {
if !ok {
return nil, ArErr{"Type Error", "stack doesn't have __setindex__", v.line, v.path, v.code, true}
}
_, err := builtinCall(stackcallable, []any{v.toset.(accessVariable).name, resp})
_, err := builtinCall(stackcallable, []any{v.toset.(accessVariable).Name, resp})
if err.EXISTS {
return nil, err
}
} else {
switch x := v.toset.(type) {
case accessVariable:
name := x.name
name := x.Name
hasSet := false
if v.function {
resp = Callable{name, v.params, v.value, v.code, stack, v.line}
@@ -263,10 +263,10 @@ func setVariableValue(v setVariable, stack stack, stacklevel int) (any, ArErr) {
if err.EXISTS {
return nil, err
}
if len(x.args) != 1 {
if len(x.Args) != 1 {
return nil, ArErr{"Runtime Error", "cannot set by slice", v.line, v.path, v.code, true}
}
key, err := runVal(x.args[0], stack, stacklevel+1)
key, err := runVal(x.Args[0], stack, stacklevel+1)
key = ArValidToAny(key)
if err.EXISTS {
return nil, err
@@ -276,11 +276,11 @@ func setVariableValue(v setVariable, stack stack, stacklevel int) (any, ArErr) {
if _, ok := y.obj["__setindex__"]; ok {
callable := y.obj["__setindex__"]
_, err := runCall(call{
callable: callable,
args: []any{key, resp},
line: v.line,
path: v.path,
code: v.code,
Callable: callable,
Args: []any{key, resp},
Line: v.line,
Path: v.path,
Code: v.code,
}, stack, stacklevel+1)
if err.EXISTS {
return nil, err
@@ -322,7 +322,7 @@ func runDelete(d ArDelete, stack stack, stacklevel int) (any, ArErr) {
if !ok {
continue
}
contains, err := builtinCall(callable, []any{x.name})
contains, err := builtinCall(callable, []any{x.Name})
if err.EXISTS {
return nil, err
}
@@ -331,19 +331,19 @@ func runDelete(d ArDelete, stack stack, stacklevel int) (any, ArErr) {
if !ok {
continue
}
return builtinCall(callable, []any{x.name})
return builtinCall(callable, []any{x.Name})
}
}
return nil, ArErr{"Name Error", "variable \"" + x.name + "\" does not exist", d.line, d.path, d.code, true}
return nil, ArErr{"Name Error", "variable \"" + x.Name + "\" does not exist", d.line, d.path, d.code, true}
case ArMapGet:
respp, err := runVal(x.VAL, stack, stacklevel+1)
if err.EXISTS {
return nil, err
}
if len(x.args) != 1 {
if len(x.Args) != 1 {
return nil, ArErr{"Runtime Error", "can't delete by slice", d.line, d.path, d.code, true}
}
key, err := runVal(x.args[0], stack, stacklevel+1)
key, err := runVal(x.Args[0], stack, stacklevel+1)
if err.EXISTS {
return nil, err
}