1use alloc::{vec, vec::Vec};
2use core::num::NonZeroU32;
3
4use crate::{
5 front::glsl::{
6 ast::{FunctionCall, FunctionCallKind, HirExpr, HirExprKind},
7 context::{Context, StmtContext},
8 error::{ErrorKind, ExpectedToken},
9 parser::ParsingContext,
10 token::{Token, TokenValue},
11 Error, Frontend, Result, Span,
12 },
13 ArraySize, BinaryOperator, Handle, Literal, Type, TypeInner, UnaryOperator,
14};
15
16impl ParsingContext<'_> {
17 pub fn parse_primary(
18 &mut self,
19 frontend: &mut Frontend,
20 ctx: &mut Context,
21 stmt: &mut StmtContext,
22 ) -> Result<Handle<HirExpr>> {
23 let mut token = self.bump(frontend)?;
24
25 let literal = match token.value {
26 TokenValue::IntConstant(int) => {
27 if int.width != 32 {
28 frontend.errors.push(Error {
29 kind: ErrorKind::SemanticError("Unsupported non-32bit integer".into()),
30 meta: token.meta,
31 });
32 }
33 if int.signed {
34 Literal::I32(int.value as i32)
35 } else {
36 Literal::U32(int.value as u32)
37 }
38 }
39 TokenValue::FloatConstant(float) => {
40 if float.width != 32 {
41 frontend.errors.push(Error {
42 kind: ErrorKind::SemanticError(
43 concat!(
44 "Unsupported floating-point value ",
45 "(expected single-precision floating-point number)"
46 )
47 .into(),
48 ),
49 meta: token.meta,
50 });
51 }
52 Literal::F32(float.value)
53 }
54 TokenValue::BoolConstant(value) => Literal::Bool(value),
55 TokenValue::LeftParen => {
56 let expr = self.parse_expression(frontend, ctx, stmt)?;
57 let meta = self.expect(frontend, TokenValue::RightParen)?.meta;
58
59 token.meta.subsume(meta);
60
61 return Ok(expr);
62 }
63 _ => {
64 return Err(Error {
65 kind: ErrorKind::InvalidToken(
66 token.value,
67 vec![
68 TokenValue::LeftParen.into(),
69 ExpectedToken::IntLiteral,
70 ExpectedToken::FloatLiteral,
71 ExpectedToken::BoolLiteral,
72 ],
73 ),
74 meta: token.meta,
75 });
76 }
77 };
78
79 Ok(stmt.hir_exprs.append(
80 HirExpr {
81 kind: HirExprKind::Literal(literal),
82 meta: token.meta,
83 },
84 Default::default(),
85 ))
86 }
87
88 pub fn parse_function_call_args(
89 &mut self,
90 frontend: &mut Frontend,
91 ctx: &mut Context,
92 stmt: &mut StmtContext,
93 meta: &mut Span,
94 ) -> Result<Vec<Handle<HirExpr>>> {
95 let mut args = Vec::new();
96 if let Some(token) = self.bump_if(frontend, TokenValue::RightParen) {
97 meta.subsume(token.meta);
98 } else {
99 loop {
100 args.push(self.parse_assignment(frontend, ctx, stmt)?);
101
102 let token = self.bump(frontend)?;
103 match token.value {
104 TokenValue::Comma => {}
105 TokenValue::RightParen => {
106 meta.subsume(token.meta);
107 break;
108 }
109 _ => {
110 return Err(Error {
111 kind: ErrorKind::InvalidToken(
112 token.value,
113 vec![TokenValue::Comma.into(), TokenValue::RightParen.into()],
114 ),
115 meta: token.meta,
116 });
117 }
118 }
119 }
120 }
121
122 Ok(args)
123 }
124
125 pub fn parse_postfix(
126 &mut self,
127 frontend: &mut Frontend,
128 ctx: &mut Context,
129 stmt: &mut StmtContext,
130 ) -> Result<Handle<HirExpr>> {
131 let mut base = if self.peek_type_name(frontend) {
132 let (mut handle, mut meta) = self.parse_type_non_void(frontend, ctx)?;
133
134 self.expect(frontend, TokenValue::LeftParen)?;
135 let args = self.parse_function_call_args(frontend, ctx, stmt, &mut meta)?;
136
137 if let TypeInner::Array {
138 size: ArraySize::Dynamic,
139 stride,
140 base,
141 } = ctx.module.types[handle].inner
142 {
143 let span = ctx.module.types.get_span(handle);
144
145 let size = u32::try_from(args.len())
146 .ok()
147 .and_then(NonZeroU32::new)
148 .ok_or(Error {
149 kind: ErrorKind::SemanticError(
150 "There must be at least one argument".into(),
151 ),
152 meta,
153 })?;
154
155 handle = ctx.module.types.insert(
156 Type {
157 name: None,
158 inner: TypeInner::Array {
159 stride,
160 base,
161 size: ArraySize::Constant(size),
162 },
163 },
164 span,
165 )
166 }
167
168 stmt.hir_exprs.append(
169 HirExpr {
170 kind: HirExprKind::Call(FunctionCall {
171 kind: FunctionCallKind::TypeConstructor(handle),
172 args,
173 }),
174 meta,
175 },
176 Default::default(),
177 )
178 } else if let TokenValue::Identifier(_) = self.expect_peek(frontend)?.value {
179 let (name, mut meta) = self.expect_ident(frontend)?;
180
181 let expr = if self.bump_if(frontend, TokenValue::LeftParen).is_some() {
182 let args = self.parse_function_call_args(frontend, ctx, stmt, &mut meta)?;
183
184 let kind = match frontend.lookup_type.get(&name) {
185 Some(ty) => FunctionCallKind::TypeConstructor(*ty),
186 None => FunctionCallKind::Function(name),
187 };
188
189 HirExpr {
190 kind: HirExprKind::Call(FunctionCall { kind, args }),
191 meta,
192 }
193 } else {
194 let var = match frontend.lookup_variable(ctx, &name, meta)? {
195 Some(var) => var,
196 None => {
197 return Err(Error {
198 kind: ErrorKind::UnknownVariable(name),
199 meta,
200 })
201 }
202 };
203
204 HirExpr {
205 kind: HirExprKind::Variable(var),
206 meta,
207 }
208 };
209
210 stmt.hir_exprs.append(expr, Default::default())
211 } else {
212 self.parse_primary(frontend, ctx, stmt)?
213 };
214
215 while let TokenValue::LeftBracket
216 | TokenValue::Dot
217 | TokenValue::Increment
218 | TokenValue::Decrement = self.expect_peek(frontend)?.value
219 {
220 let Token { value, mut meta } = self.bump(frontend)?;
221
222 match value {
223 TokenValue::LeftBracket => {
224 let index = self.parse_expression(frontend, ctx, stmt)?;
225 let end_meta = self.expect(frontend, TokenValue::RightBracket)?.meta;
226
227 meta.subsume(end_meta);
228 base = stmt.hir_exprs.append(
229 HirExpr {
230 kind: HirExprKind::Access { base, index },
231 meta,
232 },
233 Default::default(),
234 )
235 }
236 TokenValue::Dot => {
237 let (field, end_meta) = self.expect_ident(frontend)?;
238
239 if self.bump_if(frontend, TokenValue::LeftParen).is_some() {
240 let args = self.parse_function_call_args(frontend, ctx, stmt, &mut meta)?;
241
242 base = stmt.hir_exprs.append(
243 HirExpr {
244 kind: HirExprKind::Method {
245 expr: base,
246 name: field,
247 args,
248 },
249 meta,
250 },
251 Default::default(),
252 );
253 continue;
254 }
255
256 meta.subsume(end_meta);
257 base = stmt.hir_exprs.append(
258 HirExpr {
259 kind: HirExprKind::Select { base, field },
260 meta,
261 },
262 Default::default(),
263 )
264 }
265 TokenValue::Increment | TokenValue::Decrement => {
266 base = stmt.hir_exprs.append(
267 HirExpr {
268 kind: HirExprKind::PrePostfix {
269 op: match value {
270 TokenValue::Increment => BinaryOperator::Add,
271 _ => BinaryOperator::Subtract,
272 },
273 postfix: true,
274 expr: base,
275 },
276 meta,
277 },
278 Default::default(),
279 )
280 }
281 _ => unreachable!(),
282 }
283 }
284
285 Ok(base)
286 }
287
288 pub fn parse_unary(
289 &mut self,
290 frontend: &mut Frontend,
291 ctx: &mut Context,
292 stmt: &mut StmtContext,
293 ) -> Result<Handle<HirExpr>> {
294 Ok(match self.expect_peek(frontend)?.value {
295 TokenValue::Plus | TokenValue::Dash | TokenValue::Bang | TokenValue::Tilde => {
296 let Token { value, mut meta } = self.bump(frontend)?;
297
298 let expr = self.parse_unary(frontend, ctx, stmt)?;
299 let end_meta = stmt.hir_exprs[expr].meta;
300
301 let kind = match value {
302 TokenValue::Dash => HirExprKind::Unary {
303 op: UnaryOperator::Negate,
304 expr,
305 },
306 TokenValue::Bang => HirExprKind::Unary {
307 op: UnaryOperator::LogicalNot,
308 expr,
309 },
310 TokenValue::Tilde => HirExprKind::Unary {
311 op: UnaryOperator::BitwiseNot,
312 expr,
313 },
314 _ => return Ok(expr),
315 };
316
317 meta.subsume(end_meta);
318 stmt.hir_exprs
319 .append(HirExpr { kind, meta }, Default::default())
320 }
321 TokenValue::Increment | TokenValue::Decrement => {
322 let Token { value, meta } = self.bump(frontend)?;
323
324 let expr = self.parse_unary(frontend, ctx, stmt)?;
325
326 stmt.hir_exprs.append(
327 HirExpr {
328 kind: HirExprKind::PrePostfix {
329 op: match value {
330 TokenValue::Increment => BinaryOperator::Add,
331 _ => BinaryOperator::Subtract,
332 },
333 postfix: false,
334 expr,
335 },
336 meta,
337 },
338 Default::default(),
339 )
340 }
341 _ => self.parse_postfix(frontend, ctx, stmt)?,
342 })
343 }
344
345 pub fn parse_binary(
346 &mut self,
347 frontend: &mut Frontend,
348 ctx: &mut Context,
349 stmt: &mut StmtContext,
350 passthrough: Option<Handle<HirExpr>>,
351 min_bp: u8,
352 ) -> Result<Handle<HirExpr>> {
353 let mut left = passthrough
354 .ok_or(ErrorKind::EndOfFile )
355 .or_else(|_| self.parse_unary(frontend, ctx, stmt))?;
356 let mut meta = stmt.hir_exprs[left].meta;
357
358 while let Some((l_bp, r_bp)) = binding_power(&self.expect_peek(frontend)?.value) {
359 if l_bp < min_bp {
360 break;
361 }
362
363 let Token { value, .. } = self.bump(frontend)?;
364
365 let right = self.parse_binary(frontend, ctx, stmt, None, r_bp)?;
366 let end_meta = stmt.hir_exprs[right].meta;
367
368 meta.subsume(end_meta);
369 left = stmt.hir_exprs.append(
370 HirExpr {
371 kind: HirExprKind::Binary {
372 left,
373 op: match value {
374 TokenValue::LogicalOr => BinaryOperator::LogicalOr,
375 TokenValue::LogicalXor => BinaryOperator::NotEqual,
376 TokenValue::LogicalAnd => BinaryOperator::LogicalAnd,
377 TokenValue::VerticalBar => BinaryOperator::InclusiveOr,
378 TokenValue::Caret => BinaryOperator::ExclusiveOr,
379 TokenValue::Ampersand => BinaryOperator::And,
380 TokenValue::Equal => BinaryOperator::Equal,
381 TokenValue::NotEqual => BinaryOperator::NotEqual,
382 TokenValue::GreaterEqual => BinaryOperator::GreaterEqual,
383 TokenValue::LessEqual => BinaryOperator::LessEqual,
384 TokenValue::LeftAngle => BinaryOperator::Less,
385 TokenValue::RightAngle => BinaryOperator::Greater,
386 TokenValue::LeftShift => BinaryOperator::ShiftLeft,
387 TokenValue::RightShift => BinaryOperator::ShiftRight,
388 TokenValue::Plus => BinaryOperator::Add,
389 TokenValue::Dash => BinaryOperator::Subtract,
390 TokenValue::Star => BinaryOperator::Multiply,
391 TokenValue::Slash => BinaryOperator::Divide,
392 TokenValue::Percent => BinaryOperator::Modulo,
393 _ => unreachable!(),
394 },
395 right,
396 },
397 meta,
398 },
399 Default::default(),
400 )
401 }
402
403 Ok(left)
404 }
405
406 pub fn parse_conditional(
407 &mut self,
408 frontend: &mut Frontend,
409 ctx: &mut Context,
410 stmt: &mut StmtContext,
411 passthrough: Option<Handle<HirExpr>>,
412 ) -> Result<Handle<HirExpr>> {
413 let mut condition = self.parse_binary(frontend, ctx, stmt, passthrough, 0)?;
414 let mut meta = stmt.hir_exprs[condition].meta;
415
416 if self.bump_if(frontend, TokenValue::Question).is_some() {
417 let accept = self.parse_expression(frontend, ctx, stmt)?;
418 self.expect(frontend, TokenValue::Colon)?;
419 let reject = self.parse_assignment(frontend, ctx, stmt)?;
420 let end_meta = stmt.hir_exprs[reject].meta;
421
422 meta.subsume(end_meta);
423 condition = stmt.hir_exprs.append(
424 HirExpr {
425 kind: HirExprKind::Conditional {
426 condition,
427 accept,
428 reject,
429 },
430 meta,
431 },
432 Default::default(),
433 )
434 }
435
436 Ok(condition)
437 }
438
439 pub fn parse_assignment(
440 &mut self,
441 frontend: &mut Frontend,
442 ctx: &mut Context,
443 stmt: &mut StmtContext,
444 ) -> Result<Handle<HirExpr>> {
445 let tgt = self.parse_unary(frontend, ctx, stmt)?;
446 let mut meta = stmt.hir_exprs[tgt].meta;
447
448 Ok(match self.expect_peek(frontend)?.value {
449 TokenValue::Assign => {
450 self.bump(frontend)?;
451 let value = self.parse_assignment(frontend, ctx, stmt)?;
452 let end_meta = stmt.hir_exprs[value].meta;
453
454 meta.subsume(end_meta);
455 stmt.hir_exprs.append(
456 HirExpr {
457 kind: HirExprKind::Assign { tgt, value },
458 meta,
459 },
460 Default::default(),
461 )
462 }
463 TokenValue::OrAssign
464 | TokenValue::AndAssign
465 | TokenValue::AddAssign
466 | TokenValue::DivAssign
467 | TokenValue::ModAssign
468 | TokenValue::SubAssign
469 | TokenValue::MulAssign
470 | TokenValue::LeftShiftAssign
471 | TokenValue::RightShiftAssign
472 | TokenValue::XorAssign => {
473 let token = self.bump(frontend)?;
474 let right = self.parse_assignment(frontend, ctx, stmt)?;
475 let end_meta = stmt.hir_exprs[right].meta;
476
477 meta.subsume(end_meta);
478 let value = stmt.hir_exprs.append(
479 HirExpr {
480 meta,
481 kind: HirExprKind::Binary {
482 left: tgt,
483 op: match token.value {
484 TokenValue::OrAssign => BinaryOperator::InclusiveOr,
485 TokenValue::AndAssign => BinaryOperator::And,
486 TokenValue::AddAssign => BinaryOperator::Add,
487 TokenValue::DivAssign => BinaryOperator::Divide,
488 TokenValue::ModAssign => BinaryOperator::Modulo,
489 TokenValue::SubAssign => BinaryOperator::Subtract,
490 TokenValue::MulAssign => BinaryOperator::Multiply,
491 TokenValue::LeftShiftAssign => BinaryOperator::ShiftLeft,
492 TokenValue::RightShiftAssign => BinaryOperator::ShiftRight,
493 TokenValue::XorAssign => BinaryOperator::ExclusiveOr,
494 _ => unreachable!(),
495 },
496 right,
497 },
498 },
499 Default::default(),
500 );
501
502 stmt.hir_exprs.append(
503 HirExpr {
504 kind: HirExprKind::Assign { tgt, value },
505 meta,
506 },
507 Default::default(),
508 )
509 }
510 _ => self.parse_conditional(frontend, ctx, stmt, Some(tgt))?,
511 })
512 }
513
514 pub fn parse_expression(
515 &mut self,
516 frontend: &mut Frontend,
517 ctx: &mut Context,
518 stmt: &mut StmtContext,
519 ) -> Result<Handle<HirExpr>> {
520 let mut expr = self.parse_assignment(frontend, ctx, stmt)?;
521
522 while let TokenValue::Comma = self.expect_peek(frontend)?.value {
523 self.bump(frontend)?;
524 expr = self.parse_assignment(frontend, ctx, stmt)?;
525 }
526
527 Ok(expr)
528 }
529}
530
531const fn binding_power(value: &TokenValue) -> Option<(u8, u8)> {
532 Some(match *value {
533 TokenValue::LogicalOr => (1, 2),
534 TokenValue::LogicalXor => (3, 4),
535 TokenValue::LogicalAnd => (5, 6),
536 TokenValue::VerticalBar => (7, 8),
537 TokenValue::Caret => (9, 10),
538 TokenValue::Ampersand => (11, 12),
539 TokenValue::Equal | TokenValue::NotEqual => (13, 14),
540 TokenValue::GreaterEqual
541 | TokenValue::LessEqual
542 | TokenValue::LeftAngle
543 | TokenValue::RightAngle => (15, 16),
544 TokenValue::LeftShift | TokenValue::RightShift => (17, 18),
545 TokenValue::Plus | TokenValue::Dash => (19, 20),
546 TokenValue::Star | TokenValue::Slash | TokenValue::Percent => (21, 22),
547 _ => return None,
548 })
549}