本文整理汇总了Golang中go/ast.Object.Type方法的典型用法代码示例。如果您正苦于以下问题:Golang Object.Type方法的具体用法?Golang Object.Type怎么用?Golang Object.Type使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类go/ast.Object
的用法示例。
在下文中一共展示了Object.Type方法的13个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Golang代码示例。
示例1: resolve
func (tc *typechecker) resolve(obj *ast.Object) {
// check for declaration cycles
if tc.cyclemap[obj] {
tc.Errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name)
obj.Kind = ast.Bad
return
}
tc.cyclemap[obj] = true
defer func() {
tc.cyclemap[obj] = false, false
}()
// resolve non-type objects
typ, _ := obj.Type.(*Type)
if typ == nil {
switch obj.Kind {
case ast.Bad:
// ignore
case ast.Con:
tc.declConst(obj)
case ast.Var:
tc.declVar(obj)
obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)
case ast.Fun:
obj.Type = NewType(Function)
t := obj.Decl.(*ast.FuncDecl).Type
tc.declSignature(obj.Type.(*Type), nil, t.Params, t.Results)
default:
// type objects have non-nil types when resolve is called
if debug {
fmt.Printf("kind = %s\n", obj.Kind)
}
panic("unreachable")
}
return
}
// resolve type objects
if typ.Form == Unresolved {
tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false)
// provide types for all methods
for _, obj := range typ.Scope.Objects {
if obj.Kind == ast.Fun {
assert(obj.Type == nil)
obj.Type = NewType(Method)
f := obj.Decl.(*ast.FuncDecl)
t := f.Type
tc.declSignature(obj.Type.(*Type), f.Recv, t.Params, t.Results)
}
}
}
}
示例2: checkObj
// checkObj type checks an object.
func (c *checker) checkObj(obj *ast.Object, ref bool) {
if obj.Type != nil {
// object has already been type checked
return
}
switch obj.Kind {
case ast.Bad:
// ignore
case ast.Con:
// TODO(gri) complete this
case ast.Typ:
typ := &Name{Obj: obj}
obj.Type = typ // "mark" object so recursion terminates
typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref))
case ast.Var:
// TODO(gri) complete this
case ast.Fun:
// TODO(gri) complete this
default:
panic("unreachable")
}
}
示例3: checkObj
// checkObj type checks an object.
func (c *checker) checkObj(obj *ast.Object, ref bool) {
if obj.Type != nil {
// object has already been type checked
return
}
switch obj.Kind {
case ast.Bad:
// ignore
case ast.Con:
// TODO(gri) complete this
case ast.Typ:
typ := &Name{Obj: obj}
obj.Type = typ // "mark" object so recursion terminates
typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref))
case ast.Var:
// TODO(gri) complete this
case ast.Fun:
fdecl := obj.Decl.(*ast.FuncDecl)
ftyp := c.makeType(fdecl.Type, ref).(*Func)
obj.Type = ftyp
if fdecl.Recv != nil {
recvField := fdecl.Recv.List[0]
if len(recvField.Names) > 0 {
ftyp.Recv = recvField.Names[0].Obj
} else {
ftyp.Recv = ast.NewObj(ast.Var, "_")
ftyp.Recv.Decl = recvField
}
c.checkObj(ftyp.Recv, ref)
// TODO(axw) add method to a list in the receiver type.
}
// TODO(axw) check function body, if non-nil.
default:
panic("unreachable")
}
}
示例4: valueSpec
func (check *checker) valueSpec(pos token.Pos, obj *ast.Object, lhs []*ast.Ident, typ ast.Expr, rhs []ast.Expr, iota int) {
if len(lhs) == 0 {
check.invalidAST(pos, "missing lhs in declaration")
return
}
// determine type for all of lhs, if any
// (but only set it for the object we typecheck!)
var t Type
if typ != nil {
t = check.typ(typ, false)
}
// len(lhs) > 0
if len(lhs) == len(rhs) {
// check only lhs and rhs corresponding to obj
var l, r ast.Expr
for i, name := range lhs {
if name.Obj == obj {
l = lhs[i]
r = rhs[i]
break
}
}
assert(l != nil)
obj.Type = t
check.assign1to1(l, r, nil, true, iota)
return
}
// there must be a type or initialization expressions
if t == nil && len(rhs) == 0 {
check.invalidAST(pos, "missing type or initialization expression")
t = Typ[Invalid]
}
// if we have a type, mark all of lhs
if t != nil {
for _, name := range lhs {
name.Obj.Type = t
}
}
// check initial values, if any
if len(rhs) > 0 {
// TODO(gri) should try to avoid this conversion
lhx := make([]ast.Expr, len(lhs))
for i, e := range lhs {
lhx[i] = e
}
check.assignNtoM(lhx, rhs, true, iota)
}
}
示例5: valueSpec
func (check *checker) valueSpec(pos token.Pos, obj *ast.Object, lhs []*ast.Ident, typ ast.Expr, rhs []ast.Expr, iota int) {
if len(lhs) == 0 {
check.invalidAST(pos, "missing lhs in declaration")
return
}
var t Type
if typ != nil {
t = check.typ(typ, false)
}
// len(lhs) >= 1
if len(lhs) == len(rhs) {
// check only corresponding lhs and rhs
var l, r ast.Expr
for i, ident := range lhs {
if ident.Obj == obj {
l = lhs[i]
r = rhs[i]
break
}
}
assert(l != nil)
obj.Type = t
// check rhs
var x operand
check.expr(&x, r, t, iota)
// assign to lhs
check.assignment(l, &x, true)
return
}
if t != nil {
for _, name := range lhs {
name.Obj.Type = t
}
}
// check initial values, if any
if len(rhs) > 0 {
// TODO(gri) should try to avoid this conversion
lhx := make([]ast.Expr, len(lhs))
for i, e := range lhs {
lhx[i] = e
}
check.assignNtoM(lhx, rhs, true, iota)
}
}
示例6: collectParams
func (check *checker) collectParams(list *ast.FieldList, variadicOk bool) (params ObjList, isVariadic bool) {
if list == nil {
return
}
var last *ast.Object
for i, field := range list.List {
ftype := field.Type
if t, _ := ftype.(*ast.Ellipsis); t != nil {
ftype = t.Elt
if variadicOk && i == len(list.List)-1 {
isVariadic = true
} else {
check.invalidAST(field.Pos(), "... not permitted")
// ok to continue
}
}
// the parser ensures that f.Tag is nil and we don't
// care if a constructed AST contains a non-nil tag
typ := check.typ(ftype, true)
if len(field.Names) > 0 {
// named parameter
for _, name := range field.Names {
obj := name.Obj
obj.Type = typ
params = append(params, obj)
last = obj
}
} else {
// anonymous parameter
obj := ast.NewObj(ast.Var, "")
obj.Type = typ
params = append(params, obj)
last = obj
}
}
// For a variadic function, change the last parameter's object type
// from T to []T (this is the type used inside the function), but
// keep a copy of the object with the original type T in the params
// list (this is the externally visible type).
if isVariadic {
// if isVariadic is set, last must exist and len(params) > 0
copy := *last
last.Type = &Slice{Elt: last.Type.(Type)}
params[len(params)-1] = ©
}
return
}
示例7: maybeConvertUntyped
// convertUntyped takes an object, and, if it is untyped, gives it
// a named builtin type: bool, rune, int, float64, complex128 or string.
func maybeConvertUntyped(obj *ast.Object) bool {
switch obj.Type {
case Bool.Underlying:
obj.Type = Bool
case Rune.Underlying:
obj.Type = Rune
case Int.Underlying:
obj.Type = Int
case Float64.Underlying:
obj.Type = Float64
case Complex128.Underlying:
obj.Type = Complex128
case String.Underlying:
obj.Type = String
default:
return false
}
return true
}
示例8: object
// object typechecks an object by assigning it a type; obj.Type must be nil.
// Callers must check obj.Type before calling object; this eliminates a call
// for each identifier that has been typechecked already, a common scenario.
//
func (check *checker) object(obj *ast.Object, cycleOk bool) {
assert(obj.Type == nil)
switch obj.Kind {
case ast.Bad, ast.Pkg:
// nothing to do
case ast.Con, ast.Var:
// The obj.Data field for constants and variables is initialized
// to the respective (hypothetical, for variables) iota value by
// the parser. The object's fields can be in one of the following
// states:
// Type != nil => the constant value is Data
// Type == nil => the object is not typechecked yet, and Data can be:
// Data is int => Data is the value of iota for this declaration
// Data == nil => the object's expression is being evaluated
if obj.Data == nil {
check.errorf(obj.Pos(), "illegal cycle in initialization of %s", obj.Name)
obj.Type = Typ[Invalid]
return
}
spec := obj.Decl.(*ast.ValueSpec)
iota := obj.Data.(int)
obj.Data = nil
// determine initialization expressions
values := spec.Values
if len(values) == 0 && obj.Kind == ast.Con {
values = check.initexprs[spec]
}
check.valueSpec(spec.Pos(), obj, spec.Names, spec.Type, values, iota)
case ast.Typ:
typ := &NamedType{Obj: obj}
obj.Type = typ // "mark" object so recursion terminates
typ.Underlying = underlying(check.typ(obj.Decl.(*ast.TypeSpec).Type, cycleOk))
// typecheck associated method signatures
if obj.Data != nil {
scope := obj.Data.(*ast.Scope)
switch t := typ.Underlying.(type) {
case *Struct:
// struct fields must not conflict with methods
for _, f := range t.Fields {
if m := scope.Lookup(f.Name); m != nil {
check.errorf(m.Pos(), "type %s has both field and method named %s", obj.Name, f.Name)
// ok to continue
}
}
case *Interface:
// methods cannot be associated with an interface type
for _, m := range scope.Objects {
recv := m.Decl.(*ast.FuncDecl).Recv.List[0].Type
check.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
// ok to continue
}
}
// typecheck method signatures
for _, obj := range scope.Objects {
mdecl := obj.Decl.(*ast.FuncDecl)
sig := check.typ(mdecl.Type, cycleOk).(*Signature)
params, _ := check.collectParams(mdecl.Recv, false)
sig.Recv = params[0] // the parser/assocMethod ensure there is exactly one parameter
obj.Type = sig
check.later(obj, sig, mdecl.Body)
}
}
case ast.Fun:
fdecl := obj.Decl.(*ast.FuncDecl)
// methods are typechecked when their receivers are typechecked
if fdecl.Recv == nil {
sig := check.typ(fdecl.Type, cycleOk).(*Signature)
if obj.Name == "init" && (len(sig.Params) != 0 || len(sig.Results) != 0) {
check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
// ok to continue
}
obj.Type = sig
check.later(obj, sig, fdecl.Body)
}
default:
panic("unreachable")
}
}
示例9: object
// object typechecks an object by assigning it a type; obj.Type must be nil.
// Callers must check obj.Type before calling object; this eliminates a call
// for each identifier that has been typechecked already, a common scenario.
//
func (check *checker) object(obj *ast.Object, cycleOk bool) {
assert(obj.Type == nil)
switch obj.Kind {
case ast.Bad, ast.Pkg:
// nothing to do
case ast.Con, ast.Var:
// The obj.Data field for constants and variables is initialized
// to the respective (hypothetical, for variables) iota value by
// the parser. The object's fields can be in one of the following
// states:
// Type != nil => the constant value is Data
// Type == nil => the object is not typechecked yet, and Data can be:
// Data is int => Data is the value of iota for this declaration
// Data == nil => the object's expression is being evaluated
if obj.Data == nil {
check.errorf(obj.Pos(), "illegal cycle in initialization of %s", obj.Name)
obj.Type = Typ[Invalid]
return
}
spec := obj.Decl.(*ast.ValueSpec)
iota := obj.Data.(int)
obj.Data = nil
// determine initialization expressions
values := spec.Values
if len(values) == 0 && obj.Kind == ast.Con {
values = check.initexprs[spec]
}
check.valueSpec(spec.Pos(), obj, spec.Names, spec.Type, values, iota)
case ast.Typ:
typ := &NamedType{Obj: obj}
obj.Type = typ // "mark" object so recursion terminates
typ.Underlying = underlying(check.typ(obj.Decl.(*ast.TypeSpec).Type, cycleOk))
// typecheck associated method signatures
if obj.Data != nil {
scope := obj.Data.(*ast.Scope)
switch t := typ.Underlying.(type) {
case *Struct:
// struct fields must not conflict with methods
for _, f := range t.Fields {
if m := scope.Lookup(f.Name); m != nil {
check.errorf(m.Pos(), "type %s has both field and method named %s", obj.Name, f.Name)
}
}
// ok to continue
case *Interface:
// methods cannot be associated with an interface type
for _, m := range scope.Objects {
recv := m.Decl.(*ast.FuncDecl).Recv.List[0].Type
check.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
}
// ok to continue
}
// typecheck method signatures
for _, m := range scope.Objects {
mdecl := m.Decl.(*ast.FuncDecl)
// TODO(gri) At the moment, the receiver is type-checked when checking
// the method body. Also, we don't properly track if the receiver is
// a pointer (i.e., currently, method sets are too large). FIX THIS.
mtyp := check.typ(mdecl.Type, cycleOk).(*Signature)
m.Type = mtyp
}
}
case ast.Fun:
fdecl := obj.Decl.(*ast.FuncDecl)
if fdecl.Recv != nil {
// This will ensure that the method base type is
// type-checked
check.collectFields(token.FUNC, fdecl.Recv, true)
}
ftyp := check.typ(fdecl.Type, cycleOk).(*Signature)
obj.Type = ftyp
check.function(ftyp, fdecl.Body)
default:
panic("unreachable")
}
}
示例10: stmt
//.........这里部分代码省略.........
check.expr(&x, s.Cond, nil, -1)
if !isBoolean(x.typ) {
check.errorf(s.Cond.Pos(), "non-boolean condition in if statement")
}
check.stmt(s.Body)
check.optionalStmt(s.Else)
case *ast.SwitchStmt:
check.optionalStmt(s.Init)
var x operand
if s.Tag != nil {
check.expr(&x, s.Tag, nil, -1)
} else {
// TODO(gri) should provide a position (see IncDec) for good error messages
x.mode = constant
x.typ = Typ[UntypedBool]
x.val = true
}
check.multipleDefaults(s.Body.List)
for _, s := range s.Body.List {
clause, _ := s.(*ast.CaseClause)
if clause == nil {
continue // error reported before
}
for _, expr := range clause.List {
var y operand
check.expr(&y, expr, nil, -1)
// TODO(gri) x and y must be comparable
}
check.stmtList(clause.Body)
}
case *ast.TypeSwitchStmt:
check.optionalStmt(s.Init)
// A type switch guard must be of the form:
//
// TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
//
// The parser is checking syntactic correctness;
// remaining syntactic errors are considered AST errors here.
// TODO(gri) better factoring of error handling (invalid ASTs)
//
var lhs *ast.Object // lhs identifier object or nil
var rhs ast.Expr
switch guard := s.Assign.(type) {
case *ast.ExprStmt:
rhs = guard.X
case *ast.AssignStmt:
if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
check.invalidAST(s.Pos(), "incorrect form of type switch guard")
return
}
ident, _ := guard.Lhs[0].(*ast.Ident)
if ident == nil {
check.invalidAST(s.Pos(), "incorrect form of type switch guard")
return
}
lhs = ident.Obj
rhs = guard.Rhs[0]
default:
check.invalidAST(s.Pos(), "incorrect form of type switch guard")
return
}
示例11: checkObj
// checkObj type checks an object.
func (c *checker) checkObj(obj *ast.Object, ref bool) {
if obj.Type != nil {
// object has already been type checked
return
}
switch obj.Kind {
case ast.Bad:
// ignore
case ast.Con:
valspec := obj.Decl.(*ast.ValueSpec)
if valspec.Type != nil {
obj.Type = c.makeType(valspec.Type, ref)
for _, name := range valspec.Names {
name.Obj.Type = obj.Type
}
}
if valspec.Values != nil {
oldData := Iota.Data
for i, name := range valspec.Names {
if name.Obj != nil {
c.checkExpr(valspec.Values[i], []*ast.Ident{name})
iotaValue := name.Obj.Data.(int)
Iota.Data = Const{big.NewInt(int64(iotaValue))}
constValue := c.evalConst(valspec.Values[i])
typ := name.Obj.Type.(Type)
name.Obj.Data = constValue.Convert(&typ)
} else {
c.checkExpr(valspec.Values[i], nil)
}
}
if oldData != nil {
Iota.Data = oldData
}
}
case ast.Typ:
typ := &Name{Package: c.pkgid, Obj: obj}
obj.Type = typ // "mark" object so recursion terminates
typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref))
if methobjs := c.methods[obj]; methobjs != nil {
methobjs.Sort()
typ.Methods = methobjs
// Check for instances of field and method with same name.
if s, ok := typ.Underlying.(*Struct); ok {
for _, m := range methobjs {
if _, ok := s.FieldIndices[m.Name]; ok {
c.errorf(m.Pos(), "type %s has both field and method named %s", obj.Name, m.Name)
}
}
}
// methods cannot be associated with an interface type
// (do this check after sorting for reproducible error positions - needed for testing)
if _, ok := typ.Underlying.(*Interface); ok {
for _, m := range methobjs {
recv := m.Decl.(*ast.FuncDecl).Recv.List[0].Type
c.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
}
}
}
for _, m := range typ.Methods {
c.checkObj(m, ref)
}
case ast.Var:
var names []*ast.Ident
var values []ast.Expr
var typexpr ast.Expr
switch x := obj.Decl.(type) {
case *ast.ValueSpec:
names = x.Names
values = x.Values
typexpr = x.Type
case *ast.Field:
names = x.Names
typexpr = x.Type
case *ast.AssignStmt:
c.checkStmt(x)
if obj.Type == nil {
panic("obj.Type == nil")
}
default:
panic(fmt.Sprintf("unimplemented (%T)", x))
}
if names != nil { // nil for anonymous field
var typ Type
if typexpr != nil {
typ = c.makeType(typexpr, ref)
for i, name := range names {
if name.Obj != nil {
name.Obj.Type = typ
} else {
names[i] = nil
}
}
}
//.........这里部分代码省略.........
示例12: obj
// obj type checks an object.
func (check *checker) obj(obj *ast.Object, cycleOk bool) {
if trace {
fmt.Printf("obj(%s)\n", obj.Name)
}
if obj.Type != nil {
// object has already been type checked
return
}
switch obj.Kind {
case ast.Bad, ast.Pkg:
// nothing to do
case ast.Con:
if obj.Data == nil {
check.errorf(obj.Pos(), "illegal cycle in initialization of %s", obj.Name)
return
}
spec, ok := obj.Decl.(*ast.ValueSpec)
assert(ok)
// The Data stored with the constant is the value of iota for that
// ast.ValueSpec. Use it for the evaluation of the initialization
// expressions.
iota := obj.Data.(int)
obj.Data = nil
check.decl(spec.Pos(), obj, spec.Names, spec.Type, check.specValues(spec), iota)
case ast.Var:
// TODO(gri) missing cycle detection
spec, ok := obj.Decl.(*ast.ValueSpec)
if !ok {
// TODO(gri) the assertion fails for "x, y := 1, 2, 3" it seems
fmt.Printf("var = %s\n", obj.Name)
}
assert(ok)
check.decl(spec.Pos(), obj, spec.Names, spec.Type, spec.Values, 0)
case ast.Typ:
typ := &NamedType{Obj: obj}
obj.Type = typ // "mark" object so recursion terminates
typ.Underlying = underlying(check.typ(obj.Decl.(*ast.TypeSpec).Type, cycleOk))
// collect associated methods, if any
if obj.Data != nil {
scope := obj.Data.(*ast.Scope)
// struct fields must not conflict with methods
if t, ok := typ.Underlying.(*Struct); ok {
for _, f := range t.Fields {
if m := scope.Lookup(f.Name); m != nil {
check.errorf(m.Pos(), "type %s has both field and method named %s", obj.Name, f.Name)
}
}
}
// collect methods
methods := make(ObjList, len(scope.Objects))
i := 0
for _, m := range scope.Objects {
methods[i] = m
i++
}
methods.Sort()
typ.Methods = methods
// methods cannot be associated with an interface type
// (do this check after sorting for reproducible error positions - needed for testing)
if _, ok := typ.Underlying.(*Interface); ok {
for _, m := range methods {
recv := m.Decl.(*ast.FuncDecl).Recv.List[0].Type
check.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
}
}
}
case ast.Fun:
fdecl := obj.Decl.(*ast.FuncDecl)
ftyp := check.typ(fdecl.Type, cycleOk).(*Signature)
obj.Type = ftyp
if fdecl.Recv != nil {
// TODO(gri) handle method receiver
}
check.stmt(fdecl.Body)
default:
panic("unreachable")
}
}
示例13: checkObj
// checkObj type checks an object.
func (c *checker) checkObj(obj *ast.Object, ref bool) {
if obj.Type != nil {
// object has already been type checked
return
}
switch obj.Kind {
case ast.Bad:
// ignore
case ast.Con:
valspec := obj.Decl.(*ast.ValueSpec)
if valspec.Type != nil {
obj.Type = c.makeType(valspec.Type, ref)
for _, name := range valspec.Names {
name.Obj.Type = obj.Type
}
}
if valspec.Values != nil {
for i, name := range valspec.Names {
if name.Obj != nil {
c.checkExpr(valspec.Values[i], []*ast.Ident{name})
} else {
c.checkExpr(valspec.Values[i], nil)
}
}
}
case ast.Typ:
typ := &Name{Obj: obj}
obj.Type = typ // "mark" object so recursion terminates
if methobjs := c.methods[obj]; methobjs != nil {
methobjs.Sort()
typ.Methods = methobjs
}
typ.Underlying = Underlying(c.makeType(obj.Decl.(*ast.TypeSpec).Type, ref))
for _, m := range typ.Methods {
c.checkObj(m, ref)
}
case ast.Var:
var names []*ast.Ident
var values []ast.Expr
var typexpr ast.Expr
switch x := obj.Decl.(type) {
case *ast.ValueSpec:
names = x.Names
values = x.Values
typexpr = x.Type
case *ast.Field:
names = x.Names
typexpr = x.Type
case *ast.AssignStmt:
c.checkStmt(x)
if obj.Type == nil {
panic("obj.Type == nil")
}
default:
panic(fmt.Sprintf("unimplemented (%T)", x))
}
if names != nil { // nil for anonymous field
var typ Type
if typexpr != nil {
typ = c.makeType(typexpr, ref)
for i, name := range names {
if name.Obj != nil {
name.Obj.Type = typ
} else {
names[i] = nil
}
}
}
if len(values) == 1 && len(names) > 1 {
// multi-value assignment
c.checkExpr(values[0], names)
} else if len(values) == len(names) {
for i, name := range names {
if name.Obj != nil {
c.checkExpr(values[i], []*ast.Ident{name})
} else {
c.checkExpr(values[i], nil)
}
}
}
}
case ast.Fun:
fndecl := obj.Decl.(*ast.FuncDecl)
obj.Type = c.makeType(fndecl.Type, ref)
fn := obj.Type.(*Func)
if fndecl.Recv != nil {
recvField := fndecl.Recv.List[0]
if len(recvField.Names) > 0 {
fn.Recv = recvField.Names[0].Obj
} else {
fn.Recv = ast.NewObj(ast.Var, "_")
fn.Recv.Decl = recvField
}
c.checkObj(fn.Recv, ref)
//.........这里部分代码省略.........