diff --git a/env/envutil.go b/env/envutil.go index d5038310..ca4bf000 100644 --- a/env/envutil.go +++ b/env/envutil.go @@ -1,6 +1,7 @@ package env import "fmt" +import "time" func ToRyeValue(val any) Object { switch v := val.(type) { @@ -28,6 +29,8 @@ func ToRyeValue(val any) Object { return v case nil: return nil + case time.Time: + return *NewString(v.Format(time.RFC3339)) default: fmt.Println(val) // TODO-FIXME diff --git a/env/object.go b/env/object.go index 28c80b91..fdc36f1f 100644 --- a/env/object.go +++ b/env/object.go @@ -178,10 +178,11 @@ func (i String) Inspect(e Idxs) string { // Inspect returns a string representation of the Integer. func (i String) Probe(e Idxs) string { s := i.Value - if len(s) > 100 { - return s[:100] + "..." + if len(s) > 80 { + return s[:80] + "..." } - return "\"" + s + "\"" + return s + // return "\"" + s + "\"" } func (i String) Trace(msg string) { @@ -252,27 +253,32 @@ type Uri struct { } func NewUri1(index *Idxs, path string) *Uri { - scheme := strings.Split(path, "://")[0] // + "-schema" // TODO -- this is just temporary .. so we test it further, make proper once at that level + scheme2 := strings.Split(path, "://") + scheme := scheme2[0] // + "-schema" // TODO -- this is just temporary .. so we test it further, make proper once at that level idxSch := index.IndexWord(scheme) kind := scheme + "-schema" idxKind := index.IndexWord(kind) - nat := Uri{Word{idxSch}, path, Word{idxKind}} + nat := Uri{Word{idxSch}, scheme2[1], Word{idxKind}} + fmt.Println(nat) return &nat } func NewUri(index *Idxs, scheme Word, path string) *Uri { + scheme2 := strings.Split(path, "://") kindstr := strings.Split(path, "://")[0] + "-schema" // TODO -- this is just temporary .. so we test it further, make proper once at that level idx := index.IndexWord(kindstr) - nat := Uri{scheme, path, Word{idx}} + nat := Uri{scheme, scheme2[1], Word{idx}} + // nat := Uri{Word{idxSch}, scheme2[1], Word{idxKind}} + fmt.Println(nat) return &nat } func (i Uri) GetPath() string { - return strings.SplitAfter(i.Path, "://")[1] + return i.Path } func (i Uri) GetProtocol() string { - return strings.Split(i.Path, "://")[0] + return "TODO" } func (i Uri) Type() Type { diff --git a/evaldo/builtins.go b/evaldo/builtins.go index 515ecd02..4a6b4e4b 100644 --- a/evaldo/builtins.go +++ b/evaldo/builtins.go @@ -1922,6 +1922,7 @@ var builtins = map[string]*env.Builtin{ }, }, + /* TEMP FOR WASM 20250116 "get-input": { Argsn: 1, Doc: "Stops execution and gives you a Rye console, to test the code inside environment.", @@ -1950,7 +1951,7 @@ var builtins = map[string]*env.Builtin{ return MakeArgError(ps, 1, []env.Type{env.StringType}, "input-field") } }, - }, + }, */ // DOERS @@ -2394,6 +2395,30 @@ var builtins = map[string]*env.Builtin{ }, }, + "cc": { + Argsn: 1, + Doc: "Change to context", + 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.RyeCtx: + ps.Ctx = &s1 + return s1 + default: + return MakeArgError(ps, 1, []env.Type{env.StringType}, "cc") + } + }, + }, + + "mkcc": { + Argsn: 0, + Doc: "Make context with current as parent and change to it.", + Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + ctx := ps.Ctx + ps.Ctx = env.NewEnv(ctx) // make new context with current par + return ctx + }, + }, + "raw-context": { // ** Argsn: 1, 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_json.go b/evaldo/builtins_json.go index bbbf5166..e307396d 100644 --- a/evaldo/builtins_json.go +++ b/evaldo/builtins_json.go @@ -22,6 +22,10 @@ func resultToJS(res env.Object) any { return v.Value case env.Integer: return v.Value + case *env.Integer: + return v.Value + case env.Decimal: + return v.Value case env.RyeCtx: return "{ 'state': 'todo' }" default: diff --git a/evaldo/builtins_mysql.go b/evaldo/builtins_mysql.go index b5eb60c7..e7c1921c 100755 --- a/evaldo/builtins_mysql.go +++ b/evaldo/builtins_mysql.go @@ -8,6 +8,7 @@ package evaldo import ( "database/sql" "fmt" + "strings" "github.com/refaktor/rye/env" @@ -41,6 +42,38 @@ var Builtins_mysql = map[string]*env.Builtin{ }, }, + "mysql-schema//open\\pwd": { + Argsn: 2, + Doc: "Open Mysql connection.", + Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object { + switch str := arg0.(type) { + case env.Uri: + switch pwd := arg1.(type) { + case env.String: + path := strings.Replace(str.Path, "@", ":"+pwd.Value+"@", 1) + fmt.Println(path) + db, err := sql.Open("mysql", path) + if err != nil { + // TODO -- + //fmt.Println("Error1") + ps.FailureFlag = true + errMsg := fmt.Sprintf("Error opening SQL: %v", err.Error()) + return MakeBuiltinError(ps, errMsg, "mysql-schema//open") + } else { + //fmt.Println("Error2") + return *env.NewNative(ps.Idx, db, "Rye-mysql") + } + default: + ps.FailureFlag = true + return MakeArgError(ps, 2, []env.Type{env.StringType}, "mysql-schema//open") + } + default: + ps.FailureFlag = true + return MakeArgError(ps, 1, []env.Type{env.UriType}, "mysql-schema//open") + } + }, + }, + "Rye-mysql//exec": { Argsn: 2, Doc: "Execute sql query in for mysql.", @@ -54,7 +87,7 @@ var Builtins_mysql = map[string]*env.Builtin{ ser := ps.Ser ps.Ser = str.Series values := make([]any, 0, 2) - _, vals = SQL_EvalBlock(ps, MODE_PSQL, values) + _, vals = SQL_EvalBlock(ps, MODE_SQLITE, values) sqlstr = ps.Res.(env.String).Value ps.Ser = ser case env.String: @@ -103,7 +136,7 @@ var Builtins_mysql = map[string]*env.Builtin{ ser := ps.Ser ps.Ser = str.Series values := make([]any, 0, 2) - _, vals = SQL_EvalBlock(ps, MODE_PSQL, values) + _, vals = SQL_EvalBlock(ps, MODE_SQLITE, values) sqlstr = ps.Res.(env.String).Value ps.Ser = ser case env.String: @@ -143,9 +176,17 @@ var Builtins_mysql = map[string]*env.Builtin{ // storing it in the map with the name of the column as the key. m := make(map[string]any) for i, colName := range cols { - val := columnPointers[i].(*any) - m[colName] = *val - sr.Values = append(sr.Values, *val) + val := *columnPointers[i].(*any) + switch vval := val.(type) { + case []uint8: + // fmt.Println(val) + // fmt.Printf("%T", vval) + m[colName] = env.ToRyeValue(string(vval)) + sr.Values = append(sr.Values, env.ToRyeValue(string(vval))) + default: + m[colName] = env.ToRyeValue(vval) + sr.Values = append(sr.Values, env.ToRyeValue(vval)) + } } spr.AddRow(sr) result = append(result, m) @@ -157,13 +198,13 @@ var Builtins_mysql = map[string]*env.Builtin{ // fmt.Print(result) if i == 0 { ps.FailureFlag = true - return MakeBuiltinError(ps, "No data.", "Rye-mysql//exec") + return MakeBuiltinError(ps, "No data.", "Rye-mysql//query") } return *spr //return *env.NewNative(ps.Idx, *spr, "Rye-spreadsheet") } } else { - return MakeBuiltinError(ps, "Empty SQL.", "Rye-mysql//exec") + return MakeBuiltinError(ps, "Empty SQL.", "Rye-mysql//query") } default: diff --git a/evaldo/repl.go b/evaldo/repl.go index 93052845..d580b239 100644 --- a/evaldo/repl.go +++ b/evaldo/repl.go @@ -318,7 +318,7 @@ func MaybeDisplayFailureOrError(es *env.ProgramState, genv *env.Idxs) { } } -func DoGeneralInput(es *env.ProgramState, prompt string) { +/* THIS WAS DISABLED TEMP FOR WASM MODE .. 20250116 func DoGeneralInput(es *env.ProgramState, prompt string) { line := liner.NewLiner() defer line.Close() if code, err := line.SimplePrompt(prompt); err == nil { @@ -337,3 +337,4 @@ func DoGeneralInputField(es *env.ProgramState, prompt string) { log.Print("Error reading line: ", err) } } +*/ diff --git a/examples/examples-wip/goroutines/channels_2.rye b/examples/examples-wip/goroutines/channels_2.rye new file mode 100644 index 00000000..38f3c6b2 --- /dev/null +++ b/examples/examples-wip/goroutines/channels_2.rye @@ -0,0 +1,26 @@ +; example using more Rye features + +jobs: new-channel 5 +done: new-channel 0 + +go does { + print "waiting to process jobs" + forever { + read jobs |^fix { + print "recieved all jobs" + send done 1 + } + |print\val "received job {{}}" + sleep 1000 + } +} + +loop 3 { + .send* jobs , + .print\val "sent job {{}}" +} +close jobs + +print "waiting for jobs to finish" +read done +print "finished" diff --git a/examples/examples-wip/goroutines/goroutines_channels.rye b/examples/examples-wip/goroutines/goroutines_channels.rye index 26e15982..68b16394 100644 --- a/examples/examples-wip/goroutines/goroutines_channels.rye +++ b/examples/examples-wip/goroutines/goroutines_channels.rye @@ -1,3 +1,5 @@ +; original example + jobs: new-channel 5 done: new-channel 0 diff --git a/loader/loader.go b/loader/loader.go index aa4498bc..06238e29 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -345,19 +345,19 @@ func newParser() *Parser { // TODO -- add string eaddress path url time parser, _ := NewParser(` BLOCK <- "{" SPACES SERIES* "}" BBLOCK <- "[" SPACES SERIES* "]" - GROUP <- "(" SPACES SERIES* ")" - SERIES <- (GROUP / COMMENT / URI / EMAIL / STRING / DECIMAL / NUMBER / COMMA / SETWORD / LSETWORD / ONECHARPIPE / PIPEWORD / XWORD / OPWORD / TAGWORD / EXWORD / CPATH / FPATH / KINDWORD / GENWORD / GETWORD / WORD / VOID / BLOCK / GROUP / BBLOCK / ARGBLOCK ) SPACES - ARGBLOCK <- "{" WORD ":" WORD "}" - WORD <- LETTER LETTERORNUM* / NORMOPWORDS + GROUP <- "(" SPACES SERIES* ")" + SERIES <- (GROUP / COMMENT / URI / EMAIL / STRING / DECIMAL / NUMBER / COMMA / SETWORD / LSETWORD / ONECHARPIPE / PIPEWORD / XWORD / OPWORD / TAGWORD / EXWORD / 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* ":" LSETWORD <- ":" LETTER LETTERORNUM* GETWORD <- "?" LETTER LETTERORNUM* PIPEWORD <- "|" LETTER LETTERORNUM* / PIPEARROWS / "|" NORMOPWORDS - ONECHARPIPE <- "|" ONECHARWORDS + ONECHARPIPE <- "|" ONECHARWORDS OPWORD <- "." LETTER LETTERORNUM* / "." NORMOPWORDS / OPARROWS / ONECHARWORDS / "[*" LETTERORNUM* TAGWORD <- "'" LETTER LETTERORNUM* - KINDWORD <- "~(" LETTER LETTERORNUM* ")~"? + KINDWORD <- "~(" LETTER LETTERORNUM* ")~"? XWORD <- "<" LETTER LETTERORNUM* ">"? EXWORD <- ""? STRING <- ('"' STRINGCHAR* '"') / ("$" STRINGCHAR1* "$") @@ -367,22 +367,22 @@ func newParser() *Parser { // TODO -- add string eaddress path url time EMAILPART <- < ([a-zA-Z0-9._]+) > FPATH <- "%" URIPATH* CPATH <- WORD ( "/" WORD )+ - ONECHARWORDS <- < [<>*+-=/] > + ONECHARWORDS <- < [<>*+-=/] > NORMOPWORDS <- < ("_"[<>*+-=/]) > PIPEARROWS <- ">>" / "~>" / "->" OPARROWS <- "<<" / "<~" / "<-" / ">=" / "<=" - LETTER <- < [a-zA-Z^(` + "`" + `] > + LETTER <- < [a-zA-Z^(` + "`" + `] > LETTERORNUM <- < [a-zA-Z0-9-?=.\\!_+<>\]*()] > URIPATH <- < [a-zA-Z0-9-?=.:@/\\!_> ()] > UCLETTER <- < [A-Z] > - LCLETTERORNUM <- < [a-z0-9] > - NUMBER <- < ("-"?[0-9]+) > - DECIMAL <- < ("-"?[0-9]+.[0-9]+) > + LCLETTERORNUM <- < [a-z0-9] > + NUMBER <- < ("-"?[0-9]+) > + DECIMAL <- < ("-"?[0-9]+.[0-9]+) > SPACE <- < [ \t\r\n] > STRINGCHAR <- < !'"' . > STRINGCHAR1 <- < !"$" . > COMMA <- "," - VOID <- "_" + VOID <- "_" COMMENT <- (";" NOTENDLINE* ) NOTENDLINE <- < !"\n" . > `) diff --git a/loader/loader_test.go b/loader/loader_test.go index b988eaa7..b41d0742 100644 --- a/loader/loader_test.go +++ b/loader/loader_test.go @@ -406,7 +406,7 @@ func TestLoader_load_uri_min(t *testing.T) { t.Error("Expected scheme sqlite") } - if block.(env.Block).Series.Get(0).(env.Uri).Path != "sqlite://db" { // todo later return just the path part ... but there are more components to URI, so we do it later + if block.(env.Block).Series.Get(0).(env.Uri).Path != "db" { // todo later return just the path part ... but there are more components to URI, so we do it later t.Error("Expected path sqlite://db") } } diff --git a/main.go b/main.go index 1597030d..74a11ee1 100644 --- a/main.go +++ b/main.go @@ -51,15 +51,17 @@ func main() { evaldo.ShowResults = true if len(os.Args) == 1 { - main_rye_repl(os.Stdin, os.Stdout, false) + main_rye_repl(os.Stdin, os.Stdout, false, false) } else if len(os.Args) == 2 { if os.Args[1] == "shell" { main_rysh() + } else if os.Args[1] == "here" { + main_rye_repl(os.Stdin, os.Stdout, true, true) } else if os.Args[1] == "--hr" { evaldo.ShowResults = false - main_rye_repl(os.Stdin, os.Stdout, false) + main_rye_repl(os.Stdin, os.Stdout, false, false) } else if os.Args[1] == "--subc" { - main_rye_repl(os.Stdin, os.Stdout, true) + main_rye_repl(os.Stdin, os.Stdout, true, false) } else if os.Args[1] == "web" { // main_httpd() } else if os.Args[1] == "ryeco" { @@ -303,7 +305,7 @@ func main_cgi_file(file string, sig bool) { } } -func main_rye_repl(_ io.Reader, _ io.Writer, subc bool) { +func main_rye_repl(_ io.Reader, _ io.Writer, subc bool, here bool) { input := " 123 " // "name: \"Rye\" version: \"0.011 alpha\"" userHomeDir, _ := os.UserHomeDir() profile_path := filepath.Join(userHomeDir, ".rye-profile") @@ -317,14 +319,13 @@ func main_rye_repl(_ io.Reader, _ io.Writer, subc bool) { //} // input = string(content) } else { - fmt.Println("There was no profile.") + // fmt.Println("There was no profile.") } - + block, genv := loader.LoadString(input, false) es := env.NewProgramState(block.(env.Block).Series, genv) evaldo.RegisterBuiltins(es) contrib.RegisterBuiltins(es, &evaldo.BuiltinNames) - evaldo.EvalBlock(es) if subc { @@ -332,6 +333,22 @@ func main_rye_repl(_ io.Reader, _ io.Writer, subc bool) { es.Ctx = env.NewEnv(ctx) // make new context with no parent } + if (here) { + if _, err := os.Stat(".rye-here"); err == nil { + content, err := os.ReadFile(".rye-here") + if err != nil { + log.Fatal(err) + } + inputH := string(content) + block, genv := loader.LoadString(inputH, false) + block1 := block.(env.Block) + es = env.AddToProgramState(es, block1.Series, genv) + evaldo.EvalBlock(es) + } else { + fmt.Println("There was no `here` file.") + } + } + evaldo.DoRyeRepl(es, evaldo.ShowResults) } diff --git a/main_wasm.go b/main_wasm.go index 94aff903..4ba457af 100755 --- a/main_wasm.go +++ b/main_wasm.go @@ -11,6 +11,7 @@ import ( "github.com/refaktor/rye/env" "github.com/refaktor/rye/evaldo" "github.com/refaktor/rye/loader" + "github.com/refaktor/rye/util" ) type TagType int @@ -42,12 +43,56 @@ func main1() { // main for awk like functionality with rye language // -func main() { +func main_OLD() { c := make(chan struct{}, 0) js.Global().Set("RyeEvalString", js.FuncOf(RyeEvalString)) <-c } +var ( + jsCallback js.Value +) + +func sendMessageToJS(message string) { + jsCallback.Invoke(message) +} + +func main() { + + fmt.Println("MAIN OO") + + c := make(chan string) + + ml := util.NewMicroLiner(c, sendMessageToJS) + + js.Global().Set("RyeEvalString", js.FuncOf(RyeEvalString)) + + js.Global().Set("RyeEvalString2", js.FuncOf(RyeEvalString)) + + js.Global().Set("SendKeypress", js.FuncOf(func(this js.Value, args []js.Value) interface{} { + if len(args) > 0 { + c <- args[0].String() + } + return nil + })) + + // Get the JavaScript function to call back + jsCallback = js.Global().Get("receiveMessageFromGo") + + ml.MicroPrompt("x> ", "", 0) + + /* for { + key := <-c + // Process the keypress and then send a message back to JavaScript + response := key + if key == "A" { + response = "\x1B[1;3;31mA\x1B[0m" + } + sendMessageToJS(response) + } */ + +} + func RyeEvalString(this js.Value, args []js.Value) any { sig := false subc := true diff --git a/tests/structures.rye b/tests/structures.rye index 915f023f..64a7ca0d 100644 --- a/tests/structures.rye +++ b/tests/structures.rye @@ -84,7 +84,7 @@ section "Working with blocks and lists" } group "->" - mold\nowrap ?_-> + mold\nowrap "?_->" { { string } } { equal { { 11 22 33 } -> 1 } 22 @@ -93,7 +93,7 @@ section "Working with blocks and lists" } group "<-" - mold\nowrap ?_<- + mold\nowrap "?_<-" { { string } } { equal { 2 <- { 11 22 33 } } 33 @@ -237,7 +237,7 @@ section "Working with blocks and lists" { equal { { 3 2 3 5 3 2 } .list .unique .length? } 3 ; result order is not deterministic list { 3 2 5 } } - + } @@ -495,7 +495,7 @@ section "Serializers and loaders" mold\nowrap ?mold\nowrap { { function } } { - equal { mold\nowrap "33" } $"33"$ + equal { mold\nowrap "33" } $33$ ; TODO --- unify this ... just changed probe to not have quotes } group "capture-stdout" mold\nowrap ?capture-stdout diff --git a/wasm/index.html b/wasm/index.html index 9b23a651..99b77631 100644 --- a/wasm/index.html +++ b/wasm/index.html @@ -37,7 +37,7 @@ } const go = new Go(); - WebAssembly.instantiateStreaming(fetch('rye.wasm'), go.importObject).then(function(dat) { + WebAssembly.instantiateStreaming(fetch('main.wasm'), go.importObject).then(function(dat) { go.run(dat.instance); }); diff --git a/wasm/wasm_exec.js b/wasm/wasm_exec.js index bc49048c..bc6f2102 100644 --- a/wasm/wasm_exec.js +++ b/wasm/wasm_exec.js @@ -4,8 +4,6 @@ "use strict"; -var fullOutput = ""; // JM -- added this to capture the stdio output - (() => { const enosys = () => { const err = new Error("not implemented"); @@ -21,9 +19,8 @@ var fullOutput = ""; // JM -- added this to capture the stdio output outputBuf += decoder.decode(buf); const nl = outputBuf.lastIndexOf("\n"); if (nl != -1) { - console.log(outputBuf.substr(0, nl)); - fullOutput += outputBuf.substr(0, nl) + "\n"; // JM -- added this to capture the stdio output - outputBuf = outputBuf.substr(nl + 1); + console.log(outputBuf.substring(0, nl)); + outputBuf = outputBuf.substring(nl + 1); } return buf.length; }, @@ -116,6 +113,10 @@ var fullOutput = ""; // JM -- added this to capture the stdio output this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true); } + const setInt32 = (addr, v) => { + this.mem.setUint32(addr + 0, v, true); + } + const getInt64 = (addr) => { const low = this.mem.getUint32(addr + 0, true); const high = this.mem.getInt32(addr + 4, true); @@ -209,7 +210,10 @@ var fullOutput = ""; // JM -- added this to capture the stdio output const timeOrigin = Date.now() - performance.now(); this.importObject = { - go: { + _gotest: { + add: (a, b) => a + b, + }, + gojs: { // Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters) // may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported // function. A goroutine can switch to a new stack if the current stack is too small (see morestack function). @@ -272,7 +276,7 @@ var fullOutput = ""; // JM -- added this to capture the stdio output this._resume(); } }, - getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early + getInt64(sp + 8), )); this.mem.setInt32(sp + 16, id, true); },