From 8e6e8fa947efaa9f1252589aa01ae8aa2e1f937a Mon Sep 17 00:00:00 2001 From: refaktor Date: Tue, 14 May 2024 10:28:53 +0200 Subject: [PATCH] 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