From 5bac58bbf2b82bd30e5fc353d5103897ab56cf5c Mon Sep 17 00:00:00 2001 From: refaktor Date: Mon, 8 Apr 2024 12:21:38 +0200 Subject: [PATCH 1/6] changing Rye shell to basic ansi colors, so it themable in terminals and works in emacs ansi-term --- evaldo/repl.go | 2 +- examples/99beers.rye | 2 +- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evaldo/repl.go b/evaldo/repl.go index 329ec16e..3c7b1daa 100644 --- a/evaldo/repl.go +++ b/evaldo/repl.go @@ -305,7 +305,7 @@ func MaybeDisplayFailureOrError(es *env.ProgramState, genv *env.Idxs) { fmt.Println("\x1b[33m" + "Failure" + "\x1b[0m") } if es.ErrorFlag { - fmt.Println("\x1b[31;3m" + es.Res.Print(*genv)) + fmt.Println("\x1b[31m" + es.Res.Print(*genv)) switch err := es.Res.(type) { case env.Error: fmt.Println(err.CodeBlock.PositionAndSurroundingElements(*genv)) diff --git a/examples/99beers.rye b/examples/99beers.rye index 9a2a2134..3cf38cf4 100644 --- a/examples/99beers.rye +++ b/examples/99beers.rye @@ -1,5 +1,5 @@ - rye.!!!!__a<>|sdsd ; Testing with \word instead of |word for pipe-words +rye ; Testing with \word instead of |word for pipe-words ; function private creates a context, executes code in it and just returns the last value ; experimenting with using it for "ultra-private" environments and verbiage :) diff --git a/go.mod b/go.mod index 80f85b03..28c6fac5 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/mrz1836/postmark v1.6.4 github.com/pkg/term v1.1.0 github.com/refaktor/go-peg v0.0.0-20220116201714-31e3dfa8dc7d - github.com/refaktor/liner v1.2.6 + github.com/refaktor/liner v1.2.10 github.com/sashabaranov/go-openai v1.20.4 github.com/shirou/gopsutil/v3 v3.24.3 github.com/thomasberger/parsemail v1.2.6 diff --git a/go.sum b/go.sum index bc06eb52..20d6b878 100644 --- a/go.sum +++ b/go.sum @@ -158,8 +158,8 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/refaktor/go-peg v0.0.0-20220116201714-31e3dfa8dc7d h1:FXrWUGgPRzhaZIBho8zNLSrMp0VpP8E9+wbRRnJYlbE= github.com/refaktor/go-peg v0.0.0-20220116201714-31e3dfa8dc7d/go.mod h1:iIkrsFobLIWX8kQ6Oqj4cl4nwdMSE92DWpWwk9YlG9s= -github.com/refaktor/liner v1.2.6 h1:UtI+H2w5L9z6ASQ2nZlJCZ/9AB12sGYY0xgJUT2g8kg= -github.com/refaktor/liner v1.2.6/go.mod h1:ziZSGVYZ4OzZ9kbeB254MtIrxxQlDibULRQGlDi1iK8= +github.com/refaktor/liner v1.2.10 h1:MjbQj9EfNuSFnNk9zan37xpkNIRpsWKenyIBg7FZdVw= +github.com/refaktor/liner v1.2.10/go.mod h1:ziZSGVYZ4OzZ9kbeB254MtIrxxQlDibULRQGlDi1iK8= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/sashabaranov/go-openai v1.20.4 h1:095xQ/fAtRa0+Rj21sezVJABgKfGPNbyx/sAN/hJUmg= From 41a74f1d529f5bf67c2cc6bb4abda32aabc0644e Mon Sep 17 00:00:00 2001 From: refaktor Date: Mon, 15 Apr 2024 12:19:16 +0200 Subject: [PATCH 2/6] added testing for failures in various do functions, ssh sever basics --- evaldo/builtins.go | 1 + evaldo/builtins_http.go | 2 +- go.mod | 2 ++ go.sum | 4 ++++ tests/basics.rye | 3 ++- tests/main.rye | 14 ++++++++------ tests/misc.rye | 13 ++++++------- tests/validation.rye | 1 - 8 files changed, 24 insertions(+), 16 deletions(-) diff --git a/evaldo/builtins.go b/evaldo/builtins.go index 07e3d44c..7b65e18d 100644 --- a/evaldo/builtins.go +++ b/evaldo/builtins.go @@ -7423,6 +7423,7 @@ func RegisterBuiltins(ps *env.ProgramState) { RegisterBuiltins2(Builtins_bson, ps, "bson") RegisterBuiltins2(Builtins_smtpd, ps, "smtpd") RegisterBuiltins2(Builtins_mail, ps, "mail") + RegisterBuiltins2(Builtins_ssh, ps, "ssh") RegisterBuiltinsInContext(Builtins_math, ps, "math") RegisterBuiltinsInContext(Builtins_devops, ps, "devops") // ## Archived modules diff --git a/evaldo/builtins_http.go b/evaldo/builtins_http.go index 18b7eb5a..51c1d284 100755 --- a/evaldo/builtins_http.go +++ b/evaldo/builtins_http.go @@ -44,7 +44,7 @@ TODO -- integrate gowabs into this and implement their example first just as han var Builtins_http = map[string]*env.Builtin{ - "new-server": { + "http-server": { Argsn: 1, Doc: "Create new http server.", Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { diff --git a/go.mod b/go.mod index 28c6fac5..99ea4ef1 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/blevesearch/bleve/v2 v2.4.0 github.com/blevesearch/bleve_index_api v1.1.6 github.com/drewlanenga/govector v0.0.0-20220726163947-b958ac08bc93 + github.com/gliderlabs/ssh v0.3.7 github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df github.com/go-sql-driver/mysql v1.8.1 github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible @@ -42,6 +43,7 @@ require ( require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/RoaringBitmap/roaring v1.2.3 // indirect + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.10 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect diff --git a/go.sum b/go.sum index 20d6b878..be477a45 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/RoaringBitmap/roaring v1.2.3 h1:yqreLINqIrX22ErkKI0vY47/ivtJr6n+kMhVOVmhWBY= github.com/RoaringBitmap/roaring v1.2.3/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA= github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= github.com/aws/aws-sdk-go-v2/config v1.27.10 h1:PS+65jThT0T/snC5WjyfHHyUgG+eBoupSDV+f838cro= @@ -75,6 +77,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/drewlanenga/govector v0.0.0-20220726163947-b958ac08bc93 h1:2VXZHsypUG1HaQcj/+nQc5TbZ4qZ5FSl7KN4s1BjFQY= github.com/drewlanenga/govector v0.0.0-20220726163947-b958ac08bc93/go.mod h1:AbP/uRrjZFATEwl0P2DHePteIMZRWHEJBWBmMmLdCkk= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= +github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df h1:Bao6dhmbTA1KFVxmJ6nBoMuOJit2yjEgLJpIMYpop0E= github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= diff --git a/tests/basics.rye b/tests/basics.rye index 88810994..33e94bae 100644 --- a/tests/basics.rye +++ b/tests/basics.rye @@ -29,7 +29,8 @@ section "Printing functions" stdout { printv 33 "value is: {}" } "value is: 33" + newline ; stdout { print\val "OK" "value is: {{}}" } "value is: 33" + newline ; TODO-BUG quotes the string ; stdout { { "Jane Austen" } print\val "Hello {{}}!" } "value is: 33" + newline - ;} + ;} + } ; group "print-ssv" ; mold\nowrap ?print-ssv diff --git a/tests/main.rye b/tests/main.rye index 72d6cee5..08298d3b 100644 --- a/tests/main.rye +++ b/tests/main.rye @@ -14,11 +14,16 @@ test-framework: context { group: fn { name descr args code } { inc! 'cnt print " GROUP: " + name , do code } + error: fn { test } { + ; try { do\in root-ctx test } + try test :got \type? |= 'error \either { print join { " - OK: " mold got } } { inc! 'failed , print join { " - Error: expected error but got: " mold got } } + } + equal: fn { test res } { do\in root-ctx test :got = res |either { print " - OK" } { inc! 'failed , print join { " - Error: expected " mold res ", got " mold got } } } - + equal\todo: fn { test res } { } @@ -74,12 +79,12 @@ generate-doc-file: fn { filename menu } { } |write* to-file filename + ".html" } -menu: { "basics" "structures" "validation" "misc" } +menu: { "basics" "structures" "validation" "misc" "errors" } switch arg { "test" { errors: 0 - for menu { + ".rye" |to-file |load |do\in* test-framework |+ errors :errors } + for menu { + ".rye" |to-file |probe |probe |load |do\in* test-framework |+ errors :errors } print "===============" print "FAILED TESTS: " + errors } @@ -98,9 +103,6 @@ switch arg { - - - ; maybe we need this at some point ; true: fn { test } { ; do-in root-ctx test diff --git a/tests/misc.rye b/tests/misc.rye index 5973f9b7..a7336348 100644 --- a/tests/misc.rye +++ b/tests/misc.rye @@ -360,7 +360,7 @@ section "Math functions" { { string } } { equal { do\in math { asin -1 } } -1.5707963267948966 - equal { do\in math { asin 0 } } 0 + equal { do\in math { asin 0 } } 0.000 equal { do\in math { asin 1 } } 1.5707963267948966 } @@ -369,24 +369,23 @@ section "Math functions" { { string } } { equal { do\in math { asinh -1 } } -0.8813735870195428 - equal { do\in math { asinh 0 } } 0 + equal { do\in math { asinh 0 } } 0.000 equal { do\in math { asinh 1 } } 0.8813735870195429 } - -group "atan" + group "atan" mold\nowrap "" { { string } } { equal { do\in math { atan -1 } } -0.7853981633974483 - equal { do\in math { atan 0 } } 0 + equal { do\in math { atan 0 } } 0.00000 equal { do\in math { atan 1 } } 0.7853981633974483 } - + ; TODO add sin and cos ... need PI constant } -end \ No newline at end of file +end diff --git a/tests/validation.rye b/tests/validation.rye index 77c7ddfc..07bf33e1 100644 --- a/tests/validation.rye +++ b/tests/validation.rye @@ -94,4 +94,3 @@ section "Regular expressions" end - \ No newline at end of file From 2b4c3c1a7fd3387a3681bfffc47ed071870dd0c2 Mon Sep 17 00:00:00 2001 From: refaktor Date: Tue, 16 Apr 2024 01:03:20 +0200 Subject: [PATCH 3/6] new funcs like nl and pink, ssh integration and example, errors tests starting --- evaldo/builtins.go | 28 +++++++ evaldo/builtins_ssh.go | 139 +++++++++++++++++++++++++++++++ evaldo/builtins_ssh_not.go | 27 ++++++ examples/ssh/ssh_http_server.rye | 12 +++ tests/errors.rye | 32 +++++++ 5 files changed, 238 insertions(+) create mode 100755 evaldo/builtins_ssh.go create mode 100755 evaldo/builtins_ssh_not.go create mode 100644 examples/ssh/ssh_http_server.rye create mode 100644 tests/errors.rye diff --git a/evaldo/builtins.go b/evaldo/builtins.go index 7b65e18d..cd1d3096 100644 --- a/evaldo/builtins.go +++ b/evaldo/builtins.go @@ -5281,6 +5281,34 @@ var builtins = map[string]*env.Builtin{ }, }, + "nl": { + Argsn: 1, + Doc: "Returns the argument 1 a d a newline character.", + Pure: true, + Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + switch s1 := arg0.(type) { + case env.String: + return *env.NewString(s1.Value + "\n") + default: + return MakeArgError(ps, 1, []env.Type{env.StringType}, "left") + } + }, + }, + + "pink": { + Argsn: 1, + Doc: "Returns the argument 1 a d a newline character.", + Pure: true, + Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + switch s1 := arg0.(type) { + case env.String: + return *env.NewString("\033[35m" + s1.Value + "\033[0m") + default: + return MakeArgError(ps, 1, []env.Type{env.StringType}, "left") + } + }, + }, + "trim": { Argsn: 1, Doc: "Trims the String of spacing characters.", diff --git a/evaldo/builtins_ssh.go b/evaldo/builtins_ssh.go new file mode 100755 index 00000000..d031bde6 --- /dev/null +++ b/evaldo/builtins_ssh.go @@ -0,0 +1,139 @@ +//go:build b_ssh +// +build b_ssh + +package evaldo + +import ( + "io" + + "github.com/gliderlabs/ssh" + "github.com/jinzhu/copier" + "github.com/refaktor/rye/env" + "github.com/refaktor/rye/util" +) + +/* + +http-handle "/" fn { w req } { write w "Hello world!" } +ws-handle "/ws" fn { c } { forever { msg: receive c write c "GOT:" + msg } +http-serve ":9000" + +new-server ":9000" |with { + .handle "/" fn { w req } { write w "Hello world!" } , + .handle-ws "/ws" fn { c } { forever { msg: receive c write c "GOT:" + msg } } , + .serve +} + +TODO -- integrate gowabs into this and implement their example first just as handle-ws ... no rye code executed + if this all works with resetc exits multiple at the same time then implement the callFunction ... but we need to make a local programstate probably + +*/ + +var Builtins_ssh = map[string]*env.Builtin{ + + "ssh-server": { + Argsn: 1, + Doc: "Create new ssh server.", + Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + switch addr := arg0.(type) { + case env.String: + return *env.NewNative(ps.Idx, &ssh.Server{Addr: addr.Value}, "ssh-server") + default: + ps.FailureFlag = true + return MakeArgError(ps, 1, []env.Type{env.StringType}, "ssh-server") + } + + }, + }, + "ssh-server//handle": { + Argsn: 2, + Doc: "HTTP handle function for server.", + Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + switch server := arg0.(type) { + case env.Native: + switch handler := arg1.(type) { + case env.Function: + server.Value.(*ssh.Server).Handle(func(s ssh.Session) { + ps.FailureFlag = false + ps.ErrorFlag = false + ps.ReturnFlag = false + psTemp := env.ProgramState{} + copier.Copy(&psTemp, &ps) + CallFunction(handler, ps, *env.NewNative(ps.Idx, s, "ssh-session"), false, nil) + }) + return arg0 + default: + ps.FailureFlag = true + return MakeArgError(ps, 2, []env.Type{env.FunctionType}, "ssh-server//handle") + } + default: + ps.FailureFlag = true + return MakeArgError(ps, 1, []env.Type{env.NativeType}, "ssh-server//handle") + } + }, + }, + "ssh-server//password-auth": { + Argsn: 2, + Doc: "HTTP handler for password authentication.", + Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + switch server := arg0.(type) { + case env.Native: + switch handler := arg1.(type) { + case env.Function: + pwda := ssh.PasswordAuth(func(ctx ssh.Context, pass string) bool { + ps.FailureFlag = false + ps.ErrorFlag = false + ps.ReturnFlag = false + psTemp := env.ProgramState{} + copier.Copy(&psTemp, &ps) + newPs := CallFunction(handler, ps, *env.NewString(pass), false, nil) + return util.IsTruthy(newPs.Res) + }) + server.Value.(*ssh.Server).SetOption(pwda) + return arg0 + default: + ps.FailureFlag = true + return MakeArgError(ps, 2, []env.Type{env.FunctionType}, "ssh-server//handle") + } + default: + ps.FailureFlag = true + return MakeArgError(ps, 1, []env.Type{env.NativeType}, "ssh-server//handle") + } + }, + }, + "ssh-server//serve": { + Argsn: 1, + Doc: "Listen and serve new server.", + Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + switch server := arg0.(type) { + case env.Native: + server.Value.(*ssh.Server).ListenAndServe() + return arg0 + default: + ps.FailureFlag = true + return MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server//serve") + } + }, + }, + + "ssh-session//write": { + Argsn: 2, + Doc: "SSH session write function.", + Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + switch session := arg0.(type) { + case env.Native: + switch val := arg1.(type) { + case env.String: + io.WriteString(session.Value.(ssh.Session), val.Value) + return arg0 + default: + ps.FailureFlag = true + return MakeArgError(ps, 2, []env.Type{env.StringType}, "ssh-session//write") + } + default: + ps.FailureFlag = true + return MakeArgError(ps, 1, []env.Type{env.NativeType}, "ssh-session//write") + } + }, + }, +} diff --git a/evaldo/builtins_ssh_not.go b/evaldo/builtins_ssh_not.go new file mode 100755 index 00000000..97fae7af --- /dev/null +++ b/evaldo/builtins_ssh_not.go @@ -0,0 +1,27 @@ +//go:build !b_ssh +// +build !b_ssh + +package evaldo + +import ( + "github.com/refaktor/rye/env" +) + +/* + +http-handle "/" fn { w req } { write w "Hello world!" } +ws-handle "/ws" fn { c } { forever { msg: receive c write c "GOT:" + msg } +http-serve ":9000" + +new-server ":9000" |with { + .handle "/" fn { w req } { write w "Hello world!" } , + .handle-ws "/ws" fn { c } { forever { msg: receive c write c "GOT:" + msg } } , + .serve +} + +TODO -- integrate gowabs into this and implement their example first just as handle-ws ... no rye code executed + if this all works with resetc exits multiple at the same time then implement the callFunction ... but we need to make a local programstate probably + +*/ + +var Builtins_ssh = map[string]*env.Builtin{} diff --git a/examples/ssh/ssh_http_server.rye b/examples/ssh/ssh_http_server.rye new file mode 100644 index 00000000..ea6bfa25 --- /dev/null +++ b/examples/ssh/ssh_http_server.rye @@ -0,0 +1,12 @@ +rye .needs { http ssh } + +ssh-server ":2222" + \handle fn { s } { write s pink "I c you :)" .nl } + \password-auth fn { p } { = "1234" } :ssh + +http-server ":8080" + \handle "/" fn { w r } { .write "I htttp u" .nl } :http + +go does { serve ssh } go does { serve http } + +select { } diff --git a/tests/errors.rye b/tests/errors.rye new file mode 100644 index 00000000..8f3203d2 --- /dev/null +++ b/tests/errors.rye @@ -0,0 +1,32 @@ +section "Runtime error detection" +"" +{ + group "do" + "" + { { object } } + { + error { do { print } } + error { do { 1 / 0 } } + } + group "loop" + "" + { { object } } + { + error { loop 2 { print } } + error { loop 2 { 1 / 0 } } + } + group "for" + "" + { { object } } + { + error { for [ 1 2 ] { print } } + error { for [ 1 2 ] { 1 / 0 } } + } + group "with" + "" + { { object } } + { + error { with { print } } + error { with { 1 / 0 } } + } +} \ No newline at end of file From ebc18b0e0849820d1667041d6f37c2b028e99dea Mon Sep 17 00:00:00 2001 From: refaktor Date: Sat, 4 May 2024 12:27:52 +0200 Subject: [PATCH 4/6] ryel tools, embed_main flag, small fixes all around --- .gitignore | 2 ++ _sandbox/ryel.rye | 39 -------------------------- bin/ryel | 12 ++++++++ bin/ryelc | 8 ++++++ env/object.go | 4 +-- evaldo/builtins.go | 15 ++++------ evaldo/builtins_io.go | 3 +- evaldo/builtins_math.go | 2 +- evaldo/builtins_psutil.go | 2 +- evaldo/builtins_spreadsheet.go | 47 +++++++++++++++++-------------- main.go | 14 ++++++++-- option_embed_main.go | 13 +++++++++ option_embed_main_not.go | 10 +++++++ tests/structures.rye | 4 +-- util/ryel | 9 ------ util/ryel.rye | 51 ++++++++++++++++++++++++++++++++++ util/ryelc | 3 -- util/util.go | 2 +- 18 files changed, 147 insertions(+), 93 deletions(-) delete mode 100644 _sandbox/ryel.rye create mode 100755 bin/ryel create mode 100755 bin/ryelc create mode 100644 option_embed_main.go create mode 100644 option_embed_main_not.go delete mode 100755 util/ryel create mode 100644 util/ryel.rye delete mode 100755 util/ryelc diff --git a/.gitignore b/.gitignore index 8ec5f920..cd7e8b66 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ dist/ tests/*.html shell_*.rye console_*.rye + +buildtemp/main.rye \ No newline at end of file diff --git a/_sandbox/ryel.rye b/_sandbox/ryel.rye deleted file mode 100644 index 63686b60..00000000 --- a/_sandbox/ryel.rye +++ /dev/null @@ -1,39 +0,0 @@ -; # Rye local binary* -; -; *This is experimental way to work with rye interpreter* -; -; This Rye script looks at local rye.mod and tries to build Rye binary with listed bindings - -; for outside of rye source dir -; a=$PWD ; cd ~/go/src/rye ; go build -tags "b_tiny,b_http,b_bleve" -o "$a/ryel" ; cd "$a" - - -build-ryel: fn { } { - - print "___ ____, . __" - print "|__) \ / |__ | /\ |\ | / _`" - print "| \ | |___ |___ /~~\ | \| \__>" - print "============================================" - print "Building local Rye interpreter with modules:" - - open %rye.mod - |fix-either - { print "Create rye.mod file and list modules." " nil " } - { .read-all } - |load - |map { .to-string .concat* "b_" } - |join-with " " :modules |print - - command: $a=%PWD ; cd ~/go/src/rye ; go build -tags "b_tiny $ + modules + $" -o "%a/ryel" ; cd "%a"$ - command .replace "%" "$" :command - cmd command -} - -install-ryel: fn { } { - print "Installing Ryel ..." -} - -rye .args -> 2 :mode = "build" |if { build-ryel } -if mode = "install" { install-ryel } - -; Later when script is executed and it returns a failure of missing known binding it adds it to the list diff --git a/bin/ryel b/bin/ryel new file mode 100755 index 00000000..9eaef8b6 --- /dev/null +++ b/bin/ryel @@ -0,0 +1,12 @@ +#!/bin/bash + +# This is a first **proof of concept** only, the naming, the functionality might change. Please propose changes if you see any faults, +# especially security implications. + +FILE=$PWD/ryel +if [ -f "$FILE" ]; then +# echo "Starting local rye interpreter" + $FILE "$@" +else + echo "You don't have local Ryel binary yet. Define ryel.mod if needed and run ryelc build" +fi diff --git a/bin/ryelc b/bin/ryelc new file mode 100755 index 00000000..8a0ef20b --- /dev/null +++ b/bin/ryelc @@ -0,0 +1,8 @@ +#!/bin/bash + +# This is a first **proof of concept** only, the naming, the functionality might change. Please propose changes if you see any faults, +# especially security implications. + +# Assumes normal rye build (at least tiny is on the PATH), but we don't define RYE_HOME or anything like this for now, maybe we should + +rye $RYE_HOME/util/ryel.rye $@ diff --git a/env/object.go b/env/object.go index e1cfd1b3..9c3bfb12 100644 --- a/env/object.go +++ b/env/object.go @@ -410,7 +410,7 @@ func (b Block) Inspect(e Idxs) string { func (b Block) Print(e Idxs) string { var r strings.Builder - r.WriteString("{ ") + // r.WriteString("{ ") for i := 0; i < b.Series.Len(); i += 1 { if b.Series.Get(i) != nil { r.WriteString(b.Series.Get(i).Print(e)) @@ -419,7 +419,7 @@ func (b Block) Print(e Idxs) string { r.WriteString("[NIL]") } } - r.WriteString("}") + // r.WriteString("}") return r.String() } diff --git a/evaldo/builtins.go b/evaldo/builtins.go index 5276247d..e1d64f5b 100644 --- a/evaldo/builtins.go +++ b/evaldo/builtins.go @@ -233,9 +233,8 @@ func getFrom(ps *env.ProgramState, data any, key any, posMode bool) env.Object { if posMode { idx-- } - v := s1.Data[idx] - ok := true - if ok { + if len(s1.Data) >= int(idx)+1 { + v := s1.Data[idx] return env.ToRyeValue(v) } else { ps.FailureFlag = true @@ -249,9 +248,8 @@ func getFrom(ps *env.ProgramState, data any, key any, posMode bool) env.Object { if posMode { idx-- } - v := s1.Data[idx] - ok := true - if ok { + if len(s1.Data) >= int(idx)+1 { + v := s1.Data[idx] return env.ToRyeValue(v) } else { ps.FailureFlag = true @@ -265,9 +263,8 @@ func getFrom(ps *env.ProgramState, data any, key any, posMode bool) env.Object { if posMode { idx-- } - v := s1.Series.Get(int(idx)) - ok := true - if ok { + if len(s1.Series.S) >= int(idx)+1 { + v := s1.Series.Get(int(idx)) return v } else { ps.FailureFlag = true diff --git a/evaldo/builtins_io.go b/evaldo/builtins_io.go index bad3e06f..e9d1e259 100755 --- a/evaldo/builtins_io.go +++ b/evaldo/builtins_io.go @@ -42,8 +42,7 @@ func __input(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Ob func __open(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { switch s := arg0.(type) { case env.Uri: - path := strings.Split(s.Path, "://") - file, err := os.Open(path[1]) + file, err := os.Open(s.Path) if err != nil { return makeError(ps, err.Error()) } diff --git a/evaldo/builtins_math.go b/evaldo/builtins_math.go index 93de9f63..b93e3b11 100644 --- a/evaldo/builtins_math.go +++ b/evaldo/builtins_math.go @@ -393,7 +393,7 @@ var Builtins_math = map[string]*env.Builtin{ return DialectMath(ps, arg0) }, }, - "math": { + "calc": { Argsn: 1, Doc: "Do math dialect", Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { diff --git a/evaldo/builtins_psutil.go b/evaldo/builtins_psutil.go index 129d4491..1265af05 100644 --- a/evaldo/builtins_psutil.go +++ b/evaldo/builtins_psutil.go @@ -116,7 +116,7 @@ var Builtins_devops = map[string]*env.Builtin{ }, }, - "ls": { + "lsd": { Argsn: 0, Doc: "Returns current working directory.", Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { diff --git a/evaldo/builtins_spreadsheet.go b/evaldo/builtins_spreadsheet.go index 7964d60f..5feafdbc 100644 --- a/evaldo/builtins_spreadsheet.go +++ b/evaldo/builtins_spreadsheet.go @@ -496,15 +496,38 @@ var Builtins_spreadsheet = map[string]*env.Builtin{ }, }, - "sort-col!": { - Argsn: 2, + "sort-by!": { + Argsn: 3, Doc: "Sorts row by given column.", Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + dir, ok := arg2.(env.Word) + if !ok { + return MakeArgError(ps, 3, []env.Type{env.WordType}, "sort-col!") + } + var dirAsc bool + if dir.Index == ps.Idx.IndexWord("asc") { + dirAsc = true + } else if dir.Index == ps.Idx.IndexWord("desc") { + dirAsc = false + } else { + return MakeBuiltinError(ps, "Direction can be just asc or desc.", "sort-col!") + } switch spr := arg0.(type) { case env.Spreadsheet: switch col := arg1.(type) { + case env.String: + if dirAsc { + SortByColumn(ps, &spr, col.Value) + } else { + SortByColumnDesc(ps, &spr, col.Value) + } + return spr case env.Word: - SortByColumn(ps, &spr, ps.Idx.GetWord(col.Index)) + if dirAsc { + SortByColumn(ps, &spr, ps.Idx.GetWord(col.Index)) + } else { + SortByColumnDesc(ps, &spr, ps.Idx.GetWord(col.Index)) + } return spr default: return MakeArgError(ps, 2, []env.Type{env.WordType}, "sort-col!") @@ -514,24 +537,6 @@ var Builtins_spreadsheet = map[string]*env.Builtin{ } }, }, - "sort-col\\desc!": { - Argsn: 2, - Doc: "Sorts rows by given column, descending.", - Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { - switch spr := arg0.(type) { - case env.Spreadsheet: - switch col := arg1.(type) { - case env.Word: - SortByColumnDesc(ps, &spr, ps.Idx.GetWord(col.Index)) - return spr - default: - return MakeArgError(ps, 2, []env.Type{env.WordType}, "sort-col\\desc!") - } - default: - return MakeArgError(ps, 1, []env.Type{env.SpreadsheetType}, "sort-col\\desc!") - } - }, - }, "columns": { Argsn: 2, Doc: "Returs spreasheet with just given columns.", diff --git a/main.go b/main.go index 20db9b93..08f33e31 100644 --- a/main.go +++ b/main.go @@ -105,7 +105,9 @@ func main() { // Check for --help flag if flag.NFlag() == 0 && flag.NArg() == 0 { - if Option_Do_Main { + if Option_Embed_Main { + main_rye_file("buildtemp/main.rye", false, true, *console, code) + } else if Option_Do_Main { ryeFile := dotsToMainRye(".") main_rye_file(ryeFile, false, true, *console, code) } else { @@ -223,7 +225,7 @@ func dotsToMainRye(ryeFile string) string { re := regexp.MustCompile(`^\.$|/\.$`) if re.MatchString(ryeFile) { main_path := ryeFile[:len(ryeFile)-1] + "main.rye" - if _, err := os.Stat(main_path); err == nil { + if _, err := os.Stat(main_path); err == nil || Option_Embed_Main { _, err := os.ReadFile(main_path) if err != nil { log.Fatal(err) @@ -402,7 +404,13 @@ func main_rye_file(file string, sig bool, subc bool, interactive bool, code stri content = util.ReadSecure(file, password) } else if file != "" { - bcontent, err := os.ReadFile(file) + var bcontent []byte + var err error + if Option_Embed_Main { + bcontent, err = Rye_files.ReadFile(file) + } else { + bcontent, err = os.ReadFile(file) + } if err != nil { log.Fatal(err) } diff --git a/option_embed_main.go b/option_embed_main.go new file mode 100644 index 00000000..e512aabf --- /dev/null +++ b/option_embed_main.go @@ -0,0 +1,13 @@ +//go:build embed_main +// +build embed_main + +package main + +import ( + "embed" +) + +const Option_Embed_Main bool = true + +//go:embed buildtemp/main.rye +var Rye_files embed.FS diff --git a/option_embed_main_not.go b/option_embed_main_not.go new file mode 100644 index 00000000..f453597d --- /dev/null +++ b/option_embed_main_not.go @@ -0,0 +1,10 @@ +//go:build !embed_main +// +build !embed_main + +package main + +import "embed" + +const Option_Embed_Main bool = false + +var Rye_files embed.FS diff --git a/tests/structures.rye b/tests/structures.rye index 4442cd19..9d16581f 100644 --- a/tests/structures.rye +++ b/tests/structures.rye @@ -658,12 +658,12 @@ section "Spreadsheet related functions" mold\nowrap ?group-by { { block } } { - equal { spreadsheet { "name" "val" } { "a" 1 "b" 2 } |group-by 'name { } |sort-col! 'name + equal { spreadsheet { "name" "val" } { "a" 1 "b" 2 } |group-by 'name { } |sort-by! 'name 'asc } spreadsheet { "name" } { "a" "b" } equal { spreadsheet { "name" "val" } { "a" 1 "b" 6 "a" 5 "b" 10 "a" 7 } |group-by 'name { 'name count 'val sum 'val min 'val max 'val avg } - |sort-col! 'name + |sort-by! 'name 'asc } spreadsheet { "name" "name_count" "val_sum" "val_min" "val_max" "val_avg" } { "a" 3 13.0 1.0 7.0 4.333333333333333 diff --git a/util/ryel b/util/ryel deleted file mode 100755 index b92a4803..00000000 --- a/util/ryel +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -FILE=$PWD/ryel -if [ -f "$FILE" ]; then - echo "Starting local rye interpreter" - $FILE "$@" -else - echo "You don't have local Ryel binary yet. Define ryel.mod if needed and run ryelc build" -fi diff --git a/util/ryel.rye b/util/ryel.rye new file mode 100644 index 00000000..9745a898 --- /dev/null +++ b/util/ryel.rye @@ -0,0 +1,51 @@ +; Rye local binary +; +; *This is experimental way to work with rye interpreter* +; +; This Rye script looks at local rye.mod and tries to build Rye binary with listed bindings + +; for outside of rye source dir +; a=$PWD ; cd ~/go/src/rye ; go build -tags "b_tiny,b_http,b_bleve" -o "$a/ryel" ; cd "$a" + +print-header: does { + print "___ ____, . __" + print "|__) \ / |__ | /\ |\ | / _`" + print "| \ | |___ |___ /~~\ | \| \__>" + print "====================================" + print "Building local Rye interpreter with modules:" +} + +build-ryel: fn { tags } { + + print-header + + open %ryel.mod + |fix\either + { print "Create rye.mod file and list modules." " nil " } + { .read-all } + |load + |map { .to-string .concat* "b_" } + |join\with " " :modules |print + + cp-embed: either tags = "embed_main" { "cp main.rye %RYE_HOME/buildtemp/. ; " } { "" } + + command: join { cp-embed $ a=%PWD ; cd %RYE_HOME ; go build -tags "$ + modules + " " + tags $" -o "%a/ryel" ; cd "%a"$ } ; $ delimiter for string is just temporary ... ' conflicts with lit-words and Rebols { } with blocks so this question is open so far + command .replace "%" "$" :command + ; print "Build command: " + command + cmd command +} + +install-ryel: fn { } { + print-header + print "TODO: Installing Ryel ..." +} + +rye .args -> 0 \fix { "" } :mode +rye .args -> 1 \fix { "" } :tags + +switch mode { + "build" { build-ryel tags } + "install" { install-ryel } +} + +; Later when script is executed and it returns a failure of missing known binding it adds it to the list diff --git a/util/ryelc b/util/ryelc deleted file mode 100755 index f4332f00..00000000 --- a/util/ryelc +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -/home/nano/go/src/rye/rye /home/nano/go/src/rye/ryel.rye $1 diff --git a/util/util.go b/util/util.go index 6304ce21..aebd72fc 100644 --- a/util/util.go +++ b/util/util.go @@ -71,6 +71,7 @@ func StringToFieldsWithQuoted(str string, sepa string, quote string) env.Block { return !quoted && string(r) == sepa }) lst := make([]env.Object, len(spl)) + re := regexp.MustCompile("[0-9]+") for i := 0; i < len(spl); i++ { //fmt.Println(spl[i]) @@ -78,7 +79,6 @@ func StringToFieldsWithQuoted(str string, sepa string, quote string) env.Block { // val, _ := loader.LoadString(spl[i], false) // numeric, _ := regexp.MatchString("[0-9]+", spl[i]) numeric := re.MatchString(spl[i]) - // fmt.Println(numeric) pass := false if numeric { num, err := strconv.Atoi(spl[i]) From f326b05a6d3dda2d68875f52e2c2c0192f3d1a32 Mon Sep 17 00:00:00 2001 From: refaktor Date: Wed, 8 May 2024 03:12:15 +0200 Subject: [PATCH 5/6] adding support for modwords and lmodwords , also partially opcpaths and pipecpaths --- env/env.go | 17 +++++++-- env/idxs.go | 4 +++ env/object.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ evaldo/evaldo.go | 19 +++++++++- loader/loader.go | 24 ++++++++++++- main.go | 4 +-- 6 files changed, 156 insertions(+), 6 deletions(-) diff --git a/env/env.go b/env/env.go index a7706d45..68f79f53 100755 --- a/env/env.go +++ b/env/env.go @@ -243,8 +243,21 @@ func (e *RyeCtx) Get2(word int) (Object, bool, *RyeCtx) { } func (e *RyeCtx) Set(word int, val Object) Object { - e.state[word] = val - return val + if _, exists := e.state[word]; exists { + return NewError("Can't set already set word, try using modword") + } else { + e.state[word] = val + return val + } +} + +func (e *RyeCtx) Mod(word int, val Object) Object { + if _, exists := e.state[word]; exists { + e.state[word] = val + return val + } else { + return NewError("Can't mod an unset word, try using setword") + } } type ProgramState struct { diff --git a/env/idxs.go b/env/idxs.go index 71bacacb..04b58e69 100755 --- a/env/idxs.go +++ b/env/idxs.go @@ -48,6 +48,10 @@ var NativeTypes = [...]string{ // Todo change to BuiltinTypes "SpreadsheetRowType", "Decimal", "Vector", + "OpCPath", + "PipeCPath", + "Modword", + "LModword", } func (e *Idxs) IndexWord(w string) int { diff --git a/env/object.go b/env/object.go index 9c3bfb12..88e340ba 100644 --- a/env/object.go +++ b/env/object.go @@ -48,6 +48,10 @@ const ( SpreadsheetRowType Type = 33 DecimalType Type = 34 VectorType Type = 35 + OpCPathType Type = 36 + PipeCPathType Type = 37 + ModwordType Type = 38 + LModwordType Type = 39 ) // after adding new type here, also add string to idxs.go @@ -601,6 +605,96 @@ func (i LSetword) Dump(e Idxs) string { return ":" + e.GetWord(i.Index) } +// +// MODWORD +// + +type Modword struct { + Index int +} + +func NewModword(index int) *Modword { + nat := Modword{index} + return &nat +} + +func (i Modword) Type() Type { + return ModwordType +} + +func (i Modword) Inspect(e Idxs) string { + return "[Modword: " + e.GetWord(i.Index) + "]" +} + +func (b Modword) Print(e Idxs) string { + return e.GetWord(b.Index) + ":" +} + +func (i Modword) Trace(msg string) { + fmt.Print(msg + "(Modword): ") + fmt.Println(i.Index) +} + +func (i Modword) GetKind() int { + return int(ModwordType) +} + +func (i Modword) Equal(o Object) bool { + if i.Type() != o.Type() { + return false + } + return i.Index == o.(Modword).Index +} + +func (i Modword) Dump(e Idxs) string { + return e.GetWord(i.Index) + ":" +} + +// +// LMODWORD +// + +type LModword struct { + Index int +} + +func NewLModword(index int) *LModword { + nat := LModword{index} + return &nat +} + +func (i LModword) Type() Type { + return LModwordType +} + +func (i LModword) Inspect(e Idxs) string { + return "[LModword: " + e.GetWord(i.Index) + "]" +} + +func (b LModword) Print(e Idxs) string { + return ":" + e.GetWord(b.Index) +} + +func (i LModword) Trace(msg string) { + fmt.Print(msg + "(lModword): ") + fmt.Println(i.Index) +} + +func (i LModword) GetKind() int { + return int(LModwordType) +} + +func (i LModword) Equal(o Object) bool { + if i.Type() != o.Type() { + return false + } + return i.Index == o.(LModword).Index +} + +func (i LModword) Dump(e Idxs) string { + return ":" + e.GetWord(i.Index) +} + // // OPWORD // diff --git a/evaldo/evaldo.go b/evaldo/evaldo.go index b90ba709..8009eb51 100644 --- a/evaldo/evaldo.go +++ b/evaldo/evaldo.go @@ -329,6 +329,8 @@ func EvalExpressionConcrete(ps *env.ProgramState) *env.ProgramState { return EvalGenword(ps, object.(env.Genword), nil, false) case env.SetwordType: return EvalSetword(ps, object.(env.Setword)) + case env.ModwordType: + return EvalModword(ps, object.(env.Modword)) case env.GetwordType: return EvalGetword(ps, object.(env.Getword), nil, false) case env.CommaType: @@ -495,7 +497,22 @@ func EvalSetword(ps *env.ProgramState, word env.Setword) *env.ProgramState { // es1 := EvalExpression(es) ps1, _ := EvalExpressionInj(ps, nil, false) idx := word.Index - ps1.Ctx.Set(idx, ps1.Res) + ps1.Res = ps1.Ctx.Set(idx, ps1.Res) + if ps1.Res.Type() == env.ErrorType { + ps1.ErrorFlag = true + } + return ps1 +} + +// evaluates expression to the right and sets the result of it to a word in current context +func EvalModword(ps *env.ProgramState, word env.Modword) *env.ProgramState { + // es1 := EvalExpression(es) + ps1, _ := EvalExpressionInj(ps, nil, false) + idx := word.Index + ps1.Res = ps1.Ctx.Mod(idx, ps1.Res) + if ps1.Res.Type() == env.ErrorType { + ps1.ErrorFlag = true + } return ps1 } diff --git a/loader/loader.go b/loader/loader.go index b1a5479e..7ff4b8eb 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -305,6 +305,20 @@ func parseLSetword(v *Values, d Any) (Any, error) { return *env.NewLSetword(idx), nil } +func parseModword(v *Values, d Any) (Any, error) { + //fmt.Println("SETWORD:" + v.Token()) + word := v.Token() + idx := wordIndex.IndexWord(word[:len(word)-2]) + return *env.NewModword(idx), nil +} + +func parseLModword(v *Values, d Any) (Any, error) { + //fmt.Println("SETWORD:" + v.Token()) + word := v.Token() + idx := wordIndex.IndexWord(word[2:]) + return *env.NewLModword(idx), nil +} + func parseOpword(v *Values, d Any) (Any, error) { //fmt.Println("OPWORD:" + v.Token()) word := v.Token() @@ -404,12 +418,14 @@ func newParser() *Parser { // TODO -- add string eaddress path url time BLOCK <- "{" SPACES SERIES* "}" BBLOCK <- "[" SPACES SERIES* "]" GROUP <- "(" SPACES SERIES* ")" - SERIES <- (GROUP / COMMENT / URI / EMAIL / STRING / DECIMAL / NUMBER / COMMA / SETWORD / LSETWORD / ONECHARPIPE / PIPEWORD / EXWORD / XWORD / OPWORD / TAGWORD / CPATH / FPATH / KINDWORD / GENWORD / GETWORD / WORD / VOID / BLOCK / GROUP / BBLOCK / ARGBLOCK ) SPACES + SERIES <- (GROUP / COMMENT / URI / EMAIL / STRING / DECIMAL / NUMBER / COMMA / MODWORD / SETWORD / LMODWORD / LSETWORD / ONECHARPIPE / PIPECPATH / PIPEWORD / EXWORD / XWORD / OPCPATH / OPWORD / TAGWORD / CPATH / FPATH / KINDWORD / GENWORD / GETWORD / WORD / VOID / BLOCK / GROUP / BBLOCK / ARGBLOCK ) SPACES ARGBLOCK <- "{" WORD ":" WORD "}" WORD <- LETTER LETTERORNUM* / NORMOPWORDS GENWORD <- "~" UCLETTER LCLETTERORNUM* SETWORD <- LETTER LETTERORNUM* ":" + MODWORD <- LETTER LETTERORNUM* "::" LSETWORD <- ":" LETTER LETTERORNUM* + LMODWORD <- "::" LETTER LETTERORNUM* GETWORD <- "?" LETTER LETTERORNUM* PIPEWORD <- "\\" LETTER LETTERORNUM* / "|" LETTER LETTERORNUM* / PIPEARROWS / "|" NORMOPWORDS ONECHARPIPE <- "|" ONECHARWORDS @@ -425,6 +441,8 @@ func newParser() *Parser { // TODO -- add string eaddress path url time EMAILPART <- < ([a-zA-Z0-9._]+) > FPATH <- "%" URIPATH* CPATH <- WORD ( "/" WORD )+ + OPCPATH <- "." WORD ( "/" WORD )+ + PIPECPATH <- "\\" WORD ( "/" WORD )+ ONECHARWORDS <- < [<>*+-=/] > NORMOPWORDS <- < ("_"[<>*+-=/]) > PIPEARROWS <- ">>" / "~>" / "->" @@ -462,6 +480,8 @@ func newParser() *Parser { // TODO -- add string eaddress path url time g["VOID"].Action = parseVoid g["SETWORD"].Action = parseSetword g["LSETWORD"].Action = parseLSetword + g["MODWORD"].Action = parseModword + g["LMODWORD"].Action = parseLModword g["OPWORD"].Action = parseOpword g["PIPEWORD"].Action = parsePipeword g["ONECHARPIPE"].Action = parseOnecharpipe @@ -478,6 +498,8 @@ func newParser() *Parser { // TODO -- add string eaddress path url time g["URI"].Action = parseUri g["FPATH"].Action = parseFpath g["CPATH"].Action = parseCPath + g["OPCPATH"].Action = parseCPath + g["PIPECPATH"].Action = parseCPath g["COMMENT"].Action = parseComment /* g["SERIES"].Action = func(v *Values, d Any) (Any, error) { return v, nil diff --git a/main.go b/main.go index 08f33e31..b9fb1565 100644 --- a/main.go +++ b/main.go @@ -571,11 +571,11 @@ func main_cgi_file(file string, sig bool) { } func main_rye_repl(_ io.Reader, _ io.Writer, subc bool, here bool) { - input := " 123 " // "name: \"Rye\" version: \"0.011 alpha\"" + input := " " // "name: \"Rye\" version: \"0.011 alpha\"" // userHomeDir, _ := os.UserHomeDir() // profile_path := filepath.Join(userHomeDir, ".rye-profile") - fmt.Println("Welcome to Rye console. Use ls for current or lsp or lsp\\ \"prin\" to list parent context.") + fmt.Println("Welcome to Rye console. Use ls to list current or lsp and lsp\\ \"prin\" to list parent contexts.") //if _, err := os.Stat(profile_path); err == nil { //content, err := os.ReadFile(profile_path) From 8e6e8fa947efaa9f1252589aa01ae8aa2e1f937a Mon Sep 17 00:00:00 2001 From: refaktor Date: Tue, 14 May 2024 10:28:53 +0200 Subject: [PATCH 6/6] improved modword with left options, added support for opcpath and pipecpath --- env/env.go | 9 ++++++++ env/object.go | 7 +++++-- evaldo/builtins.go | 14 +++++++++++++ evaldo/evaldo.go | 52 ++++++++++++++++++++++++++++++++++++++++++---- loader/loader.go | 33 +++++++++++++++++++++++------ 5 files changed, 103 insertions(+), 12 deletions(-) diff --git a/env/env.go b/env/env.go index 68f79f53..8dfb01e7 100755 --- a/env/env.go +++ b/env/env.go @@ -251,6 +251,15 @@ func (e *RyeCtx) Set(word int, val Object) Object { } } +func (e *RyeCtx) Unset(word int) Object { + if _, exists := e.state[word]; !exists { + return NewError("Can't unset non-existing word in this context") + } else { + delete(e.state, word) + return NewInteger(1) + } +} + func (e *RyeCtx) Mod(word int, val Object) Object { if _, exists := e.state[word]; exists { e.state[word] = val diff --git a/env/object.go b/env/object.go index 88e340ba..1a85c40f 100644 --- a/env/object.go +++ b/env/object.go @@ -1542,6 +1542,7 @@ func (i Argword) Dump(e Idxs) string { // type CPath struct { + Mode int // 0 Cpath, 1 OpCpath , 2 PipeCPath Cnt int Word1 Word Word2 Word @@ -1585,15 +1586,17 @@ func (i CPath) GetKind() int { return int(CPathType) } -func NewCPath2(w1 Word, w2 Word) *CPath { +func NewCPath2(mode int, w1 Word, w2 Word) *CPath { var cp CPath + cp.Mode = mode cp.Cnt = 2 cp.Word1 = w1 cp.Word2 = w2 return &cp } -func NewCPath3(w1 Word, w2 Word, w3 Word) *CPath { +func NewCPath3(mode int, w1 Word, w2 Word, w3 Word) *CPath { var cp CPath + cp.Mode = mode cp.Cnt = 3 cp.Word1 = w1 cp.Word2 = w2 diff --git a/evaldo/builtins.go b/evaldo/builtins.go index e1d64f5b..727cddf9 100644 --- a/evaldo/builtins.go +++ b/evaldo/builtins.go @@ -722,6 +722,20 @@ var builtins = map[string]*env.Builtin{ }, }, + "unset!": { // *** + Argsn: 1, + Doc: "Unset a word in current context", + Pure: false, + Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + switch word := arg0.(type) { + case env.Word: + return ps.Ctx.Unset(word.Index) + default: + return MakeArgError(ps, 1, []env.Type{env.WordType}, "set") + } + }, + }, + "get_": { // *** find a name or decide on order of naming with generic words clashes with Argsn: 1, Doc: "Returns value of the word in context", diff --git a/evaldo/evaldo.go b/evaldo/evaldo.go index 8009eb51..5781881d 100644 --- a/evaldo/evaldo.go +++ b/evaldo/evaldo.go @@ -251,6 +251,32 @@ func MaybeEvalOpwordOnRight(nextObj env.Object, ps *env.ProgramState, limited bo ps.Ser.Next() ps = EvalWord(ps, opword.ToWord(), ps.Res, false, opword.Force > 0) return MaybeEvalOpwordOnRight(ps.Ser.Peek(), ps, limited) + case env.CPath: + if opword.Mode == 1 { + ps.Ser.Next() + ps = EvalWord(ps, opword, ps.Res, false, false) // WWWWWWWWWWWWWWWWWWWWWWWWWWWW error interface converions + // when calling cpath + return MaybeEvalOpwordOnRight(ps.Ser.Peek(), ps, limited) + } else if opword.Mode == 2 { + if limited { + return ps + } + ps.Ser.Next() + ps = EvalWord(ps, opword, ps.Res, false, false) // TODO .. check opword force + if ps.ReturnFlag { + return ps //... not sure if we need this + } + // checkFlagsBi() + /*if ps.FailureFlag { // uncommented 202008017 + ps.FailureFlag = false + ps.ErrorFlag = true + ps.ReturnFlag = true + return ps + }*/ + return MaybeEvalOpwordOnRight(ps.Ser.Peek(), ps, limited) + } else { + ps.SkipFlag = false + } case env.Pipeword: if limited { return ps @@ -274,7 +300,25 @@ func MaybeEvalOpwordOnRight(nextObj env.Object, ps *env.ProgramState, limited bo } //ProcOpword(nextObj, es) idx := opword.Index - ps.Ctx.Set(idx, ps.Res) + ps.Res = ps.Ctx.Set(idx, ps.Res) + if ps.Res.Type() == env.ErrorType { + ps.ErrorFlag = true + return ps + } + ps.Ser.Next() + ps.SkipFlag = false + return MaybeEvalOpwordOnRight(ps.Ser.Peek(), ps, limited) + case env.LModword: + if limited { + return ps + } + //ProcOpword(nextObj, es) + idx := opword.Index + ps.Res = ps.Ctx.Mod(idx, ps.Res) + if ps.Res.Type() == env.ErrorType { + ps.ErrorFlag = true + return ps + } ps.Ser.Next() ps.SkipFlag = false return MaybeEvalOpwordOnRight(ps.Ser.Peek(), ps, limited) @@ -362,7 +406,6 @@ func findWordValue(ps *env.ProgramState, word1 env.Object) (bool, env.Object, *e case env.Opword: object, found := ps.Ctx.Get(word.Index) return found, object, nil - case env.CPath: currCtx := ps.Ctx i := 1 @@ -423,8 +466,9 @@ func EvalWord(ps *env.ProgramState, word env.Object, leftVal env.Object, toLeft } } // fmt.Println(kind) - if leftVal != nil && ps.Ctx.Kind.Index != -1 { // don't use generic words if context kind is -1 --- TODO temporary solution to isolates, think about it more - object, found = ps.Gen.Get(kind, word.(env.Word).Index) + rword, ok := word.(env.Word) + if ok && leftVal != nil && ps.Ctx.Kind.Index != -1 { // don't use generic words if context kind is -1 --- TODO temporary solution to isolates, think about it more + object, found = ps.Gen.Get(kind, rword.Index) } } if found { diff --git a/loader/loader.go b/loader/loader.go index 7ff4b8eb..f7bb122e 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -266,11 +266,32 @@ func parseFpath(v *Values, d Any) (Any, error) { func parseCPath(v *Values, d Any) (Any, error) { switch len(v.Vs) { case 2: - return *env.NewCPath2(v.Vs[0].(env.Word), v.Vs[1].(env.Word)), nil + return *env.NewCPath2(0, v.Vs[0].(env.Word), v.Vs[1].(env.Word)), nil case 3: - return *env.NewCPath3(v.Vs[0].(env.Word), v.Vs[1].(env.Word), v.Vs[2].(env.Word)), nil + return *env.NewCPath3(0, v.Vs[0].(env.Word), v.Vs[1].(env.Word), v.Vs[2].(env.Word)), nil default: - return *env.NewCPath3(v.Vs[0].(env.Word), v.Vs[1].(env.Word), v.Vs[2].(env.Word)), nil + return *env.NewCPath3(0, v.Vs[0].(env.Word), v.Vs[1].(env.Word), v.Vs[2].(env.Word)), nil + } +} + +func parseOpCPath(v *Values, d Any) (Any, error) { + switch len(v.Vs) { + case 2: + return *env.NewCPath2(1, v.Vs[0].(env.Word), v.Vs[1].(env.Word)), nil + case 3: + return *env.NewCPath3(1, v.Vs[0].(env.Word), v.Vs[1].(env.Word), v.Vs[2].(env.Word)), nil + default: + return *env.NewCPath3(1, v.Vs[0].(env.Word), v.Vs[1].(env.Word), v.Vs[2].(env.Word)), nil + } +} +func parsePipeCPath(v *Values, d Any) (Any, error) { + switch len(v.Vs) { + case 2: + return *env.NewCPath2(2, v.Vs[0].(env.Word), v.Vs[1].(env.Word)), nil + case 3: + return *env.NewCPath3(2, v.Vs[0].(env.Word), v.Vs[1].(env.Word), v.Vs[2].(env.Word)), nil + default: + return *env.NewCPath3(2, v.Vs[0].(env.Word), v.Vs[1].(env.Word), v.Vs[2].(env.Word)), nil } } @@ -442,7 +463,7 @@ func newParser() *Parser { // TODO -- add string eaddress path url time FPATH <- "%" URIPATH* CPATH <- WORD ( "/" WORD )+ OPCPATH <- "." WORD ( "/" WORD )+ - PIPECPATH <- "\\" WORD ( "/" WORD )+ + PIPECPATH <- "\\" WORD ( "/" WORD )+ / "|" WORD ( "/" WORD )+ ONECHARWORDS <- < [<>*+-=/] > NORMOPWORDS <- < ("_"[<>*+-=/]) > PIPEARROWS <- ">>" / "~>" / "->" @@ -498,8 +519,8 @@ func newParser() *Parser { // TODO -- add string eaddress path url time g["URI"].Action = parseUri g["FPATH"].Action = parseFpath g["CPATH"].Action = parseCPath - g["OPCPATH"].Action = parseCPath - g["PIPECPATH"].Action = parseCPath + g["OPCPATH"].Action = parseOpCPath + g["PIPECPATH"].Action = parsePipeCPath g["COMMENT"].Action = parseComment /* g["SERIES"].Action = func(v *Values, d Any) (Any, error) { return v, nil