diff options
Diffstat (limited to 'usr/austin/eval/expr.go')
-rw-r--r-- | usr/austin/eval/expr.go | 176 |
1 files changed, 167 insertions, 9 deletions
diff --git a/usr/austin/eval/expr.go b/usr/austin/eval/expr.go index 3ebd493fe..498822473 100644 --- a/usr/austin/eval/expr.go +++ b/usr/austin/eval/expr.go @@ -35,6 +35,7 @@ type exprCompiler struct { evalIdealFloat func() *bignum.Rational; evalString func(f *Frame) string; evalArray func(f *Frame) ArrayValue; + evalStruct func(f *Frame) StructValue; evalPtr func(f *Frame) Value; evalFunc func(f *Frame) Func; evalMulti func(f *Frame) []Value; @@ -64,7 +65,7 @@ func (a *exprCompiler) genConstant(v Value) func (a *exprCompiler) genIdentOp(level int, index int) func (a *exprCompiler) genIndexArray(l *exprCompiler, r *exprCompiler) func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) -func (a *exprCompiler) genStarOp(v *exprCompiler) +func (a *exprCompiler) genValue(vf func(*Frame) Value) func (a *exprCompiler) genUnaryOpNeg(v *exprCompiler) func (a *exprCompiler) genUnaryOpNot(v *exprCompiler) func (a *exprCompiler) genUnaryOpXor(v *exprCompiler) @@ -172,6 +173,13 @@ func (a *exprCompiler) asArray() (func(f *Frame) ArrayValue) { return a.evalArray; } +func (a *exprCompiler) asStruct() (func(f *Frame) StructValue) { + if a.evalStruct == nil { + log.Crashf("tried to get %v node as StructType", a.t); + } + return a.evalStruct; +} + func (a *exprCompiler) asPtr() (func(f *Frame) Value) { if a.evalPtr == nil { log.Crashf("tried to get %v node as PtrType", a.t); @@ -272,6 +280,10 @@ func (a *exprCompiler) convertTo(t Type) *exprCompiler { return res; } +func (a *exprCompiler) genStarOp(v *exprCompiler) { + a.genValue(v.asPtr()); +} + /* * Assignments */ @@ -596,7 +608,135 @@ func (a *exprCompiler) DoParenExpr(x *ast.ParenExpr) { } func (a *exprCompiler) DoSelectorExpr(x *ast.SelectorExpr) { - log.Crash("Not implemented"); + v := a.copyVisit(x.X); + if v.t == nil { + return; + } + + // mark marks a field that matches the selector name. It + // tracks the best depth found so far and whether more than + // one field has been found at that depth. + bestDepth := -1; + ambig := false; + amberr := ""; + mark := func(depth int, pathName string) { + switch { + case bestDepth == -1 || depth < bestDepth: + bestDepth = depth; + ambig = false; + amberr = ""; + + case depth == bestDepth: + ambig = true; + + default: + log.Crashf("Marked field at depth %d, but already found one at depth %d", depth, bestDepth); + } + amberr += "\n\t" + pathName[1:len(pathName)]; + }; + + name := x.Sel.Value; + visited := make(map[Type] bool); + + // find recursively searches for the named field, starting at + // type t. If it finds the named field, it returns a function + // which takes an exprCompiler that retrieves a value of type + // 't' and fills 'a' to retrieve the named field. We delay + // exprCompiler construction to avoid filling in anything + // until we're sure we have the right field, and to avoid + // producing lots of garbage exprCompilers as we search. + var find func(Type, int, string) (func (*exprCompiler)); + find = func(t Type, depth int, pathName string) (func (*exprCompiler)) { + // Don't bother looking if we've found something shallower + if bestDepth != -1 && bestDepth < depth { + return nil; + } + + // Don't check the same type twice and avoid loops + if _, ok := visited[t]; ok { + return nil; + } + visited[t] = true; + + // Implicit dereference + deref := false; + if ti, ok := t.(*PtrType); ok { + deref = true; + t = ti.Elem; + } + + // If it's a named type, look for methods + if ti, ok := t.(*NamedType); ok { + method, ok := ti.methods[name]; + if ok { + mark(depth, pathName + "." + name); + log.Crash("Methods not implemented"); + } + t = ti.def; + } + + // If it's a struct type, check fields and embedded types + var builder func(*exprCompiler); + if t, ok := t.(*StructType); ok { + for i, f := range t.Elems { + var this *exprCompiler; + var sub func(*exprCompiler); + switch { + case f.Name == name: + mark(depth, pathName + "." + name); + this = a; + sub = func(*exprCompiler) {}; + + case f.Anonymous: + sub = find(f.Type, depth+1, pathName + "." + f.Name); + if sub == nil { + continue; + } + this = a.copy(); + + default: + continue; + } + + // We found something. Create a + // builder for accessing this field. + ft := f.Type; + index := i; + builder = func(parent *exprCompiler) { + this.t = ft; + var evalAddr func(f *Frame) Value; + if deref { + pf := parent.asPtr(); + evalAddr = func(f *Frame) Value { + return pf(f).(StructValue).Field(index); + }; + } else { + pf := parent.asStruct(); + evalAddr = func(f *Frame) Value { + return pf(f).Field(index); + }; + } + this.genValue(evalAddr); + sub(this); + }; + } + } + + return builder; + }; + + builder := find(v.t, 0, ""); + if builder == nil { + a.diag("type %v has no field or method %s", v.t, name); + return; + } + if ambig { + a.diag("field %s is ambiguous in type %v%s", name, v.t, amberr); + return; + } + + a.desc = "selector expression"; + builder(v); } func (a *exprCompiler) DoIndexExpr(x *ast.IndexExpr) { @@ -810,6 +950,7 @@ func (a *exprCompiler) DoStarExpr(x *ast.StarExpr) { switch vt := v.t.lit().(type) { case *PtrType: a.t = vt.Elem; + // TODO(austin) Deal with nil pointers a.genStarOp(v); a.desc = "indirect expression"; @@ -1134,10 +1275,15 @@ func (a *exprCompiler) doBinaryExpr(op token.Token, l, r *exprCompiler) { return; } // Arrays and structs may not be compared to anything. + // TODO(austin) Use a multi-type switch if _, ok := l.t.(*ArrayType); ok { a.diagOpTypes(op, origlt, origrt); return; } + if _, ok := l.t.(*StructType); ok { + a.diagOpTypes(op, origlt, origrt); + return; + } a.t = BoolType; default: @@ -1283,11 +1429,8 @@ func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) { if lenExpr == nil { return 0, false; } - if !lenExpr.t.isInteger() { - a.diagAt(expr, "array size must be an integer"); - return 0, false; - } + // XXX(Spec) Are ideal floats with no fractional part okay? if lenExpr.t.isIdeal() { lenExpr = lenExpr.convertTo(IntType); if lenExpr == nil { @@ -1295,6 +1438,11 @@ func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) { } } + if !lenExpr.t.isInteger() { + a.diagAt(expr, "array size must be an integer"); + return 0, false; + } + switch _ := lenExpr.t.lit().(type) { case *intType: return lenExpr.evalInt(nil), true; @@ -1442,6 +1590,9 @@ func (a *exprCompiler) genConstant(v Value) { case *ArrayType: val := v.(ArrayValue).Get(); a.evalArray = func(f *Frame) ArrayValue { return val }; + case *StructType: + val := v.(StructValue).Get(); + a.evalStruct = func(f *Frame) StructValue { return val }; case *PtrType: val := v.(PtrValue).Get(); a.evalPtr = func(f *Frame) Value { return val }; @@ -1468,6 +1619,8 @@ func (a *exprCompiler) genIdentOp(level int, index int) { a.evalString = func(f *Frame) string { return f.Get(level, index).(StringValue).Get() }; case *ArrayType: a.evalArray = func(f *Frame) ArrayValue { return f.Get(level, index).(ArrayValue).Get() }; + case *StructType: + a.evalStruct = func(f *Frame) StructValue { return f.Get(level, index).(StructValue).Get() }; case *PtrType: a.evalPtr = func(f *Frame) Value { return f.Get(level, index).(PtrValue).Get() }; case *FuncType: @@ -1493,6 +1646,8 @@ func (a *exprCompiler) genIndexArray(l *exprCompiler, r *exprCompiler) { a.evalString = func(f *Frame) string { return lf(f).Elem(rf(f)).(StringValue).Get() }; case *ArrayType: a.evalArray = func(f *Frame) ArrayValue { return lf(f).Elem(rf(f)).(ArrayValue).Get() }; + case *StructType: + a.evalStruct = func(f *Frame) StructValue { return lf(f).Elem(rf(f)).(StructValue).Get() }; case *PtrType: a.evalPtr = func(f *Frame) Value { return lf(f).Elem(rf(f)).(PtrValue).Get() }; case *FuncType: @@ -1517,6 +1672,8 @@ func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) { a.evalString = func(f *Frame) string { return call(f)[0].(StringValue).Get() }; case *ArrayType: a.evalArray = func(f *Frame) ArrayValue { return call(f)[0].(ArrayValue).Get() }; + case *StructType: + a.evalStruct = func(f *Frame) StructValue { return call(f)[0].(StructValue).Get() }; case *PtrType: a.evalPtr = func(f *Frame) Value { return call(f)[0].(PtrValue).Get() }; case *FuncType: @@ -1528,9 +1685,8 @@ func (a *exprCompiler) genFuncCall(call func(f *Frame) []Value) { } } -func (a *exprCompiler) genStarOp(v *exprCompiler) { - vf := v.asPtr(); - a.evalAddr = func(f *Frame) Value { return vf(f) }; +func (a *exprCompiler) genValue(vf func(*Frame) Value) { + a.evalAddr = vf; switch _ := a.t.lit().(type) { case *boolType: a.evalBool = func(f *Frame) bool { return vf(f).(BoolValue).Get() }; @@ -1544,6 +1700,8 @@ func (a *exprCompiler) genStarOp(v *exprCompiler) { a.evalString = func(f *Frame) string { return vf(f).(StringValue).Get() }; case *ArrayType: a.evalArray = func(f *Frame) ArrayValue { return vf(f).(ArrayValue).Get() }; + case *StructType: + a.evalStruct = func(f *Frame) StructValue { return vf(f).(StructValue).Get() }; case *PtrType: a.evalPtr = func(f *Frame) Value { return vf(f).(PtrValue).Get() }; case *FuncType: |