evaluator: Add index and dot expression evaluation#39
Conversation
|
firebase-deployment: https://evy-lang--39-zvdfxh68.web.app (0237bfa) |
| `print 1 (len "abc") 2`: "print(1, len('abc'), 2)", | ||
| `print (len "abc") 2`: "print(len('abc'), 2)", | ||
| `print (len "abc") (len "x")`: "print(len('abc'), len('x'))", | ||
| `print s[1]`: "print((s[1]))", |
There was a problem hiding this comment.
This was a nil panic before
| ` | ||
| m := {name: "Greta"} | ||
| s := name | ||
| print m[s]`: "line 3 column 6: unknown variable name 'name'", |
There was a problem hiding this comment.
nil panic before fix.
camh-
left a comment
There was a problem hiding this comment.
🍃 LGTM. A few comments, but feel free to fix, commit and merge.
| return val | ||
| } | ||
| if decl.Type() == parser.ANY_TYPE { | ||
| val = &Any{Val: val} |
There was a problem hiding this comment.
If e.Eval(...) above returns an Any, should you just use val as is?
There was a problem hiding this comment.
If I remove these added lines I get a test failures:
--- FAIL: TestAssignmentAny (0.00s)
evaluator_test.go:174: want != got
"false 0\n0 0\n🦊 0\n"
"false 0\nfalse 0\nfalse 0\n"
There was a problem hiding this comment.
The zero value for any is false; the inferred decl might by anything, but in either case it does not return the wrapped any type it seems but the bare type.
There was a problem hiding this comment.
If you search for &Any{.... it doesn't seem to be created anywhere in the evaluator.go file.
There was a problem hiding this comment.
OH! I think you are suggesting I should just add it to the main switch.
There was a problem hiding this comment.
hmmm. not sure actually
There was a problem hiding this comment.
add a parseAnyLiteral ?
The wrapped value could hold an error so we want to surface that I think.
There was a problem hiding this comment.
also: there is no AST node for Any...
I think I need to leave this as is.
There was a problem hiding this comment.
I just meant if eval could return an any will you end up wrapping an any in an any?
pkg/evaluator/value.go
Outdated
|
|
||
| func (m *Map) Set(v Value) { | ||
| if m2, ok := v.(*Map); ok { | ||
| m.Pairs = m2.Pairs |
There was a problem hiding this comment.
Just *m = *m2 should do i think (instead of assigning individual elements) - and you could do that for all the Set() methods if you like
| case *Map: | ||
| index, ok := index.(*String) | ||
| if !ok { | ||
| return newError("expected string for map index, found " + index.String()) |
There was a problem hiding this comment.
hmmm, isn't index here an empty string or something from two lines above? Shadowing vars is confusing. I was also confused about left which I thought was a Node, but later realised it was shadowed by the type switch. I guess its ok, I'm not sure what other name to give it that makes sense.
But, shouldn't you be printing the type of the incorrect map index? as in "expected , got "?
Edit: checked the spec, and indeed index will be an empty string in this error message.
There was a problem hiding this comment.
ok, I've renamed this to strIndex and also renamed left := left.(type) to l := left.(type).
I've added an extra fixup commit on top doing the rename from the previous evalBinaryExpr function for consitency.
| "print m.name": "Greta", | ||
| `print m["name"]`: "Greta", | ||
| `s := "name" | ||
| print m[s]`: "Greta", |
There was a problem hiding this comment.
Should there be a test case for looking up a key not in the map? I can't remember what the semantics of that is? Returns zero value like Go? (as an aside, what's the zero value of any? doesn't seem to be in the spec)
ok, I see from below value.go that a bad index is an error. leaving this comment for the any question.
🍍
There was a problem hiding this comment.
ok, good point. I've added a test case. Will add more when implementing has and del functions.
I wonder if I should return the zero value....
There was a problem hiding this comment.
sorry, no good at not answering.
Fix IndexExpression.Type() for indexed string, e.g. "abc"[1]. We indiscriminately returned left.Type().Sub, which is only correct for arrays. For strings the indexed type should also be string.
Add missing early return on index expression parse error. This resulted in a "dereferenced nil pointer" panic at run time.
3548b60 to
e564415
Compare
Rework scoped Value updates such that instead of replacing the value in the scope on assignment with scope.set(name, newValue), we now update the Value field with: val := scope.get(name) val.set(newVal) This is a preparatory step for index and dot expressions which also update the "internals" of a Value. As a fall-out of this step we had to extend the Value interface with a `Set(Val)` method. We also had to remove the bool constants TRUE and FALSE, as the internals of these constants got updated. `scope.getScope (name)` is now not needed any longer and removed. Additionally introduce an `Any` type that implements Value and wraps a value so that we can update an any value from one type to another, e.g. Bool to String.
Change Array.Elements and Map.Order to pointer. This is another preparatory step for proper array and map manipulation so that two variables may reference the same array or map and if one gets updated the other one will get updated too. In go maps are references and natively support this property, however slices may get allocated new memory and are not guaranteed to keep the same reference and appended.
ba173e9 to
f27370f
Compare
Add index and dot expression evaluation in evaluator, similar to binary expression evaluation.
Rename local variable in evalBinaryExpr for consistency with new evalIndexExpr: avoid variable shadowing when type casting in switch statement.
b09dda1 to
0237bfa
Compare
Add index and dot expression evaluation in evaluator, similar to binary
expression evaluation.
Change Array.Elements and Map.Order to pointer. This is another preparatory
step for proper array and map manipulation so that two variables may
reference the same array or map and if one gets updated the other one will
get updated too.
Rework scoped Value updates such that instead of replacing the value in the
scope on assignment with scope.set(name, newValue), we now update the Value
field with scope.get(name).Set(newValue)
The first three commits are covered by PRs #37 and #38 .