github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/internal/compiler/parser/parser.go (about)

     1  // Package parser implements source code parsing.
     2  // It uses parser (and lexer) generated by ANTLR4 from neva.g4 grammar file.
     3  package parser
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  	"runtime/debug"
     9  
    10  	"github.com/antlr4-go/antlr/v4"
    11  
    12  	"github.com/nevalang/neva/internal/compiler"
    13  	generated "github.com/nevalang/neva/internal/compiler/parser/generated"
    14  	src "github.com/nevalang/neva/internal/compiler/sourcecode"
    15  )
    16  
    17  type treeShapeListener struct {
    18  	*generated.BasenevaListener
    19  	file src.File
    20  	loc  src.Location
    21  }
    22  
    23  type Parser struct {
    24  	isDebug bool
    25  }
    26  
    27  func (p Parser) ParseModules(
    28  	rawMods map[src.ModuleRef]compiler.RawModule,
    29  ) (map[src.ModuleRef]src.Module, *compiler.Error) {
    30  	parsedMods := make(map[src.ModuleRef]src.Module, len(rawMods))
    31  
    32  	for modRef, rawMod := range rawMods {
    33  		parsedPkgs, err := p.ParsePackages(modRef, rawMod.Packages)
    34  		if err != nil {
    35  			return nil, compiler.Error{
    36  				Err:      errors.New("Parsing error"),
    37  				Location: &src.Location{ModRef: modRef},
    38  			}.Wrap(err)
    39  		}
    40  
    41  		parsedMods[modRef] = src.Module{
    42  			Manifest: rawMod.Manifest,
    43  			Packages: parsedPkgs,
    44  		}
    45  	}
    46  
    47  	return parsedMods, nil
    48  }
    49  
    50  func (p Parser) ParsePackages(
    51  	modRef src.ModuleRef,
    52  	rawPkgs map[string]compiler.RawPackage,
    53  ) (
    54  	map[string]src.Package,
    55  	*compiler.Error,
    56  ) {
    57  	packages := make(map[string]src.Package, len(rawPkgs))
    58  
    59  	for pkgName, pkgFiles := range rawPkgs {
    60  		parsedFiles, err := p.ParseFiles(modRef, pkgName, pkgFiles)
    61  		if err != nil {
    62  			return nil, compiler.Error{
    63  				Location: &src.Location{PkgName: pkgName},
    64  			}.Wrap(err)
    65  		}
    66  
    67  		packages[pkgName] = parsedFiles
    68  	}
    69  
    70  	return packages, nil
    71  }
    72  
    73  func (p Parser) ParseFiles(
    74  	modRef src.ModuleRef,
    75  	pkgName string,
    76  	files map[string][]byte,
    77  ) (map[string]src.File, *compiler.Error) {
    78  	result := make(map[string]src.File, len(files))
    79  
    80  	for fileName, fileBytes := range files {
    81  		loc := src.Location{
    82  			ModRef:   modRef,
    83  			PkgName:  pkgName,
    84  			FileName: fileName,
    85  		}
    86  		parsedFile, err := p.parseFile(loc, fileBytes)
    87  		if err != nil {
    88  			return nil, compiler.Error{Location: &loc}.Wrap(err)
    89  		}
    90  		result[fileName] = parsedFile
    91  	}
    92  
    93  	return result, nil
    94  }
    95  
    96  func (p Parser) parseFile(
    97  	loc src.Location,
    98  	bb []byte,
    99  ) (f src.File, err *compiler.Error) {
   100  	defer func() {
   101  		if e := recover(); e != nil {
   102  			compilerErr, ok := e.(*compiler.Error)
   103  			if ok {
   104  				err = compiler.Error{Location: &loc}.Wrap(compilerErr)
   105  				return
   106  			}
   107  			err = &compiler.Error{
   108  				Err: fmt.Errorf(
   109  					"%v: %v",
   110  					e,
   111  					string(debug.Stack()),
   112  				),
   113  				Location: &loc,
   114  			}
   115  		}
   116  	}()
   117  
   118  	input := antlr.NewInputStream(string(bb))
   119  	lexer := generated.NewnevaLexer(input)
   120  	lexerErrors := &CustomErrorListener{}
   121  	lexer.RemoveErrorListeners()
   122  	lexer.AddErrorListener(lexerErrors)
   123  	tokenStream := antlr.NewCommonTokenStream(lexer, 0)
   124  
   125  	parserErrors := &CustomErrorListener{}
   126  	prsr := generated.NewnevaParser(tokenStream)
   127  	prsr.RemoveErrorListeners()
   128  	prsr.AddErrorListener(parserErrors)
   129  	if p.isDebug {
   130  		prsr.AddErrorListener(antlr.NewDiagnosticErrorListener(true))
   131  	}
   132  	prsr.BuildParseTrees = true
   133  
   134  	tree := prsr.Prog()
   135  	listener := &treeShapeListener{loc: loc}
   136  
   137  	antlr.ParseTreeWalkerDefault.Walk(listener, tree)
   138  
   139  	if len(lexerErrors.Errors) > 0 {
   140  		return src.File{}, &compiler.Error{
   141  			Err: lexerErrors.Errors[0],
   142  		}
   143  	}
   144  
   145  	if len(parserErrors.Errors) > 0 {
   146  		return src.File{}, &compiler.Error{
   147  			Err: parserErrors.Errors[0],
   148  		}
   149  	}
   150  
   151  	return listener.file, nil
   152  }
   153  
   154  func New(isDebug bool) Parser {
   155  	return Parser{isDebug: isDebug}
   156  }