z_mirror/luapls
git clone https://git.raiguard.me/z_mirror/luapls
5c64afc
main
1// Package Parser implements a recursive descent parser for Lua 5.2. It is 2// heavily based on "Writing an Interpreter in Go" by Thorston Ball. 3// https://interpreterbook.com/ 4 5// Error recovery: https://supunsetunga.medium.com/writing-a-parser-syntax-error-handling-b71b67a8ac66 6 7package parser 8 9import ( 10"fmt" 11"strings" 12 13"github.com/raiguard/luapls/lua/ast" 14"github.com/raiguard/luapls/lua/lexer" 15"github.com/raiguard/luapls/lua/token" 16"github.com/raiguard/luapls/util" 17 protocol"github.com/tliron/glsp/protocol_3_16" 18) 19 20type Parser struct { 21errors []ast.Diagnostic 22lineBreaks []int 23units []ast.Unit 24pos int 25} 26 27func New (input string )* Parser { 28units ,lineBreaks := Run (input ) 29p := & Parser { 30errors : []ast.Diagnostic {}, 31lineBreaks :lineBreaks , 32units :units , 33 } 34 35return p 36} 37 38func Run (input string ) ([]ast.Unit , []int ) { 39// Consume all tokens and convert them into units 40tokens ,lineBreaks := lexer .Run (input ) 41units := []ast.Unit {} 42u := ast.Unit { 43LeadingTrivia : []token.Token {}, 44Token : token.Token {}, 45TrailingTrivia : []token.Token {}, 46 } 47state := "leading" 48newUnit := func () { 49units = append (units ,u ) 50u = ast.Unit { 51LeadingTrivia : []token.Token {}, 52Token : token.Token {}, 53TrailingTrivia : []token.Token {}, 54 } 55 } 56for _ ,tok := range tokens { 57if tok .Type == token .COMMENT || tok .Type == token .WHITESPACE { 58if state == "leading" { 59u .LeadingTrivia = append (u .LeadingTrivia ,tok ) 60 }else { 61u .TrailingTrivia = append (u .TrailingTrivia ,tok ) 62if strings .Contains (tok .Literal ,"\n" ) { 63newUnit () 64state = "leading" 65 } 66 } 67 }else { 68if state == "leading" { 69state = "trailing" 70u .Token = tok 71 }else { 72newUnit () 73u .Token = tok 74 } 75 } 76 } 77newUnit () 78 79return units ,lineBreaks 80} 81 82func (p * Parser )Errors () []ast.Diagnostic { 83return p .errors 84} 85 86func (p * Parser )ParseFile () ast.File { 87return ast.File { 88Block :util .Ptr (p .parseBlock ()), 89Diagnostics :p .errors , 90LineBreaks :p .lineBreaks , 91 } 92} 93 94func (p * Parser )unit ()* ast.Unit { 95return & p .units [p .pos ] 96} 97 98func (p * Parser )next () ast.Unit { 99if p .pos < len (p .units )- 1 { 100p .pos ++ 101 } 102return p .units [p .pos ] 103} 104 105func (p * Parser )parseBlock () ast.Block { 106block := ast.Block {StartPos :p .unit ().Pos ()} 107 108for { 109if blockEnd [p .unit ().Type ()] { 110break 111 } 112pair := ast.Pair [ast.Statement ]{Node :p .parseStatement ()} 113if p .tokIs (token .SEMICOLON ) { 114pair .Delimeter = p .unit () 115p .next () 116 } 117block .Pairs = append (block .Pairs ,pair ) 118 } 119 120return block 121} 122 123func (p * Parser )parseFunctionCall (name ast.Expression )* ast.FunctionCall { 124fc := & ast.FunctionCall {Name :name } 125if p .tokIs (token .STRING ) { 126fc .Args = ast.SimplePunctuated [ast.Expression ](p .parseStringLiteral ()) 127return fc 128 } 129if p .tokIs (token .RAWSTRING ) { 130fc .Args = ast.SimplePunctuated [ast.Expression ](p .parseRawStringLiteral ()) 131return fc 132 } 133 134if p .tokIs (token .LBRACE ) { 135fc .Args = ast.SimplePunctuated [ast.Expression ](p .parseTableLiteral ()) 136return fc 137 } 138 139fc .LeftParen = util .Ptr (p .expect (token .LPAREN )) 140 141if rparen := p .accept (token .RPAREN );rparen != nil { 142fc .RightParen = rparen 143return fc 144 } 145 146fc .Args = p .parseExpressionList () 147 148fc .RightParen = util .Ptr (p .expect (token .RPAREN )) 149 150return fc 151} 152 153func (p * Parser )accept (tokenType token.TokenType )* ast.Unit { 154if ! p .tokIs (tokenType ) { 155return nil 156 } 157return util .Ptr (p .next ()) 158} 159 160func (p * Parser )expect (tokenType token.TokenType ) ast.Unit { 161if ! p .tokIs (tokenType ) { 162initialPos := p .pos 163errorTokens := []token.Token {p .unit ().Token } 164limit := p .pos + 5 165if limit > len (p .units )- 1 { 166limit = len (p .units )- 1 167 } 168for i := p .pos + 1 ;i < limit ;i ++ { 169unit := p .units [i ] 170if unit .Type ()== tokenType { 171p .pos = i 172break 173 }else { 174for _ ,tok := range unit .LeadingTrivia { 175errorTokens = append (errorTokens ,tok ) 176 } 177errorTokens = append (errorTokens ,unit .Token ) 178for _ ,tok := range unit .TrailingTrivia { 179errorTokens = append (errorTokens ,tok ) 180 } 181 } 182 } 183if p .pos != initialPos { 184unit := & p .units [p .pos ] 185for _ ,tok := range errorTokens { 186p .errors = append (p .errors , ast.Diagnostic { 187Message :fmt .Sprintf ("Extraneous %s" ,token .TokenStr [tok .Type ]), 188Range :tok .Range (), 189Severity :protocol .DiagnosticSeverityError , 190 }) 191unit .LeadingTrivia = append (unit .LeadingTrivia ,tok ) 192 } 193 }else { 194fakeTok := ast.Unit { 195LeadingTrivia : []token.Token {}, 196Token : token.Token { 197Type :tokenType , 198Literal :"" , 199Pos :initialPos , 200 }, 201TrailingTrivia : []token.Token {}, 202 } 203p .errors = append (p .errors , ast.Diagnostic { 204Message :fmt .Sprintf ("Missing %s" ,token .TokenStr [tokenType ]), 205Range :fakeTok .Range (), 206Severity :protocol .DiagnosticSeverityError , 207 }) 208p .next () 209return fakeTok 210 } 211 } 212p .next () 213return p .units [p .pos - 1 ] 214} 215 216func (p * Parser )expectedTokenError (expected token.TokenType ) { 217p .addError ( 218fmt .Sprintf ("Expected %s, got %s" , 219token .TokenStr [expected ], 220token .TokenStr [p .unit ().Type ()]), 221 ) 222} 223 224func (p * Parser )invalidTokenError () { 225p .addError (fmt .Sprintf ("Unexpected %s" ,token .TokenStr [p .unit ().Type ()])) 226} 227 228func (p * Parser )addError (message string ) { 229p .errors = append (p .errors , ast.Diagnostic { 230Range :p .unit ().Token .Range (), 231Message :message , 232Severity :protocol .DiagnosticSeverityError , 233 }) 234} 235 236func (p * Parser )addErrorForNode (node ast.Node ,message string ) { 237p .errors = append (p .errors , ast.Diagnostic {Range :ast .Range (node ),Message :message ,Severity :protocol .DiagnosticSeverityError }) 238} 239 240func (p * Parser )tokIs (tokenType token.TokenType )bool { 241return p .unit ().Type ()== tokenType 242} 243 244func (p * Parser )tokPrecedence ()operatorPrecedence { 245if p ,ok := precedences [p .unit ().Type ()];ok { 246return p 247 } 248return LOWEST 249} 250 251var blockEnd = map [token.TokenType ]bool { 252token .ELSEIF :true , 253token .ELSE :true , 254token .END :true , 255token .EOF :true , 256token .UNTIL :true , 257}