|
@@ -42,6 +42,10 @@ func (rt *assignmentRuntime) Validate() error {
|
|
|
|
|
|
leftVar := rt.node.Children[0]
|
|
|
|
|
|
+ if _, ok := leftVar.Runtime.(*letRuntime); ok {
|
|
|
+ leftVar = leftVar.Children[0]
|
|
|
+ }
|
|
|
+
|
|
|
if leftRuntime, ok := leftVar.Runtime.(*identifierRuntime); ok {
|
|
|
|
|
|
rt.leftSide = []*identifierRuntime{leftRuntime}
|
|
@@ -79,44 +83,132 @@ func (rt *assignmentRuntime) Eval(vs parser.Scope, is map[string]interface{}, ti
|
|
|
_, err := rt.baseRuntime.Eval(vs, is, tid)
|
|
|
|
|
|
if err == nil {
|
|
|
- var val interface{}
|
|
|
|
|
|
- val, err = rt.node.Children[1].Runtime.Eval(vs, is, tid)
|
|
|
+
|
|
|
|
|
|
- if err == nil {
|
|
|
- if len(rt.leftSide) == 1 {
|
|
|
+ if _, err = rt.node.Children[0].Runtime.Eval(vs, is, tid); err == nil {
|
|
|
+ var val interface{}
|
|
|
|
|
|
- err = rt.leftSide[0].Set(vs, is, tid, val)
|
|
|
+ val, err = rt.node.Children[1].Runtime.Eval(vs, is, tid)
|
|
|
|
|
|
- } else if valList, ok := val.([]interface{}); ok {
|
|
|
+ if err == nil {
|
|
|
+ if len(rt.leftSide) == 1 {
|
|
|
|
|
|
- if len(rt.leftSide) != len(valList) {
|
|
|
+ err = rt.leftSide[0].Set(vs, is, tid, val)
|
|
|
|
|
|
- err = rt.erp.NewRuntimeError(util.ErrInvalidState,
|
|
|
- fmt.Sprintf("Assigned number of variables is different to "+
|
|
|
- "number of values (%v variables vs %v values)",
|
|
|
- len(rt.leftSide), len(valList)), rt.node)
|
|
|
+ } else if valList, ok := val.([]interface{}); ok {
|
|
|
|
|
|
- } else {
|
|
|
+ if len(rt.leftSide) != len(valList) {
|
|
|
|
|
|
- for i, v := range rt.leftSide {
|
|
|
+ err = rt.erp.NewRuntimeError(util.ErrInvalidState,
|
|
|
+ fmt.Sprintf("Assigned number of variables is different to "+
|
|
|
+ "number of values (%v variables vs %v values)",
|
|
|
+ len(rt.leftSide), len(valList)), rt.node)
|
|
|
|
|
|
- if err = v.Set(vs, is, tid, valList[i]); err != nil {
|
|
|
- err = rt.erp.NewRuntimeError(util.ErrVarAccess,
|
|
|
- err.Error(), rt.node)
|
|
|
- break
|
|
|
+ } else {
|
|
|
+
|
|
|
+ for i, v := range rt.leftSide {
|
|
|
+
|
|
|
+ if err = v.Set(vs, is, tid, valList[i]); err != nil {
|
|
|
+ err = rt.erp.NewRuntimeError(util.ErrVarAccess,
|
|
|
+ err.Error(), rt.node)
|
|
|
+ break
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- } else {
|
|
|
+ } else {
|
|
|
|
|
|
- err = rt.erp.NewRuntimeError(util.ErrInvalidState,
|
|
|
- fmt.Sprintf("Result is not a list (value is %v)", val),
|
|
|
- rt.node)
|
|
|
+ err = rt.erp.NewRuntimeError(util.ErrInvalidState,
|
|
|
+ fmt.Sprintf("Result is not a list (value is %v)", val),
|
|
|
+ rt.node)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil, err
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+letRuntime is the runtime component for let statements
|
|
|
+*/
|
|
|
+type letRuntime struct {
|
|
|
+ *baseRuntime
|
|
|
+ declared []*identifierRuntime
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+letRuntimeInst returns a new runtime component instance.
|
|
|
+*/
|
|
|
+func letRuntimeInst(erp *ECALRuntimeProvider, node *parser.ASTNode) parser.Runtime {
|
|
|
+ return &letRuntime{newBaseRuntime(erp, node), nil}
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+Validate this node and all its child nodes.
|
|
|
+*/
|
|
|
+func (rt *letRuntime) Validate() error {
|
|
|
+ err := rt.baseRuntime.Validate()
|
|
|
+
|
|
|
+ if err == nil {
|
|
|
+
|
|
|
+ leftVar := rt.node.Children[0]
|
|
|
+
|
|
|
+ if leftRuntime, ok := leftVar.Runtime.(*identifierRuntime); ok {
|
|
|
+
|
|
|
+ rt.declared = []*identifierRuntime{leftRuntime}
|
|
|
+
|
|
|
+ } else if leftVar.Name == parser.NodeLIST {
|
|
|
+
|
|
|
+ rt.declared = make([]*identifierRuntime, 0, len(leftVar.Children))
|
|
|
+
|
|
|
+ for _, child := range leftVar.Children {
|
|
|
+ childRuntime, ok := child.Runtime.(*identifierRuntime)
|
|
|
+
|
|
|
+ if !ok {
|
|
|
+ err = rt.erp.NewRuntimeError(util.ErrInvalidConstruct,
|
|
|
+ "Let can only declare variables within a list", rt.node)
|
|
|
+ break
|
|
|
+ }
|
|
|
+
|
|
|
+ rt.declared = append(rt.declared, childRuntime)
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ err = rt.erp.NewRuntimeError(util.ErrInvalidConstruct,
|
|
|
+ "Let must declare a variable or list of variables", rt.node)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+Eval evaluate this runtime component.
|
|
|
+*/
|
|
|
+func (rt *letRuntime) Eval(vs parser.Scope, is map[string]interface{}, tid uint64) (interface{}, error) {
|
|
|
+ var res interface{}
|
|
|
+
|
|
|
+ _, err := rt.baseRuntime.Eval(vs, is, tid)
|
|
|
+
|
|
|
+ if err == nil {
|
|
|
+
|
|
|
+ for _, v := range rt.declared {
|
|
|
+ if len(v.node.Children) == 0 {
|
|
|
+ vs.SetLocalValue(v.node.Token.Val, nil)
|
|
|
+ } else {
|
|
|
+ err = rt.erp.NewRuntimeError(util.ErrInvalidConstruct,
|
|
|
+ "Let can only declare simple variables", rt.node)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if err == nil {
|
|
|
+ res, err = rt.node.Children[0].Runtime.Eval(vs, is, tid)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return res, err
|
|
|
+}
|