func buildIdent(b *builder, ident *lex8.Token) tast.Expr { s := b.scope.Query(ident.Lit) if s == nil { b.Errorf(ident.Pos, "undefined identifier %s", ident.Lit) return nil } b.refSym(s, ident.Pos) t := s.ObjType.(types.T) switch s.Type { case tast.SymVar, tast.SymField: ref := tast.NewAddressableRef(t) return &tast.Ident{ident, ref, s} case tast.SymConst, tast.SymStruct, tast.SymType, tast.SymImport: ref := tast.NewRef(t) return &tast.Ident{ident, ref, s} case tast.SymFunc: if t, ok := t.(*types.Func); ok { if t.MethodFunc == nil { return &tast.Ident{ident, tast.NewRef(t), s} } if b.this == nil { panic("this missing") } ref := &tast.Ref{T: t.MethodFunc, Recv: b.this} return &tast.Ident{ident, ref, s} } return &tast.Ident{ident, tast.NewRef(t), s} default: b.Errorf(ident.Pos, "todo: token type: %s", tast.SymStr(s.Type)) return nil } }
func buildIdent(b *builder, id *tast.Ident) *ref { s := id.Symbol switch s.Type { case tast.SymVar: return s.Obj.(*objVar).ref case tast.SymFunc: v := s.Obj.(*objFunc) if !v.isMethod { return v.ref } if b.this == nil { panic("this missing") } return newRecvRef(v.Type().(*types.Func), b.this, v.IR()) case tast.SymConst: return s.Obj.(*objConst).ref case tast.SymField: v := s.Obj.(*types.Field) return buildField(b, b.this.IR(), v) case tast.SymImport: t := s.ObjType.(types.T) return newRef(t, nil) } panic(fmt.Errorf("unhandled token type: %s", tast.SymStr(s.Type))) }
func buildPkgSym( b *builder, m *ast.MemberExpr, pkg *types.Pkg, ) (*tast.Ref, *sym8.Symbol) { sym := findPackageSym(b, m.Sub, pkg) if sym == nil { return nil, nil } if pkg.Lang == "asm8" { switch sym.Type { case asm8.SymVar: return tast.NewRef(types.Uint), sym case asm8.SymFunc: return tast.NewRef(types.VoidFunc), sym } b.Errorf(m.Sub.Pos, "invalid symbol %s in %s: %s", m.Sub.Lit, pkg, asm8.SymStr(sym.Type), ) return nil, nil } t := sym.ObjType.(types.T) switch sym.Type { case tast.SymConst, tast.SymStruct, tast.SymFunc: return tast.NewRef(t), sym case tast.SymVar: return tast.NewAddressableRef(t), sym } b.Errorf(m.Sub.Pos, "bug: invalid symbol %s in %s: %s", m.Sub.Lit, pkg, tast.SymStr(sym.Type), ) return nil, nil }
func buildConstIdent(b *builder, id *tast.Ident) *ref { s := id.Symbol switch s.Type { case tast.SymConst: return s.Obj.(*objConst).ref } panic(fmt.Errorf("not a const: %s", tast.SymStr(s.Type))) }
func scopePopAndCheck(b *builder) { tab := b.scope.Pop() syms := tab.List() for _, sym := range syms { if !sym.Used { b.Errorf( sym.Pos, "unused %s %q", tast.SymStr(sym.Type), sym.Name(), ) } } }
func declareVar(b *builder, tok *lex8.Token, t types.T) *sym8.Symbol { name := tok.Lit s := sym8.Make(b.path, name, tast.SymVar, nil, t, tok.Pos) conflict := b.scope.Declare(s) if conflict != nil { b.Errorf(tok.Pos, "%q already defined as a %s", name, tast.SymStr(conflict.Type), ) b.Errorf(conflict.Pos, "previously defined here") return nil } return s }
func declareFuncSym(b *builder, f *ast.Func, t types.T) *sym8.Symbol { name := f.Name.Lit s := sym8.Make(b.path, name, tast.SymFunc, nil, t, f.Name.Pos) conflict := b.scope.Declare(s) if conflict != nil { b.Errorf(f.Name.Pos, "%q already defined as a %s", name, tast.SymStr(conflict.Type), ) b.Errorf(conflict.Pos, "previously defined here") return nil } return s }
func declareStruct(b *builder, s *ast.Struct) *pkgStruct { ret := newPkgStruct(s) name := ret.name.Lit pos := ret.name.Pos t := &types.Type{ret.t} sym := sym8.Make(b.path, name, tast.SymStruct, nil, t, pos) conflict := b.scope.Declare(sym) if conflict != nil { b.Errorf(pos, "%s already defined", name) b.Errorf(conflict.Pos, "previously defined here as a %s", tast.SymStr(conflict.Type), ) return nil } ret.sym = sym return ret }
func buildConstIdent(b *builder, ident *lex8.Token) tast.Expr { s := b.scope.Query(ident.Lit) if s == nil { b.Errorf(ident.Pos, "undefined identifier %s", ident.Lit) return nil } b.refSym(s, ident.Pos) t := s.ObjType.(types.T) switch s.Type { case tast.SymConst: ref := tast.NewRef(t) return &tast.Const{ref} case tast.SymStruct, tast.SymType, tast.SymImport: ref := tast.NewRef(t) return &tast.Ident{ident, ref, s} } b.Errorf(ident.Pos, "%s is a %s; expect a const", ident.Lit, tast.SymStr(s.Type), ) return nil }
func buildMember(b *builder, m *ast.MemberExpr) tast.Expr { obj := b.buildExpr(m.Expr) if obj == nil { return nil } ref := obj.R() if !ref.IsSingle() { b.Errorf(m.Dot.Pos, "%s does not have any member", ref) return nil } t := ref.T if pkg, ok := t.(*types.Pkg); ok { r, sym := buildPkgSym(b, m, pkg) if r == nil { return nil } // TODO: this can be further optimized return &tast.MemberExpr{obj, m.Sub, r, sym} } pt := types.PointerOf(t) var tstruct *types.Struct var ok bool if pt != nil { if tstruct, ok = pt.(*types.Struct); !ok { b.Errorf(m.Dot.Pos, "*%s is not a pointer of struct", t) return nil } } else { if tstruct, ok = t.(*types.Struct); !ok { b.Errorf(m.Dot.Pos, "%s is not a struct", t) return nil } } symTable := tstruct.Syms name := m.Sub.Lit sym := symTable.Query(name) if sym == nil { b.Errorf(m.Sub.Pos, "struct %s has no member named %s", tstruct, name, ) return nil } else if !sym8.IsPublic(name) && sym.Pkg() != b.path { b.Errorf(m.Sub.Pos, "symbol %s is not public", name) return nil } b.refSym(sym, m.Sub.Pos) if sym.Type == tast.SymField { t := sym.ObjType.(types.T) r := tast.NewAddressableRef(t) return &tast.MemberExpr{obj, m.Sub, r, sym} } else if sym.Type == tast.SymFunc { ft := sym.ObjType.(*types.Func) r := tast.NewRef(ft.MethodFunc) r.Recv = ref return &tast.MemberExpr{obj, m.Sub, r, sym} } b.Errorf(m.Sub.Pos, "invalid sym type: %s", tast.SymStr(sym.Type)) return nil }
func buildType(b *builder, expr ast.Expr) types.T { if expr == nil { panic("bug") } switch expr := expr.(type) { case *ast.Operand: ret := buildOperand(b, expr) if ret == nil { return nil } ref := ret.R() t, ok := ref.T.(*types.Type) if !ok { b.Errorf(ast.ExprPos(expr), "expect a type, got %s", ref.T) return nil } return t.T case *ast.StarExpr: t := buildType(b, expr.Expr) if t == nil { return nil } return &types.Pointer{t} case *ast.ArrayTypeExpr: return buildArrayType(b, expr) case *ast.ParenExpr: return buildType(b, expr.Expr) case *ast.FuncTypeExpr: return buildFuncType(b, nil, expr.FuncSig) case *ast.MemberExpr: op, ok := expr.Expr.(*ast.Operand) if !ok { b.Errorf(ast.ExprPos(expr.Expr), "expect a package") return nil } pkg := buildPkgRef(b, op.Token) if pkg == nil { return nil } name := expr.Sub.Lit s := pkg.Syms.Query(name) if s == nil { b.Errorf(expr.Sub.Pos, "symbol %s not found", name) return nil } if !sym8.IsPublic(name) && s.Pkg() != b.path { b.Errorf(expr.Sub.Pos, "symbol %s is not public", name) return nil } if s.Type != tast.SymStruct { b.Errorf(expr.Sub.Pos, "symbol %s is a %s, not a struct", name, tast.SymStr(s.Type), ) return nil } return s.ObjType.(*types.Type).T } b.Errorf(ast.ExprPos(expr), "expect a type") return nil }