github.com/yunabe/lgo@v0.0.0-20190709125917-42c42d410fdf/parser/custom.go (about)

     1  package parser
     2  
     3  import (
     4  	"go/ast"
     5  	"go/token"
     6  )
     7  
     8  type LGOBlock struct {
     9  	Scope      *ast.Scope          // package scope (this file only)
    10  	Imports    []*ast.ImportSpec   // imports in this file
    11  	Unresolved []*ast.Ident        // unresolved identifiers in this file
    12  	Comments   []*ast.CommentGroup // list of all comments in the source file
    13  	Stmts      []ast.Stmt
    14  }
    15  
    16  func (p *parser) parseLgoStmtList() (list []ast.Stmt) {
    17  	if p.trace {
    18  		defer un(trace(p, "LgoStatementList"))
    19  	}
    20  
    21  	for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF {
    22  		list = append(list, p.parseStmtWithFuncDeclImport(true, true))
    23  	}
    24  
    25  	return
    26  }
    27  
    28  func (p *parser) parseLesserGoSrc() *LGOBlock {
    29  	// Extended from parseFile
    30  	if p.trace {
    31  		defer un(trace(p, "File"))
    32  	}
    33  
    34  	// Don't bother parsing the rest if we had errors scanning the first token.
    35  	// Likely not a Go source file at all.
    36  	if p.errors.Len() != 0 {
    37  		return nil
    38  	}
    39  
    40  	p.openScope()
    41  	// We need to open/close a label-scope to support label in the top-level scope.
    42  	p.openLabelScope()
    43  	p.pkgScope = p.topScope
    44  	// rest of package body
    45  	stmts := p.parseLgoStmtList()
    46  	p.closeLabelScope()
    47  	p.closeScope()
    48  	assert(p.topScope == nil, "unbalanced scopes")
    49  	assert(p.labelScope == nil, "unbalanced label scopes")
    50  
    51  	// resolve global identifiers within the same file
    52  	i := 0
    53  	for _, ident := range p.unresolved {
    54  		// i <= index for current ident
    55  		assert(ident.Obj == unresolved, "object already resolved")
    56  		ident.Obj = p.pkgScope.Lookup(ident.Name) // also removes unresolved sentinel
    57  		if ident.Obj == nil {
    58  			p.unresolved[i] = ident
    59  			i++
    60  		}
    61  	}
    62  
    63  	return &LGOBlock{
    64  		// Package:    pos,
    65  		// Name:       ident,
    66  		// Decls:      decls,
    67  		Stmts:      stmts,
    68  		Scope:      p.pkgScope,
    69  		Imports:    p.imports,
    70  		Unresolved: p.unresolved[0:i],
    71  		Comments:   p.comments,
    72  	}
    73  }
    74  
    75  func ParseLesserGoFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (f *LGOBlock, err error) {
    76  	if fset == nil {
    77  		panic("parser.ParseFile: no token.FileSet provided (fset == nil)")
    78  	}
    79  
    80  	// get source
    81  	text, err := readSource(filename, src)
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	var p parser
    87  	defer func() {
    88  		if e := recover(); e != nil {
    89  			// resume same panic if it's not a bailout
    90  			if _, ok := e.(bailout); !ok {
    91  				panic(e)
    92  			}
    93  		}
    94  
    95  		// set result values
    96  		if f == nil {
    97  			// source is not a valid Go source file - satisfy
    98  			// ParseFile API and return a valid (but) empty
    99  			// *ast.File
   100  			f = &LGOBlock{
   101  				// Name:  new(ast.Ident),
   102  				Scope: ast.NewScope(nil),
   103  			}
   104  		}
   105  
   106  		p.errors.Sort()
   107  		err = p.errors.Err()
   108  	}()
   109  
   110  	// parse source
   111  	p.init(fset, filename, text, mode)
   112  	f = p.parseLesserGoSrc()
   113  
   114  	return
   115  }