sbpf_assembler/
parser.rs

1use crate::ast::AST;
2use crate::astnode::{
3    ASTNode, Directive, EquDecl, ExternDecl, GlobalDecl, Label, ROData, RodataDecl,
4};
5use crate::bug;
6use crate::dynsym::{DynamicSymbolMap, RelDynMap};
7use crate::errors::CompileError;
8use crate::instruction::Instruction;
9use crate::lexer::Op;
10use crate::lexer::{ImmediateValue, Token};
11use crate::messages::*;
12use crate::section::{CodeSection, DataSection};
13use num_traits::FromPrimitive;
14use sbpf_common::opcode::Opcode;
15use std::collections::HashMap;
16
17pub struct ParseResult {
18    // TODO: parse result is basically 1. static part 2. dynamic part of the program
19    pub code_section: CodeSection,
20
21    pub data_section: DataSection,
22
23    pub dynamic_symbols: DynamicSymbolMap,
24
25    pub relocation_data: RelDynMap,
26
27    // TODO: this can be removed and dynamic-ness should just be
28    // determined by if there's any dynamic symbol
29    pub prog_is_static: bool,
30}
31
32// for now, we only return one error per parse for simpler error handling
33pub trait Parse {
34    fn parse(tokens: &[Token]) -> Result<(Self, &[Token]), CompileError>
35    where
36        Self: Sized;
37}
38
39pub trait ParseWithConstMap {
40    fn parse_with_constmap<'a>(
41        tokens: &'a [Token],
42        const_map: &HashMap<String, ImmediateValue>,
43    ) -> Result<(Self, &'a [Token]), CompileError>
44    where
45        Self: Sized;
46}
47
48impl Parse for GlobalDecl {
49    fn parse(tokens: &[Token]) -> Result<(Self, &[Token]), CompileError> {
50        let Token::Directive(_, span) = &tokens[0] else {
51            bug!("GlobalDecl not a valid directive")
52        };
53        if tokens.len() < 2 {
54            return Err(CompileError::InvalidGlobalDecl {
55                span: span.clone(),
56                custom_label: None,
57            });
58        }
59        match &tokens[1] {
60            Token::Identifier(name, span) => Ok((
61                GlobalDecl {
62                    entry_label: name.clone(),
63                    span: span.clone(),
64                },
65                &tokens[2..],
66            )),
67            _ => Err(CompileError::InvalidGlobalDecl {
68                span: span.clone(),
69                custom_label: None,
70            }),
71        }
72    }
73}
74
75impl ParseWithConstMap for EquDecl {
76    fn parse_with_constmap<'a>(
77        tokens: &'a [Token],
78        const_map: &HashMap<String, ImmediateValue>,
79    ) -> Result<(Self, &'a [Token]), CompileError> {
80        let Token::Directive(_, span) = &tokens[0] else {
81            bug!("EquDecl not a valid directive")
82        };
83        if tokens.len() < 3 {
84            return Err(CompileError::InvalidEquDecl {
85                span: span.clone(),
86                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
87            });
88        }
89        let (value, advance_token_num) = inline_and_fold_constant(tokens, const_map, 3);
90        if let Some(value) = value {
91            match (
92                &tokens[1], &tokens[2],
93                // third operand is folded to an immediate value
94            ) {
95                (
96                    Token::Identifier(name, span),
97                    Token::Comma(_),
98                    // third operand is folded to an immediate value
99                ) => Ok((
100                    EquDecl {
101                        name: name.clone(),
102                        value: Token::ImmediateValue(value, span.clone()),
103                        span: span.clone(),
104                    },
105                    &tokens[advance_token_num..],
106                )),
107                _ => Err(CompileError::InvalidEquDecl {
108                    span: span.clone(),
109                    custom_label: Some(EXPECTS_IDEN_COM_IMM.to_string()),
110                }),
111            }
112        } else {
113            Err(CompileError::InvalidEquDecl {
114                span: span.clone(),
115                custom_label: Some(EXPECTS_IDEN_COM_IMM.to_string()),
116            })
117        }
118    }
119}
120
121impl Parse for ExternDecl {
122    fn parse(tokens: &[Token]) -> Result<(Self, &[Token]), CompileError> {
123        let Token::Directive(_, span) = &tokens[0] else {
124            bug!("ExternDecl not a valid directive")
125        };
126        if tokens.len() < 2 {
127            return Err(CompileError::InvalidExternDecl {
128                span: span.clone(),
129                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
130            });
131        }
132        let mut args = Vec::new();
133        let mut i = 1;
134        while i < tokens.len() {
135            match &tokens[i] {
136                Token::Identifier(name, span) => {
137                    args.push(Token::Identifier(name.clone(), span.clone()));
138                    i += 1;
139                }
140                _ => {
141                    break;
142                }
143            }
144        }
145        //
146        if args.is_empty() {
147            Err(CompileError::InvalidExternDecl {
148                span: span.clone(),
149                custom_label: Some(EXPECTS_IDEN.to_string()),
150            })
151        } else {
152            Ok((
153                ExternDecl {
154                    args,
155                    span: span.clone(),
156                },
157                &tokens[i..],
158            ))
159        }
160    }
161}
162
163impl Parse for ROData {
164    fn parse(tokens: &[Token]) -> Result<(Self, &[Token]), CompileError> {
165        let Token::Label(_, span) = &tokens[0] else {
166            bug!("ROData not a valid directive")
167        };
168        if tokens.len() < 3 {
169            return Err(CompileError::InvalidRodataDecl {
170                span: span.clone(),
171                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
172            });
173        }
174
175        let mut args = Vec::new();
176        match (&tokens[0], &tokens[1], &tokens[2]) {
177            (Token::Label(name, span), Token::Directive(_, _), Token::StringLiteral(_, _)) => {
178                args.push(tokens[1].clone());
179                args.push(tokens[2].clone());
180                Ok((
181                    ROData {
182                        name: name.clone(),
183                        args,
184                        span: span.clone(),
185                    },
186                    &tokens[3..],
187                ))
188            }
189            (Token::Label(name, span), Token::Directive(_, _), Token::ImmediateValue(val, _)) => {
190                let mut data_vector = vec![val.clone()];
191                let idx = parse_vector_literal(tokens, &mut data_vector, 3);
192                args.push(tokens[1].clone());
193                args.push(Token::VectorLiteral(data_vector, span.clone()));
194                Ok((
195                    ROData {
196                        name: name.clone(),
197                        args,
198                        span: span.clone(),
199                    },
200                    &tokens[idx..],
201                ))
202            }
203            _ => Err(CompileError::InvalidRodataDecl {
204                span: span.clone(),
205                custom_label: Some(EXPECTS_LABEL_DIR_STR.to_string()),
206            }),
207        }
208    }
209}
210
211impl ParseWithConstMap for Instruction {
212    fn parse_with_constmap<'a>(
213        tokens: &'a [Token],
214        const_map: &HashMap<String, ImmediateValue>,
215    ) -> Result<(Self, &'a [Token]), CompileError> {
216        let next_token_num;
217        match &tokens[0] {
218            Token::Opcode(opcode, span) => {
219                let mut opcode = *opcode;
220                let mut operands = Vec::new();
221                match opcode {
222                    Opcode::Lddw => {
223                        if tokens.len() < 4 {
224                            return Err(CompileError::InvalidInstruction {
225                                //
226                                instruction: opcode.to_string(), //
227                                span: span.clone(),              //
228                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
229                            });
230                        }
231                        let (value, advance_token_num) =
232                            inline_and_fold_constant(tokens, const_map, 3);
233                        if let Some(value) = value {
234                            match (
235                                &tokens[1],
236                                &tokens[2],
237                                // Third operand is folded to an immediate value
238                            ) {
239                                (
240                                    Token::Register(_, _),
241                                    Token::Comma(_),
242                                    // Third operand is folded to an immediate value
243                                ) => {
244                                    operands.push(tokens[1].clone());
245                                    operands.push(Token::ImmediateValue(value, span.clone()));
246                                }
247                                _ => {
248                                    return Err(CompileError::InvalidInstruction {
249                                        //
250                                        instruction: opcode.to_string(), //
251                                        span: span.clone(),              //
252                                        custom_label: Some(EXPECTS_REG_COM_IMM_OR_IDEN.to_string()),
253                                    });
254                                }
255                            }
256                            next_token_num = advance_token_num;
257                        } else {
258                            match (&tokens[1], &tokens[2], &tokens[3]) {
259                                (
260                                    Token::Register(_, _),
261                                    Token::Comma(_),
262                                    Token::Identifier(_, _),
263                                ) => {
264                                    operands.push(tokens[1].clone());
265                                    operands.push(tokens[3].clone());
266                                }
267                                _ => {
268                                    return Err(CompileError::InvalidInstruction {
269                                        //
270                                        instruction: opcode.to_string(), //
271                                        span: span.clone(),              //
272                                        custom_label: Some(EXPECTS_REG_COM_IMM_OR_IDEN.to_string()),
273                                    });
274                                }
275                            }
276                            next_token_num = 4;
277                        }
278                    }
279                    Opcode::Ldxw | Opcode::Ldxh | Opcode::Ldxb | Opcode::Ldxdw => {
280                        if tokens.len() < 8 {
281                            return Err(CompileError::InvalidInstruction {
282                                //
283                                instruction: opcode.to_string(), //
284                                span: span.clone(),              //
285                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
286                            });
287                        }
288                        let (value, advance_token_num) =
289                            inline_and_fold_constant(tokens, const_map, 6);
290                        if let Some(value) = value {
291                            match (
292                                &tokens[1],
293                                &tokens[2],
294                                &tokens[3],
295                                &tokens[4],
296                                &tokens[5],
297                                // Sixth operand is folded to an immediate value
298                                &tokens[advance_token_num],
299                            ) {
300                                (
301                                    Token::Register(_, _),
302                                    Token::Comma(_),
303                                    Token::LeftBracket(_),
304                                    Token::Register(_, _),
305                                    Token::BinaryOp(_, _),
306                                    // Sixth operand is folded to an immediate value
307                                    Token::RightBracket(_),
308                                ) => {
309                                    operands.push(tokens[1].clone());
310                                    operands.push(tokens[4].clone());
311                                    operands.push(Token::ImmediateValue(value, span.clone()));
312                                }
313                                _ => {
314                                    return Err(CompileError::InvalidInstruction {
315                                        //
316                                        instruction: opcode.to_string(), //
317                                        span: span.clone(),              //
318                                        custom_label: Some(
319                                            EXPECTS_REG_COM_LB_REG_BIOP_IMM_RB.to_string(),
320                                        ),
321                                    });
322                                }
323                            }
324                            next_token_num = advance_token_num + 1;
325                        } else {
326                            return Err(CompileError::InvalidInstruction {
327                                //
328                                instruction: opcode.to_string(), //
329                                span: span.clone(),              //
330                                custom_label: Some(EXPECTS_REG_COM_LB_REG_BIOP_IMM_RB.to_string()),
331                            });
332                        }
333                    }
334                    Opcode::Stw | Opcode::Sth | Opcode::Stb | Opcode::Stdw => {
335                        if tokens.len() < 8 {
336                            return Err(CompileError::InvalidInstruction {
337                                //
338                                instruction: opcode.to_string(), //
339                                span: span.clone(),              //
340                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
341                            });
342                        }
343                        let (value, advance_token_num) =
344                            inline_and_fold_constant(tokens, const_map, 4);
345                        if let Some(value) = value {
346                            // Now we need to fold the second immediate value (after the comma)
347                            let (value2, advance_token_num2) =
348                                inline_and_fold_constant(tokens, const_map, advance_token_num + 2);
349                            if let Some(value2) = value2 {
350                                match (
351                                    &tokens[1],
352                                    &tokens[2],
353                                    &tokens[3],
354                                    // Fourth operand is folded to an immediate value
355                                    &tokens[advance_token_num],
356                                    &tokens[advance_token_num + 1],
357                                    // Sixth operand is also folded to an immediate value
358                                ) {
359                                    (
360                                        Token::LeftBracket(_),
361                                        Token::Register(_, _),
362                                        Token::BinaryOp(_, _),
363                                        // Fourth operand is folded to an immediate value
364                                        Token::RightBracket(_),
365                                        Token::Comma(_),
366                                    ) => {
367                                        operands.push(tokens[2].clone());
368                                        operands.push(Token::ImmediateValue(value2, span.clone()));
369                                        operands.push(Token::ImmediateValue(value, span.clone()));
370                                    }
371                                    _ => {
372                                        return Err(CompileError::InvalidInstruction {
373                                            //
374                                            instruction: opcode.to_string(), //
375                                            span: span.clone(),              //
376                                            custom_label: Some(
377                                                EXPECTS_LB_REG_BIOP_IMM_RB_COM_IMM.to_string(),
378                                            ),
379                                        });
380                                    }
381                                }
382                                next_token_num = advance_token_num2;
383                            } else {
384                                return Err(CompileError::InvalidInstruction {
385                                    //
386                                    instruction: opcode.to_string(), //
387                                    span: span.clone(),              //
388                                    custom_label: Some(
389                                        EXPECTS_LB_REG_BIOP_IMM_RB_COM_IMM.to_string(),
390                                    ),
391                                });
392                            }
393                        } else {
394                            return Err(CompileError::InvalidInstruction {
395                                //
396                                instruction: opcode.to_string(), //
397                                span: span.clone(),              //
398                                custom_label: Some(EXPECTS_LB_REG_BIOP_IMM_RB_COM_IMM.to_string()),
399                            });
400                        }
401                    }
402                    Opcode::Stxb | Opcode::Stxh | Opcode::Stxw | Opcode::Stxdw => {
403                        if tokens.len() < 8 {
404                            return Err(CompileError::InvalidInstruction {
405                                //
406                                instruction: opcode.to_string(), //
407                                span: span.clone(),              //
408                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
409                            });
410                        }
411                        let (value, advance_token_num) =
412                            inline_and_fold_constant(tokens, const_map, 4);
413                        if let Some(value) = value {
414                            match (
415                                &tokens[1],
416                                &tokens[2],
417                                &tokens[3],
418                                // Fourth operand is folded to an immediate value
419                                &tokens[advance_token_num],
420                                &tokens[advance_token_num + 1],
421                                &tokens[advance_token_num + 2],
422                            ) {
423                                (
424                                    Token::LeftBracket(_),
425                                    Token::Register(_, _),
426                                    Token::BinaryOp(_, _),
427                                    // Fourth operand is folded to an immediate value
428                                    Token::RightBracket(_),
429                                    Token::Comma(_),
430                                    Token::Register(_, _),
431                                ) => {
432                                    operands.push(tokens[2].clone());
433                                    operands.push(Token::ImmediateValue(value, span.clone()));
434                                    operands.push(tokens[advance_token_num + 2].clone());
435                                }
436                                _ => {
437                                    return Err(CompileError::InvalidInstruction {
438                                        //
439                                        instruction: opcode.to_string(), //
440                                        span: span.clone(),              //
441                                        custom_label: Some(
442                                            EXPECTS_LB_REG_BIOP_IMM_RB_COM_REG.to_string(),
443                                        ),
444                                    });
445                                }
446                            }
447                            next_token_num = advance_token_num + 3;
448                        } else {
449                            return Err(CompileError::InvalidInstruction {
450                                //
451                                instruction: opcode.to_string(), //
452                                span: span.clone(),              //
453                                custom_label: Some(EXPECTS_LB_REG_BIOP_IMM_RB_COM_REG.to_string()),
454                            });
455                        }
456                    }
457                    Opcode::Add32
458                    | Opcode::Sub32
459                    | Opcode::Mul32
460                    | Opcode::Div32
461                    | Opcode::Or32
462                    | Opcode::And32
463                    | Opcode::Lsh32
464                    | Opcode::Rsh32
465                    | Opcode::Mod32
466                    | Opcode::Xor32
467                    | Opcode::Mov32
468                    | Opcode::Arsh32
469                    | Opcode::Lmul32
470                    | Opcode::Udiv32
471                    | Opcode::Urem32
472                    | Opcode::Sdiv32
473                    | Opcode::Srem32
474                    | Opcode::Add64
475                    | Opcode::Sub64
476                    | Opcode::Mul64
477                    | Opcode::Div64
478                    | Opcode::Or64
479                    | Opcode::And64
480                    | Opcode::Lsh64
481                    | Opcode::Rsh64
482                    | Opcode::Mod64
483                    | Opcode::Xor64
484                    | Opcode::Mov64
485                    | Opcode::Arsh64
486                    | Opcode::Lmul64
487                    | Opcode::Uhmul64
488                    | Opcode::Udiv64
489                    | Opcode::Urem64
490                    | Opcode::Sdiv64
491                    | Opcode::Srem64 => {
492                        if tokens.len() < 4 {
493                            return Err(CompileError::InvalidInstruction {
494                                //
495                                instruction: opcode.to_string(), //
496                                span: span.clone(),              //
497                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
498                            });
499                        }
500                        let (value, advance_token_num) =
501                            inline_and_fold_constant(tokens, const_map, 3);
502                        if let Some(value) = value {
503                            match (
504                                &tokens[1],
505                                &tokens[2],
506                                // Third operand is folded to an immediate value
507                            ) {
508                                (
509                                    Token::Register(_, _),
510                                    Token::Comma(_),
511                                    // Third operand is folded to an immediate value
512                                ) => {
513                                    opcode = FromPrimitive::from_u8((opcode as u8) + 1)
514                                        .expect("Invalid opcode conversion");
515                                    operands.push(tokens[1].clone());
516                                    operands.push(Token::ImmediateValue(value, span.clone()));
517                                }
518                                _ => {
519                                    return Err(CompileError::InvalidInstruction {
520                                        //
521                                        instruction: opcode.to_string(), //
522                                        span: span.clone(),              //
523                                        custom_label: Some(EXPECTS_REG_COM_IMM.to_string()),
524                                    });
525                                }
526                            }
527                            next_token_num = advance_token_num;
528                        } else {
529                            match (&tokens[1], &tokens[2], &tokens[3]) {
530                                (Token::Register(_, _), Token::Comma(_), Token::Register(_, _)) => {
531                                    opcode = FromPrimitive::from_u8((opcode as u8) + 2)
532                                        .expect("Invalid opcode conversion");
533                                    operands.push(tokens[1].clone());
534                                    operands.push(tokens[3].clone());
535                                }
536                                _ => {
537                                    return Err(CompileError::InvalidInstruction {
538                                        //
539                                        instruction: opcode.to_string(), //
540                                        span: span.clone(),              //
541                                        custom_label: Some(EXPECTS_REG_COM_REG.to_string()),
542                                    });
543                                }
544                            }
545                            next_token_num = 4;
546                        }
547                    }
548                    Opcode::Be | Opcode::Le => {
549                        if tokens.len() < 4 {
550                            return Err(CompileError::InvalidInstruction {
551                                //
552                                instruction: opcode.to_string(), //
553                                span: span.clone(),              //
554                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
555                            });
556                        }
557                        let (value, advance_token_num) =
558                            inline_and_fold_constant(tokens, const_map, 3);
559                        if let Some(value) = value {
560                            match (
561                                &tokens[1],
562                                &tokens[2],
563                                // Third operand is folded to an immediate value
564                            ) {
565                                (
566                                    Token::Register(_, _),
567                                    Token::Comma(_),
568                                    // Third operand is folded to an immediate value
569                                ) => {
570                                    operands.push(tokens[1].clone());
571                                    operands.push(Token::ImmediateValue(value, span.clone()));
572                                }
573                                _ => {
574                                    return Err(CompileError::InvalidInstruction {
575                                        //
576                                        instruction: opcode.to_string(), //
577                                        span: span.clone(),              //
578                                        custom_label: Some(EXPECTS_REG_COM_IMM.to_string()),
579                                    });
580                                }
581                            }
582                            next_token_num = advance_token_num;
583                        } else {
584                            return Err(CompileError::InvalidInstruction {
585                                //
586                                instruction: opcode.to_string(), //
587                                span: span.clone(),              //
588                                custom_label: Some(EXPECTS_REG_COM_IMM.to_string()),
589                            });
590                        }
591                    }
592                    Opcode::Jeq
593                    | Opcode::Jgt
594                    | Opcode::Jge
595                    | Opcode::Jlt
596                    | Opcode::Jle
597                    | Opcode::Jset
598                    | Opcode::Jne
599                    | Opcode::Jsgt
600                    | Opcode::Jsge
601                    | Opcode::Jslt
602                    | Opcode::Jsle => {
603                        if tokens.len() < 6 {
604                            return Err(CompileError::InvalidInstruction {
605                                //
606                                instruction: opcode.to_string(), //
607                                span: span.clone(),              //
608                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
609                            });
610                        }
611                        let (value, advance_token_num) =
612                            inline_and_fold_constant(tokens, const_map, 3);
613                        if let Some(value) = value {
614                            let (jump_val, jump_val_advance_token_num) =
615                                inline_and_fold_constant(tokens, const_map, advance_token_num + 1);
616                            if let Some(jump_val) = jump_val {
617                                match (
618                                    &tokens[1],
619                                    &tokens[2],
620                                    // Third operand is folded to an immediate value
621                                    &tokens[advance_token_num],
622                                    // Fifth operand is folded to an immediate value
623                                ) {
624                                    (
625                                        Token::Register(_, _),
626                                        Token::Comma(_),
627                                        // Third operand is folded to an immediate value
628                                        Token::Comma(_),
629                                        // Fifth operand is folded to an immediate value
630                                    ) => {
631                                        opcode = FromPrimitive::from_u8((opcode as u8) + 1)
632                                            .expect("Invalid opcode conversion");
633                                        operands.push(tokens[1].clone());
634                                        operands.push(Token::ImmediateValue(value, span.clone()));
635                                        operands
636                                            .push(Token::ImmediateValue(jump_val, span.clone()));
637                                    }
638                                    _ => {
639                                        return Err(CompileError::InvalidInstruction {
640                                            instruction: opcode.to_string(),
641                                            span: span.clone(),
642                                            custom_label: Some(
643                                                EXPECTS_REG_COM_IMM_COM_IMM_OR_IDEN.to_string(),
644                                            ),
645                                        });
646                                    }
647                                }
648                                next_token_num = jump_val_advance_token_num;
649                            } else {
650                                match (
651                                    &tokens[1],
652                                    &tokens[2],
653                                    // Third operand is folded to an immediate value
654                                    &tokens[advance_token_num],
655                                    &tokens[advance_token_num + 1],
656                                ) {
657                                    (
658                                        Token::Register(_, _),
659                                        Token::Comma(_),
660                                        // Third operand is folded to an immediate value
661                                        Token::Comma(_),
662                                        Token::Identifier(_, _),
663                                    ) => {
664                                        opcode = FromPrimitive::from_u8((opcode as u8) + 1)
665                                            .expect("Invalid opcode conversion");
666                                        operands.push(tokens[1].clone());
667                                        operands.push(Token::ImmediateValue(value, span.clone()));
668                                        operands.push(tokens[advance_token_num + 1].clone());
669                                    }
670                                    _ => {
671                                        return Err(CompileError::InvalidInstruction {
672                                            //
673                                            instruction: opcode.to_string(), //
674                                            span: span.clone(),              //
675                                            custom_label: Some(
676                                                EXPECTS_REG_COM_IMM_COM_IMM_OR_IDEN.to_string(),
677                                            ),
678                                        });
679                                    }
680                                }
681                                next_token_num = advance_token_num + 2;
682                            }
683                        } else {
684                            let (jump_val, jump_val_advance_token_num) =
685                                inline_and_fold_constant(tokens, const_map, advance_token_num + 1);
686                            if let Some(jump_val) = jump_val {
687                                match (
688                                    &tokens[1], &tokens[2], &tokens[3],
689                                    &tokens[4],
690                                    // Fifth operand is folded to an immediate value
691                                ) {
692                                    (
693                                        Token::Register(_, _),
694                                        Token::Comma(_),
695                                        Token::Register(_, _),
696                                        Token::Comma(_),
697                                        // Fifth operand is folded to an immediate value
698                                    ) => {
699                                        // turn "invalid opcode" to a bug
700                                        opcode = FromPrimitive::from_u8((opcode as u8) + 2)
701                                            .expect("Invalid opcode conversion");
702                                        operands.push(tokens[1].clone());
703                                        operands.push(tokens[3].clone());
704                                        operands
705                                            .push(Token::ImmediateValue(jump_val, span.clone()));
706                                    }
707                                    _ => {
708                                        return Err(CompileError::InvalidInstruction {
709                                            //
710                                            instruction: opcode.to_string(), //
711                                            span: span.clone(),              //
712                                            custom_label: Some(
713                                                EXPECTS_REG_COM_IMM_COM_IMM_OR_IDEN.to_string(),
714                                            ),
715                                        });
716                                    }
717                                }
718                                next_token_num = jump_val_advance_token_num;
719                            } else {
720                                match (&tokens[1], &tokens[2], &tokens[3], &tokens[4], &tokens[5]) {
721                                    (
722                                        Token::Register(_, _),
723                                        Token::Comma(_),
724                                        Token::Register(_, _),
725                                        Token::Comma(_),
726                                        Token::Identifier(_, _),
727                                    ) => {
728                                        // turn "invalid opcode" to a bug
729                                        opcode = FromPrimitive::from_u8((opcode as u8) + 2)
730                                            .expect("Invalid opcode conversion");
731                                        operands.push(tokens[1].clone());
732                                        operands.push(tokens[3].clone());
733                                        operands.push(tokens[5].clone());
734                                    }
735                                    _ => {
736                                        return Err(CompileError::InvalidInstruction {
737                                            //
738                                            instruction: opcode.to_string(), //
739                                            span: span.clone(),              //
740                                            custom_label: Some(
741                                                EXPECTS_REG_COM_IMM_COM_IMM_OR_IDEN.to_string(),
742                                            ),
743                                        });
744                                    }
745                                }
746                                next_token_num = 6;
747                            }
748                        }
749                    }
750                    Opcode::Neg32 | Opcode::Neg64 => {
751                        if tokens.len() < 2 {
752                            return Err(CompileError::InvalidInstruction {
753                                //
754                                instruction: opcode.to_string(), //
755                                span: span.clone(),              //
756                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
757                            });
758                        }
759                        match &tokens[1] {
760                            Token::Register(_, _) => {
761                                operands.push(tokens[1].clone());
762                            }
763                            _ => {
764                                return Err(CompileError::InvalidInstruction {
765                                    //
766                                    instruction: opcode.to_string(), //
767                                    span: span.clone(),              //
768                                    custom_label: Some(EXPECTS_REG.to_string()),
769                                });
770                            }
771                        }
772                        next_token_num = 2;
773                    }
774                    Opcode::Ja => {
775                        if tokens.len() < 2 {
776                            return Err(CompileError::InvalidInstruction {
777                                //
778                                instruction: opcode.to_string(), //
779                                span: span.clone(),              //
780                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
781                            });
782                        }
783                        let (value, advance_token_num) =
784                            inline_and_fold_constant(tokens, const_map, 1);
785                        if let Some(value) = value {
786                            operands.push(Token::ImmediateValue(value, span.clone()));
787                            next_token_num = advance_token_num;
788                        } else {
789                            match &tokens[1] {
790                                Token::Identifier(_, _) => {
791                                    operands.push(tokens[1].clone());
792                                }
793                                _ => {
794                                    return Err(CompileError::InvalidInstruction {
795                                        //
796                                        instruction: opcode.to_string(), //
797                                        span: span.clone(),              //
798                                        custom_label: Some(EXPECTS_IDEN.to_string()),
799                                    });
800                                }
801                            }
802                            next_token_num = 2;
803                        }
804                    }
805                    Opcode::Call => {
806                        if tokens.len() < 2 {
807                            return Err(CompileError::InvalidInstruction {
808                                //
809                                instruction: opcode.to_string(), //
810                                span: span.clone(),              //
811                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
812                            });
813                        }
814                        match &tokens[1] {
815                            Token::Identifier(_, _) => {
816                                operands.push(tokens[1].clone());
817                            }
818                            _ => {
819                                return Err(CompileError::InvalidInstruction {
820                                    //
821                                    instruction: opcode.to_string(), //
822                                    span: span.clone(),              //
823                                    custom_label: Some(EXPECTS_IDEN.to_string()),
824                                });
825                            }
826                        }
827                        next_token_num = 2;
828                    }
829                    Opcode::Callx => {
830                        if tokens.len() < 2 {
831                            return Err(CompileError::InvalidInstruction {
832                                //
833                                instruction: opcode.to_string(), //
834                                span: span.clone(),              //
835                                custom_label: Some(EXPECTS_MORE_OPERAND.to_string()),
836                            });
837                        }
838                        match &tokens[1] {
839                            Token::Register(_, _) => {
840                                operands.push(tokens[1].clone());
841                            }
842                            _ => {
843                                return Err(CompileError::InvalidInstruction {
844                                    //
845                                    instruction: opcode.to_string(), //
846                                    span: span.clone(),              //
847                                    custom_label: Some(EXPECTS_IDEN.to_string()),
848                                });
849                            }
850                        }
851                        next_token_num = 2;
852                    }
853                    Opcode::Exit => {
854                        next_token_num = 1;
855                    }
856                    _ => {
857                        bug!("invalid opcode: {}", opcode.to_str());
858                    }
859                }
860                Ok((
861                    Instruction {
862                        opcode,
863                        operands,
864                        span: span.clone(),
865                    },
866                    &tokens[next_token_num..],
867                ))
868            }
869            _ => {
870                bug!("invalid instruction");
871            }
872        }
873    }
874}
875
876fn parse_vector_literal(
877    tokens: &[Token],
878    stack: &mut Vec<ImmediateValue>,
879    start_idx: usize,
880) -> usize {
881    let mut idx = start_idx;
882    while idx < tokens.len() - 1 {
883        match (&tokens[idx], &tokens[idx + 1]) {
884            (Token::Comma(_), Token::ImmediateValue(val, _)) => {
885                stack.push(val.clone());
886                idx += 2;
887            }
888            _ => {
889                break;
890            }
891        }
892    }
893    idx
894}
895
896fn fold_top(stack: &mut Vec<Token>) {
897    if stack.len() < 3 {
898        return;
899    }
900
901    if let (
902        Token::ImmediateValue(val1, _),
903        Token::BinaryOp(op, _),
904        Token::ImmediateValue(val2, span),
905    ) = (
906        stack[stack.len() - 3].clone(),
907        stack[stack.len() - 2].clone(),
908        stack[stack.len() - 1].clone(),
909    ) {
910        let result = match op {
911            Op::Add => val1.clone() + val2.clone(),
912            Op::Sub => val1.clone() - val2.clone(),
913            Op::Mul => val1.clone() * val2.clone(),
914            Op::Div => val1.clone() / val2.clone(),
915        };
916        stack.pop();
917        stack.pop();
918        stack.pop();
919        stack.push(Token::ImmediateValue(result, span));
920    }
921}
922
923fn inline_and_fold_constant(
924    tokens: &[Token],
925    const_map: &std::collections::HashMap<String, ImmediateValue>,
926    start_idx: usize,
927) -> (Option<ImmediateValue>, usize) {
928    inline_and_fold_constant_with_map(tokens, Some(const_map), start_idx)
929}
930
931fn inline_and_fold_constant_with_map(
932    tokens: &[Token],
933    const_map: Option<&std::collections::HashMap<String, ImmediateValue>>,
934    start_idx: usize,
935) -> (Option<ImmediateValue>, usize) {
936    let mut stack: Vec<Token> = Vec::new();
937    let mut expect_number = true;
938    let mut idx = start_idx;
939
940    while idx < tokens.len() {
941        match &tokens[idx] {
942            Token::ImmediateValue(val, span) if expect_number => {
943                stack.push(Token::ImmediateValue(val.clone(), span.clone()));
944                expect_number = false;
945
946                // Immediately fold * / if top
947                if stack.len() > 2 {
948                    if let Token::BinaryOp(op, _) = &stack[stack.len() - 2] {
949                        if matches!(op, Op::Mul | Op::Div) {
950                            fold_top(&mut stack);
951                        }
952                    }
953                }
954            }
955
956            Token::Identifier(name, span) if expect_number => {
957                if let Some(const_map) = const_map {
958                    if let Some(val) = const_map.get(name) {
959                        stack.push(Token::ImmediateValue(val.clone(), span.clone()));
960                        expect_number = false;
961
962                        if stack.len() > 2 {
963                            if let Token::BinaryOp(op, _) = &stack[stack.len() - 2] {
964                                if matches!(op, Op::Mul | Op::Div) {
965                                    fold_top(&mut stack);
966                                }
967                            }
968                        }
969                    } else {
970                        return (None, idx);
971                    }
972                } else {
973                    // error out would be better here
974                    return (None, idx);
975                }
976            }
977
978            Token::BinaryOp(op, span) => {
979                match op {
980                    Op::Sub if expect_number => {
981                        // unary minus → 0 - expr
982                        stack.push(Token::ImmediateValue(ImmediateValue::Int(0), span.clone()));
983                        stack.push(Token::BinaryOp(Op::Sub, span.clone()));
984                    }
985                    _ => {
986                        stack.push(Token::BinaryOp(op.clone(), span.clone()));
987                    }
988                }
989                expect_number = true;
990            }
991
992            Token::LeftParen(span) => {
993                // Parse inside parentheses
994                let (inner_val, new_idx) =
995                    inline_and_fold_constant_with_map(tokens, const_map, idx + 1);
996                idx = new_idx;
997                if let Some(v) = inner_val {
998                    stack.push(Token::ImmediateValue(v, span.clone()));
999                    expect_number = false;
1000
1001                    if stack.len() > 2 {
1002                        if let Token::BinaryOp(op, _) = &stack[stack.len() - 2] {
1003                            if matches!(op, Op::Mul | Op::Div) {
1004                                fold_top(&mut stack);
1005                            }
1006                        }
1007                    }
1008                } else {
1009                    return (None, idx);
1010                }
1011                continue; // skip normal idx++
1012            }
1013
1014            Token::RightParen(_) => {
1015                // fold remaining + and -
1016                while stack.len() > 2 {
1017                    fold_top(&mut stack);
1018                }
1019                if let Token::ImmediateValue(v, _) = &stack[0] {
1020                    return (Some(v.clone()), idx + 1);
1021                } else {
1022                    return (None, idx + 1);
1023                }
1024            }
1025
1026            _ => {
1027                // Unexpected token, stop
1028                break;
1029            }
1030        }
1031        idx += 1;
1032    }
1033
1034    // Final fold at the end of expression
1035    while stack.len() > 2 {
1036        fold_top(&mut stack);
1037    }
1038
1039    if let Some(Token::ImmediateValue(v, _)) = stack.pop() {
1040        (Some(v), idx)
1041    } else {
1042        (None, idx)
1043    }
1044}
1045
1046pub fn parse_tokens(mut tokens: &[Token]) -> Result<ParseResult, Vec<CompileError>> {
1047    let mut ast = AST::new();
1048
1049    let mut rodata_phase = false;
1050    let mut accum_offset = 0;
1051    let mut rodata_accum_offset = 0;
1052    let mut const_map = HashMap::<String, ImmediateValue>::new();
1053    let mut label_spans = HashMap::<String, std::ops::Range<usize>>::new();
1054    let mut errors = Vec::new();
1055
1056    while !tokens.is_empty() {
1057        match &tokens[0] {
1058            Token::Directive(name, span) => match name.as_str() {
1059                "global" | "globl" => match GlobalDecl::parse(tokens) {
1060                    Ok((node, rest)) => {
1061                        ast.entry_label = Some(node.get_entry_label());
1062                        ast.nodes.push(ASTNode::GlobalDecl { global_decl: node });
1063                        tokens = rest;
1064                    }
1065                    Err(e) => {
1066                        errors.push(e);
1067                        tokens = &tokens[1..];
1068                    }
1069                },
1070                "extern" => match ExternDecl::parse(tokens) {
1071                    Ok((node, rest)) => {
1072                        ast.nodes.push(ASTNode::ExternDecl { extern_decl: node });
1073                        tokens = rest;
1074                    }
1075                    Err(e) => {
1076                        errors.push(e);
1077                        tokens = &tokens[1..];
1078                    }
1079                },
1080                "text" => {
1081                    rodata_phase = false;
1082                    tokens = &tokens[1..];
1083                }
1084                "rodata" => {
1085                    ast.nodes.push(ASTNode::RodataDecl {
1086                        rodata_decl: RodataDecl { span: span.clone() },
1087                    });
1088                    rodata_phase = true;
1089                    tokens = &tokens[1..];
1090                }
1091                "equ" => match EquDecl::parse_with_constmap(tokens, &const_map) {
1092                    Ok((node, rest)) => {
1093                        const_map.insert(node.get_name(), node.get_val());
1094                        ast.nodes.push(ASTNode::EquDecl { equ_decl: node });
1095                        tokens = rest;
1096                    }
1097                    Err(e) => {
1098                        errors.push(e);
1099                        tokens = &tokens[1..];
1100                    }
1101                },
1102                "section" => {
1103                    ast.nodes.push(ASTNode::Directive {
1104                        directive: Directive {
1105                            name: name.clone(),
1106                            args: Vec::new(),
1107                            span: span.clone(),
1108                        },
1109                    });
1110                    tokens = &tokens[1..];
1111                }
1112                _ => {
1113                    errors.push(CompileError::InvalidDirective {
1114                        directive: name.clone(),
1115                        span: span.clone(),
1116                        custom_label: None,
1117                    });
1118                    tokens = &tokens[1..];
1119                }
1120            },
1121            Token::Label(name, span) => {
1122                if rodata_phase {
1123                    match ROData::parse(tokens) {
1124                        Ok((rodata, rest)) => {
1125                            if label_spans.contains_key(name) {
1126                                let original_span =
1127                                    label_spans.get(name).cloned().unwrap_or(span.clone());
1128                                errors.push(CompileError::DuplicateLabel {
1129                                    label: name.clone(),
1130                                    span: span.clone(),
1131                                    original_span,
1132                                    custom_label: Some(LABEL_REDEFINED.to_string()),
1133                                });
1134                            } else {
1135                                label_spans.insert(name.clone(), span.clone());
1136                                if let Err(e) = rodata.verify() {
1137                                    errors.push(e);
1138                                }
1139                            }
1140                            let rodata_size = rodata.get_size();
1141                            ast.rodata_nodes.push(ASTNode::ROData {
1142                                rodata,
1143                                offset: rodata_accum_offset,
1144                            });
1145                            rodata_accum_offset += rodata_size;
1146                            tokens = rest;
1147                        }
1148                        Err(e) => {
1149                            errors.push(e);
1150                            tokens = &tokens[1..];
1151                        }
1152                    }
1153                } else {
1154                    if label_spans.contains_key(name) {
1155                        let original_span = label_spans.get(name).cloned().unwrap_or(span.clone());
1156                        errors.push(CompileError::DuplicateLabel {
1157                            label: name.clone(),
1158                            span: span.clone(),
1159                            original_span,
1160                            custom_label: Some(LABEL_REDEFINED.to_string()),
1161                        });
1162                    } else {
1163                        label_spans.insert(name.clone(), span.clone());
1164                    }
1165                    ast.nodes.push(ASTNode::Label {
1166                        label: Label {
1167                            name: name.clone(),
1168                            span: span.clone(),
1169                        },
1170                        offset: accum_offset,
1171                    });
1172                    tokens = &tokens[1..];
1173                }
1174            }
1175            Token::Opcode(_, _) => match Instruction::parse_with_constmap(tokens, &const_map) {
1176                Ok((inst, rest)) => {
1177                    let offset = accum_offset;
1178                    accum_offset += inst.get_size();
1179                    ast.nodes.push(ASTNode::Instruction {
1180                        instruction: inst,
1181                        offset,
1182                    });
1183                    tokens = rest;
1184                }
1185                Err(e) => {
1186                    errors.push(e);
1187                    tokens = &tokens[1..];
1188                }
1189            },
1190            _ => {
1191                tokens = &tokens[1..];
1192            }
1193        }
1194    }
1195
1196    if !errors.is_empty() {
1197        return Err(errors);
1198    }
1199
1200    ast.set_text_size(accum_offset);
1201    ast.set_rodata_size(rodata_accum_offset);
1202
1203    let parse_result = ast.build_program();
1204    if let Ok(parse_result) = parse_result {
1205        Ok(parse_result)
1206    } else {
1207        Err(parse_result.err().unwrap())
1208    }
1209}