diff --git a/evaldo/builtins.go b/evaldo/builtins.go index 07e3d44c..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.", @@ -7423,6 +7451,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/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/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/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/go.mod b/go.mod index 80f85b03..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 @@ -27,7 +28,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 @@ -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 bc06eb52..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= @@ -158,8 +162,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= 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/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 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 b24c337c..47c70e00 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,17 +369,16 @@ 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 } @@ -396,10 +395,7 @@ group "atanh" { equal { do\in math { atanh 0.5 } } 0.5493061443340548 } - - - ; 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