z_mirror/luapls

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

Caleb HeuerImprove error handling37b5dce

main
6.4 KiB275 linesraw
1package parser
2
3import (
4	"github.com/raiguard/luapls/lua/ast"
5	"github.com/raiguard/luapls/lua/token"
6	"github.com/raiguard/luapls/util"
7)
8
9func (p *Parser) parseStatement() ast.Statement {
10	switch p.unit().Type() {
11	case token.BREAK:
12		return p.parseBreakStatement()
13	case token.DO:
14		return p.parseDoStatement()
15	case token.FOR:
16		return p.parseForStatement()
17	case token.FUNCTION:
18		return p.parseFunctionStatement(nil)
19	case token.GOTO:
20		return p.parseGotoStatement()
21	case token.IF:
22		return p.parseIfStatement()
23	case token.LABEL:
24		return p.parseLabelStatement()
25	case token.LOCAL:
26		tok := p.expect(token.LOCAL)
27		switch p.unit().Type() {
28		case token.FUNCTION:
29			return p.parseFunctionStatement(&tok)
30		case token.IDENT:
31			return p.parseLocalStatement(tok)
32		}
33		stat := &ast.Invalid{Position: tok.Pos()}
34		p.addErrorForNode(stat, "Invalid statement")
35		return stat
36	case token.REPEAT:
37		return p.parseRepeatStatement()
38	case token.RETURN:
39		return p.parseReturnStatement()
40	case token.SEMICOLON:
41		return p.parseSemicolonStatement()
42	case token.WHILE:
43		return p.parseWhileStatement()
44	}
45
46	exps := p.parseExpressionList()
47	if p.tokIs(token.ASSIGN) {
48		return p.parseAssignmentStatement(exps)
49		// TODO: Can there ever be zero expressions?
50	} else if fc, ok := exps.Pairs[0].Node.(*ast.FunctionCall); ok {
51		return fc
52	} else {
53		stat := &ast.Invalid{Position: exps.Pos()}
54		p.addErrorForNode(stat, "Invalid statement")
55		return stat
56	}
57}
58
59func (p *Parser) parseAssignmentStatement(vars ast.Punctuated[ast.Expression]) *ast.AssignmentStatement {
60	assign := p.expect(token.ASSIGN)
61	exps := p.parseExpressionList()
62
63	return &ast.AssignmentStatement{
64		Vars:   vars,
65		Assign: assign,
66		Exps:   exps,
67	}
68}
69
70func (p *Parser) parseBreakStatement() *ast.BreakStatement {
71	node := util.Ptr(ast.BreakStatement(*p.unit()))
72	p.expect(token.BREAK)
73	return node
74}
75
76func (p *Parser) parseDoStatement() *ast.DoStatement {
77	do := p.expect(token.DO)
78	block := p.parseBlock()
79	end := p.expect(token.END)
80	return &ast.DoStatement{
81		DoTok:  do,
82		Body:   block,
83		EndTok: end,
84	}
85}
86
87func (p *Parser) parseForStatement() ast.Statement {
88	forTok := p.expect(token.FOR)
89	names := p.parseNameList()
90
91	var sepTok ast.Unit
92
93	bareLoop := len(names.Pairs) == 1 && p.tokIs(token.ASSIGN)
94	if bareLoop {
95		sepTok = p.expect(token.ASSIGN)
96	} else {
97		sepTok = p.expect(token.IN)
98	}
99
100	exps := p.parseExpressionList()
101	doTok := p.expect(token.DO)
102	body := p.parseBlock()
103	endTok := p.expect(token.END)
104
105	if bareLoop {
106		var start, finish ast.Pair[ast.Expression]
107		if len(exps.Pairs) < 2 || len(exps.Pairs) > 3 {
108			p.addError("Expected 2 to 3 expressions")
109		}
110		start = exps.Pairs[0]
111		finish = exps.Pairs[1]
112		var step *ast.Pair[ast.Expression]
113		if len(exps.Pairs) > 2 {
114			step = &exps.Pairs[2]
115		}
116		return &ast.ForStatement{
117			ForTok:    forTok,
118			Name:      names.Pairs[0].Node,
119			AssignTok: sepTok,
120			Start:     start,
121			Finish:    finish,
122			Step:      step,
123			DoTok:     doTok,
124			Body:      body,
125			EndTok:    endTok,
126		}
127	}
128
129	return &ast.ForInStatement{
130		ForTok: forTok,
131		Names:  names,
132		InTok:  sepTok,
133		Exps:   exps,
134		DoTok:  doTok,
135		Body:   body,
136		EndTok: endTok,
137	}
138}
139
140func (p *Parser) parseFunctionStatement(localTok *ast.Unit) *ast.FunctionStatement {
141	funcTok := p.expect(token.FUNCTION)
142	name := p.parseExpression(LOWEST, false)
143	lparen := p.expect(token.LPAREN)
144	params, vararg := p.parseParameterList()
145	rparen := p.expect(token.RPAREN)
146	body := p.parseBlock()
147	endTok := p.expect(token.END)
148
149	return &ast.FunctionStatement{
150		LocalTok:   localTok,
151		FuncTok:    funcTok,
152		Name:       name,
153		LeftParen:  lparen,
154		Params:     params,
155		Vararg:     vararg,
156		RightParen: rparen,
157		Body:       body,
158		EndTok:     endTok,
159	}
160}
161
162func (p *Parser) parseGotoStatement() *ast.GotoStatement {
163	gotoTok := p.expect(token.GOTO)
164	name := p.parseIdentifier()
165	return &ast.GotoStatement{
166		GotoTok: gotoTok,
167		Name:    name,
168	}
169}
170
171func (p *Parser) parseIfStatement() *ast.IfStatement {
172	ifTok := p.expect(token.IF)
173
174	clauses := []*ast.IfClause{p.parseIfClause(ifTok)}
175
176	for p.tokIs(token.ELSEIF) {
177		elseifTok := p.expect(token.ELSEIF)
178		clauses = append(clauses, p.parseIfClause(elseifTok))
179	}
180
181	if p.tokIs(token.ELSE) {
182		elseTok := p.expect(token.ELSE)
183		body := p.parseBlock()
184		clauses = append(clauses, &ast.IfClause{
185			LeadingTok: elseTok,
186			Condition:  nil,
187			ThenTok:    nil,
188			Body:       body,
189		})
190	}
191
192	endTok := p.expect(token.END)
193
194	return &ast.IfStatement{
195		IfTok:   ifTok,
196		Clauses: clauses,
197		EndTok:  endTok,
198	}
199}
200
201func (p *Parser) parseIfClause(leadingTok ast.Unit) *ast.IfClause {
202	condition := p.parseExpression(LOWEST, true)
203	thenTok := p.expect(token.THEN)
204	block := p.parseBlock()
205	return &ast.IfClause{
206		LeadingTok: leadingTok,
207		Condition:  condition,
208		ThenTok:    &thenTok,
209		Body:       block,
210	}
211}
212
213func (p *Parser) parseLabelStatement() *ast.LabelStatement {
214	leadingLabelTok := p.expect(token.LABEL)
215	name := p.parseIdentifier()
216	trailingLabelTok := p.expect(token.LABEL)
217	return &ast.LabelStatement{
218		LeadingLabelTok:  leadingLabelTok,
219		Name:             name,
220		TrailingLabelTok: trailingLabelTok,
221	}
222}
223
224func (p *Parser) parseLocalStatement(localTok ast.Unit) *ast.LocalStatement {
225	ls := &ast.LocalStatement{
226		LocalTok: localTok,
227		Names:    p.parseNameList(),
228	}
229	if assignTok := p.accept(token.ASSIGN); assignTok != nil {
230		ls.AssignTok = assignTok
231		ls.Exps = util.Ptr(p.parseExpressionList())
232	}
233	return ls
234}
235
236func (p *Parser) parseRepeatStatement() *ast.RepeatStatement {
237	repeatTok := p.expect(token.REPEAT)
238	body := p.parseBlock()
239	untilTok := p.expect(token.UNTIL)
240	condition := p.parseExpression(LOWEST, true)
241	return &ast.RepeatStatement{
242		RepeatTok: repeatTok,
243		Body:      body,
244		UntilTok:  untilTok,
245		Condition: condition,
246	}
247}
248
249func (p *Parser) parseReturnStatement() *ast.ReturnStatement {
250	returnTok := p.expect(token.RETURN)
251	rs := &ast.ReturnStatement{ReturnTok: returnTok}
252	if !blockEnd[p.unit().Type()] {
253		rs.Exps = util.Ptr(p.parseExpressionList())
254	}
255	return rs
256}
257
258func (p *Parser) parseSemicolonStatement() *ast.SemicolonStatement {
259	return util.Ptr(ast.SemicolonStatement(p.expect(token.SEMICOLON)))
260}
261
262func (p *Parser) parseWhileStatement() *ast.WhileStatement {
263	whileTok := p.expect(token.WHILE)
264	condition := p.parseExpression(LOWEST, true)
265	doTok := p.expect(token.DO)
266	body := p.parseBlock()
267	endTok := p.expect(token.END)
268	return &ast.WhileStatement{
269		WhileTok:  whileTok,
270		Condition: condition,
271		DoTok:     doTok,
272		Body:      body,
273		EndTok:    endTok,
274	}
275}