Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parser: shadowEntry #2163

Merged
merged 1 commit into from
Mar 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 2 additions & 69 deletions ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 }

// ----------------------------------------------------------------------------
69 changes: 69 additions & 0 deletions ast/ast_gop.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

// -----------------------------------------------------------------------------
21 changes: 12 additions & 9 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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{
Expand All @@ -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
}

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -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 {
Expand All @@ -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()
Expand Down Expand Up @@ -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,
}
}
Loading