Translate CocoPy subscripts
This change implements simple index-based CocoPy subscripts (and not the more fully featured slicing ones). Alongside this, we relax a binder-time check that all dynamic access types must be strings. The eval code already handles numeric (array) accesses, so we will permit these to flow through.
This commit is contained in:
parent
9adfa6a18f
commit
aa730b5913
3 changed files with 29 additions and 8 deletions
|
@ -3,6 +3,7 @@
|
|||
package binder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/pulumi/coconut/pkg/compiler/ast"
|
||||
|
@ -240,10 +241,25 @@ func (a *astBinder) checkForStatement(node *ast.ForStatement) {
|
|||
|
||||
// Expressions
|
||||
|
||||
func (a *astBinder) checkExprType(expr ast.Expression, expect symbols.Type) bool {
|
||||
func (a *astBinder) checkExprType(expr ast.Expression, expect symbols.Type, alts ...symbols.Type) bool {
|
||||
actual := a.b.ctx.RequireType(expr)
|
||||
if !types.CanConvert(actual, expect) {
|
||||
a.b.Diag().Errorf(errors.ErrorIncorrectExprType.At(expr), expect, actual)
|
||||
conv := false
|
||||
if conv = types.CanConvert(actual, expect); !conv {
|
||||
// If the primary didn't convert, check the alternatives.
|
||||
for _, alt := range alts {
|
||||
if conv = types.CanConvert(actual, alt); conv {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if !conv {
|
||||
expects := expect.Token().String()
|
||||
if len(alts) > 0 {
|
||||
for _, alt := range alts {
|
||||
expects += fmt.Sprintf(" or %v", alt.Token())
|
||||
}
|
||||
}
|
||||
a.b.Diag().Errorf(errors.ErrorIncorrectExprType.At(expr), expects, actual)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
@ -382,8 +398,8 @@ func (a *astBinder) checkLoadLocationExpression(node *ast.LoadLocationExpression
|
|||
}
|
||||
|
||||
func (a *astBinder) checkLoadDynamicExpression(node *ast.LoadDynamicExpression) {
|
||||
// Ensure that the name is either a string or a dynamic.
|
||||
a.checkExprType(node.Name, types.String)
|
||||
// Ensure that the name is either a string, number, or a dynamic.
|
||||
a.checkExprType(node.Name, types.String, types.Number)
|
||||
|
||||
// No matter the outcome, a load dynamic always produces a dynamically typed thing.
|
||||
a.b.ctx.RegisterType(node, types.Dynamic)
|
||||
|
|
|
@ -1586,8 +1586,8 @@ func (e *evaluator) evalNew(node diag.Diagable, t symbols.Type, args *[]*ast.Cal
|
|||
for i, arg := range *args {
|
||||
contract.Assertf(arg.Name != nil, "Expected only named args for new of a record type")
|
||||
id := tokens.ClassMemberName(arg.Name.Ident)
|
||||
contract.Assertf(t.TypeMembers()[id] != nil, "Expected named arg to match a type member")
|
||||
contract.Assertf(t.TypeMembers()[id].Primary(), "Expected named arg to match a primary member")
|
||||
contract.Assertf(t.TypeMembers()[id] != nil, "Expected named arg %v to match a type member", id)
|
||||
contract.Assertf(t.TypeMembers()[id].Primary(), "Expected named arg %v to match a primary member", id)
|
||||
val := argobjs[i]
|
||||
prop := rt.PropertyKey(id)
|
||||
addr := obj.GetPropertyAddr(prop, true, true)
|
||||
|
|
|
@ -580,7 +580,12 @@ class Transformer:
|
|||
self.not_yet_implemented(node) # value, ctx
|
||||
|
||||
def transform_Subscript(self, node):
|
||||
self.not_yet_implemented(node) # value, slice, ctx
|
||||
obj = self.transform_expr(node.value)
|
||||
if isinstance(node.slice, py_ast.Index):
|
||||
idx = self.transform_expr(node.slice.value)
|
||||
else:
|
||||
assert false, "Unsupported slicing type: {}".format(type(node.slice).__name__)
|
||||
return ast.LoadDynamicExpression(idx, obj, loc=self.loc_from(node))
|
||||
|
||||
def transform_Tuple(self, node):
|
||||
self.not_yet_implemented(node) # elts, ctx
|
||||
|
|
Loading…
Reference in a new issue