From bbf939ce65e580a31c3bfb12a5357bd520f860e6 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sun, 9 Mar 2025 11:55:04 +0800 Subject: [PATCH] parser: shadowEntry --- ast/ast.go | 71 ++---------------------------------------------- ast/ast_gop.go | 69 ++++++++++++++++++++++++++++++++++++++++++++++ parser/parser.go | 21 ++++++++------ 3 files changed, 83 insertions(+), 78 deletions(-) diff --git a/ast/ast.go b/ast/ast.go index e3ee3c9e1..d72576876 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -1079,75 +1079,6 @@ func (*GenDecl) declNode() {} func (*FuncDecl) declNode() {} // ---------------------------------------------------------------------------- -// Files and packages - -type FileType = int16 - -// A File node represents a Go+ source file. -// -// The Comments list contains all comments in the source file in order of -// appearance, including the comments that are pointed to from other nodes -// via Doc and Comment fields. -// -// For correct printing of source code containing comments (using packages -// go/format and go/printer), special care must be taken to update comments -// when a File's syntax tree is modified: For printing, comments are interspersed -// between tokens based on their position. If syntax tree nodes are -// removed or moved, relevant comments in their vicinity must also be removed -// (from the File.Comments list) or moved accordingly (by updating their -// positions). A CommentMap may be used to facilitate some of these operations. -// -// Whether and how a comment is associated with a node depends on the -// interpretation of the syntax tree by the manipulating program: Except for Doc -// and Comment comments directly associated with nodes, the remaining comments -// are "free-floating" (see also issues #18593, #20744). -type File struct { - Doc *CommentGroup // associated documentation; or nil - Package token.Pos // position of "package" keyword; or NoPos - Name *Ident // package name - Decls []Decl // top-level declarations; or nil - - Scope *Scope // package scope (this file only) - Imports []*ImportSpec // imports in this file - Unresolved []*Ident // unresolved identifiers in this file - Comments []*CommentGroup // list of all comments in the source file - Code []byte - ShadowEntry *FuncDecl // no entrypoint func to indicate the module entry point. - NoPkgDecl bool // no `package xxx` declaration - IsClass bool // is a classfile (including normal .gox file) - IsProj bool // is a project classfile - IsNormalGox bool // is a normal .gox file -} - -// There is no entrypoint func to indicate the module entry point. -func (f *File) HasShadowEntry() bool { - return f.ShadowEntry != nil -} - -// HasPkgDecl checks if `package xxx` exists or not. -func (f *File) HasPkgDecl() bool { - return f.Package != token.NoPos -} - -// Pos returns position of first character belonging to the node. -func (f *File) Pos() token.Pos { - if f.Package != token.NoPos { - return f.Package - } - return f.Name.NamePos -} - -// End returns position of first character immediately after the node. -func (f *File) End() token.Pos { - for n := len(f.Decls) - 1; n >= 0; n-- { - d := f.Decls[n] - if fn, ok := d.(*FuncDecl); ok && fn.Shadow && fn != f.ShadowEntry { - continue - } - return d.End() - } - return f.Name.End() -} // A Package node represents a set of source files // collectively building a Go+ package. @@ -1164,3 +1095,5 @@ func (p *Package) Pos() token.Pos { return token.NoPos } // End returns position of first character immediately after the node. func (p *Package) End() token.Pos { return token.NoPos } + +// ---------------------------------------------------------------------------- diff --git a/ast/ast_gop.go b/ast/ast_gop.go index db2148ac4..4800073c9 100644 --- a/ast/ast_gop.go +++ b/ast/ast_gop.go @@ -436,3 +436,72 @@ func (s *SendStmt) End() token.Pos { } // ----------------------------------------------------------------------------- + +// A File node represents a Go+ source file. +// +// The Comments list contains all comments in the source file in order of +// appearance, including the comments that are pointed to from other nodes +// via Doc and Comment fields. +// +// For correct printing of source code containing comments (using packages +// go/format and go/printer), special care must be taken to update comments +// when a File's syntax tree is modified: For printing, comments are interspersed +// between tokens based on their position. If syntax tree nodes are +// removed or moved, relevant comments in their vicinity must also be removed +// (from the File.Comments list) or moved accordingly (by updating their +// positions). A CommentMap may be used to facilitate some of these operations. +// +// Whether and how a comment is associated with a node depends on the +// interpretation of the syntax tree by the manipulating program: Except for Doc +// and Comment comments directly associated with nodes, the remaining comments +// are "free-floating" (see also issues #18593, #20744). +type File struct { + Doc *CommentGroup // associated documentation; or nil + Package token.Pos // position of "package" keyword; or NoPos + Name *Ident // package name + Decls []Decl // top-level declarations; or nil + + Scope *Scope // package scope (this file only) + Imports []*ImportSpec // imports in this file + Unresolved []*Ident // unresolved identifiers in this file + Comments []*CommentGroup // list of all comments in the source file + Code []byte + ShadowEntry *FuncDecl // indicate the module entry point. + NoPkgDecl bool // no `package xxx` declaration + IsClass bool // is a classfile (including normal .gox file) + IsProj bool // is a project classfile + IsNormalGox bool // is a normal .gox file +} + +// There is no entrypoint func to indicate the module entry point. +func (f *File) HasShadowEntry() bool { + return f.ShadowEntry != nil +} + +// HasPkgDecl checks if `package xxx` exists or not. +func (f *File) HasPkgDecl() bool { + return f.Package != token.NoPos +} + +// Pos returns position of first character belonging to the node. +func (f *File) Pos() token.Pos { + if f.Package != token.NoPos { + return f.Package + } + // if no package clause, name records the position of the first token in the file + return f.Name.NamePos +} + +// End returns position of first character immediately after the node. +func (f *File) End() token.Pos { + for n := len(f.Decls) - 1; n >= 0; n-- { + d := f.Decls[n] + if fn, ok := d.(*FuncDecl); ok && fn.Shadow && fn != f.ShadowEntry { + continue + } + return d.End() + } + return f.Name.End() +} + +// ----------------------------------------------------------------------------- diff --git a/parser/parser.go b/parser/parser.go index 7c03fb017..8d232215c 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -50,10 +50,9 @@ type parser struct { scanner scanner.Scanner // Tracing/debugging - mode Mode // parsing mode - trace bool // == (mode & Trace != 0) - shadowEntry *ast.FuncDecl // shadowEntry != nil: no entrypoint func - indent int // indentation used for tracing output + mode Mode // parsing mode + trace bool // == (mode & Trace != 0) + indent int // indentation used for tracing output // Comments comments []*ast.CommentGroup @@ -3975,13 +3974,13 @@ func (p *parser) parseGlobalStmts(sync map[token.Token]bool, pos token.Pos, stmt if stmts != nil { list = append(stmts, list...) } - if p.errors.Len() != 0 { // TODO: error + if p.errors.Len() != 0 { // TODO(xsw): error p.advance(sync) } if p.tok != token.EOF { p.errorExpected(p.pos, "statement", 2) } - f := &ast.FuncDecl{ + return &ast.FuncDecl{ Name: &ast.Ident{NamePos: pos, Name: "main"}, Doc: doc, Type: &ast.FuncType{ @@ -3991,8 +3990,6 @@ func (p *parser) parseGlobalStmts(sync map[token.Token]bool, pos token.Pos, stmt Body: &ast.BlockStmt{List: list}, Shadow: true, } - p.shadowEntry = f - return f } // ---------------------------------------------------------------------------- @@ -4038,6 +4035,7 @@ func (p *parser) parseFile() *ast.File { p.openScope() p.pkgScope = p.topScope var decls []ast.Decl + var shadowEntry *ast.FuncDecl if p.mode&PackageClauseOnly == 0 { // import decls for p.tok == token.IMPORT { @@ -4049,6 +4047,11 @@ func (p *parser) parseFile() *ast.File { for p.tok != token.EOF { decls = append(decls, p.parseDecl(declStart)) } + if n := len(decls); n > 0 { + if f, ok := decls[n-1].(*ast.FuncDecl); ok && f.Shadow { + shadowEntry = f + } + } } } p.closeScope() @@ -4076,7 +4079,7 @@ func (p *parser) parseFile() *ast.File { Imports: p.imports, Unresolved: p.unresolved[0:i], Comments: p.comments, - ShadowEntry: p.shadowEntry, + ShadowEntry: shadowEntry, NoPkgDecl: noPkgDecl, } }