From d96123ab026724ead86c8beed0231e0a21d0622c Mon Sep 17 00:00:00 2001 From: Celestino Amoroso Date: Tue, 4 Jun 2024 11:07:35 +0200 Subject: [PATCH] The assign operator '=' can now set items in ListType and DictType --- operator-assign.go | 129 ++++++++++++++++++++++++++++++++++++++++++++- t_list_test.go | 2 +- 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/operator-assign.go b/operator-assign.go index 7a5fd5f..930deea 100644 --- a/operator-assign.go +++ b/operator-assign.go @@ -16,13 +16,93 @@ func newAssignTerm(tk *Token) (inst *term) { } } +func assignListItem(list *ListType, index int64, value any) (err error) { + return list.setItem(index, value) +} + +func assignCollectionItem(ctx ExprContext, collectionTerm, keyListTerm *term, value any) (err error) { + var collectionValue, keyListValue, keyValue any + var keyList *ListType + var ok bool + + if collectionValue, err = collectionTerm.compute(ctx); err != nil { + return + } + + if keyListValue, err = keyListTerm.compute(ctx); err != nil { + return + } else if keyList, ok = keyListValue.(*ListType); !ok || len(*keyList) != 1 { + err = keyListTerm.Errorf("index/key specification expected, got %v [%T]", keyListValue, keyListValue) + return + } + keyValue = (*keyList)[0] + + switch collection := collectionValue.(type) { + case *ListType: + if index, ok := keyValue.(int64); ok { + err = assignListItem(collection, index, value) + } else { + err = keyListTerm.Errorf("integer expected, got %v [%T]", keyValue, keyValue) + } + case *DictType: + collection.setItem(keyValue, value) + default: + err = collectionTerm.Errorf("collection expected") + } + return +} + +func assignValue(ctx ExprContext, leftTerm *term, v any) (err error) { + if leftTerm.symbol() == SymIndex { + err = assignCollectionItem(ctx, leftTerm.children[0], leftTerm.children[1], v) + } else { + ctx.UnsafeSetVar(leftTerm.source(), v) + } + return +} + +func _assignValue(ctx ExprContext, leftTerm *term, v any) (err error) { + if leftTerm.symbol() == SymIndex { + var collection, indexListAny any + var list *ListType + var index int64 + if collection, err = leftTerm.children[0].compute(ctx); err != nil { + return + } else if IsList(collection) { + list, _ = collection.(*ListType) + } else { + err = leftTerm.children[0].Errorf("expected collection") + return + } + + if indexListAny, err = leftTerm.children[1].compute(ctx); err != nil { + return + } else if indexList, ok := indexListAny.(*ListType); ok && len(*indexList) == 1 { + if indexAny := (*indexList)[0]; IsInteger(indexAny) { + index, _ = indexAny.(int64) + } else { + err = leftTerm.children[1].Errorf("expected integer, got %v [%T]", indexAny, indexAny) + } + } else { + err = leftTerm.children[1].Errorf("expected index spec, got %v [%T]", indexListAny, indexListAny) + return + } + list.setItem(index, v) + } else { + ctx.UnsafeSetVar(leftTerm.source(), v) + } + return +} + +/* func evalAssign(ctx ExprContext, self *term) (v any, err error) { if err = self.checkOperands(); err != nil { return } leftTerm := self.children[0] - if leftTerm.tk.Sym != SymVariable { + leftSym := leftTerm.symbol() + if leftSym != SymVariable && leftSym != SymIndex { err = leftTerm.tk.Errorf("left operand of %q must be a variable", self.tk.source) return } @@ -49,6 +129,53 @@ func evalAssign(ctx ExprContext, self *term) (v any, err error) { } return } +*/ + +func evalAssign(ctx ExprContext, self *term) (v any, err error) { + if err = self.checkOperands(); err != nil { + return + } + + leftTerm := self.children[0] + leftSym := leftTerm.symbol() + if leftSym != SymVariable && leftSym != SymIndex { + err = leftTerm.tk.Errorf("left operand of %q must be a variable", self.tk.source) + return + } + + rightChild := self.children[1] + + if v, err = rightChild.compute(ctx); err == nil { + if functor, ok := v.(Functor); ok { + if info := functor.GetFunc(); info != nil { + ctx.RegisterFunc(leftTerm.source(), info.Functor(), info.ReturnType(), info.Params()) + } else if funcDef, ok := functor.(*exprFunctor); ok { + // paramSpecs := ForAll(funcDef.params, newFuncParam) + paramSpecs := ForAll(funcDef.params, func(p ExprFuncParam) ExprFuncParam { return p }) + + ctx.RegisterFunc(leftTerm.source(), functor, typeAny, paramSpecs) + /* + } + funcName := rightChild.source() + if info, exists, _ := GetFuncInfo(ctx, funcName); exists { + // ctx.RegisterFuncInfo(info) + ctx.RegisterFunc(leftTerm.source(), info.Functor(), info.ReturnType(), info.Params()) + } else if funcDef, ok := functor.(*exprFunctor); ok { + // paramSpecs := ForAll(funcDef.params, newFuncParam) + paramSpecs := ForAll(funcDef.params, func(p ExprFuncParam) ExprFuncParam { return p }) + + ctx.RegisterFunc(leftTerm.source(), functor, typeAny, paramSpecs) + */ + } else { + err = self.Errorf("unknown function %s()", rightChild.source()) + } + } else { + err = assignValue(ctx, leftTerm, v) + //ctx.UnsafeSetVar(leftTerm.source(), v) + } + } + return +} // init func init() { diff --git a/t_list_test.go b/t_list_test.go index 69b3bf2..d39013d 100644 --- a/t_list_test.go +++ b/t_list_test.go @@ -52,7 +52,7 @@ func TestListParser(t *testing.T) { /* 30 */ {`2 >> 3;`, nil, errors.New(`[1:4] left operand '2' [integer] and right operand '3' [integer] are not compatible with operator ">>"`)}, /* 31 */ {`a=[1,2]; a<<3`, []any{1, 2, 3}, nil}, /* 33 */ {`a=[1,2]; 5>>a`, []any{5, 1, 2}, nil}, - + /* 34 */ {`L=[1,2]; L[0]=9; L`, newListA(int64(9),int64(2)), nil}, // /* 8 */ {`[int(x)|x=csv("test.csv",1,all(),1)]`, []any{int64(10), int64(40), int64(20)}, nil}, // /* 9 */ {`sum(@[int(x)|x=csv("test.csv",1,all(),1)])`, []any{int64(10), int64(40), int64(20)}, nil}, }