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 }