z_mirror/luapls

git clone https://git.raiguard.me/z_mirror/luapls

Caleb HeuerRevert "Convert trivia to an interface in preparation annotations-in-AST"5c64afc

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