Skip to main content

cambridge_asm/parse/
lexer.rs

1// Copyright (c) 2021 Saadi Save
2// This Source Code Form is subject to the terms of the Mozilla Public
3// License, v. 2.0. If a copy of the MPL was not distributed with this
4// file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6use crate::inst::Op;
7use logos::{Lexer, Logos};
8use std::{collections::HashMap, fmt::Debug, num::ParseIntError, ops::Range};
9use thiserror::Error;
10
11fn parse_num(lex: &mut Lexer<Token>) -> Result<usize, ErrorKind> {
12    let src = if lex.slice().as_bytes()[0] == b'#' {
13        &lex.slice()[1..]
14    } else {
15        lex.slice()
16    };
17
18    let res = match src.as_bytes()[0] {
19        b'b' | b'B' => usize::from_str_radix(&src[1..], 2),
20        b'x' | b'X' | b'&' => usize::from_str_radix(&src[1..], 16),
21        b'o' | b'O' => usize::from_str_radix(&src[1..], 8),
22        _ => src.parse(),
23    }?;
24
25    Ok(res)
26}
27
28fn pop_parens(lex: &mut Lexer<Token>) -> String {
29    let mut chars = lex.slice().chars();
30    chars.next();
31    chars.next_back();
32    chars.collect()
33}
34
35#[derive(Default, Error, Debug, Clone, PartialEq)]
36pub enum ErrorKind {
37    #[error("Invalid integer format")]
38    ParseIntError(#[from] ParseIntError),
39    #[error("Syntax error")]
40    #[default]
41    SyntaxError,
42    #[error("Invalid opcode `{0}`")]
43    InvalidOpcode(String),
44    #[error("Invalid operand")]
45    InvalidOperand,
46}
47
48pub type ErrorMap = HashMap<Span, ErrorKind>;
49
50pub type ParseError = WithSpan<ErrorKind>;
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub struct LinearMemory {
54    pub init: usize,
55    pub len: usize,
56}
57
58impl LinearMemory {
59    pub(self) fn from_lexer(lexer: &mut Lexer<Token>) -> Self {
60        Self::from_str(lexer.slice())
61    }
62
63    pub(self) fn from_str(s: &str) -> Self {
64        let mut decl = s.trim_matches(|c| c == '[' || c == ']').split(';');
65
66        let init = decl.next().unwrap().parse().unwrap();
67        let len = decl.next().unwrap().parse().unwrap();
68
69        Self { init, len }
70    }
71}
72
73#[derive(Logos, Debug, Clone, PartialEq, Eq)]
74#[logos(skip r"[ \t]")]
75#[logos(error = ErrorKind)]
76pub enum Token {
77    #[regex(r"//[^\r\n]*", logos::skip)]
78    Comment,
79
80    #[regex(r"\w*", |lex| lex.slice().to_string(), priority = 0)]
81    Text(String),
82
83    #[token(":")]
84    Colon,
85
86    #[token(",")]
87    Comma,
88
89    #[regex("r[0-9][0-9]?", |lex| lex.slice()[1..].parse())]
90    Gpr(usize),
91
92    #[regex("#[&xXoObB][0-9a-fA-F]+", parse_num)]
93    #[regex("#[0-9]+", parse_num)]
94    Literal(usize),
95
96    #[regex("[xXoObB][0-9a-fA-F]+", parse_num)]
97    #[regex("[0-9]+", parse_num)]
98    BareNumber(usize),
99
100    #[regex(r"\(\w*\)", pop_parens)]
101    Indirect(String),
102
103    #[regex(r"(?:\r\n)|\n")]
104    Newline,
105
106    #[regex(r"\[[0-9]+;[0-9]+\]", LinearMemory::from_lexer)]
107    LinearMemory(LinearMemory),
108}
109
110impl From<Token> for Op {
111    fn from(t: Token) -> Self {
112        match t {
113            Token::BareNumber(addr) => Op::Addr(addr),
114            Token::Gpr(r) => Op::Gpr(r),
115            Token::Literal(lit) => Op::Literal(lit),
116            Token::Text(txt) => match txt.to_lowercase().as_str() {
117                "acc" => Op::Acc,
118                "cmp" => Op::Cmp,
119                "ix" => Op::Ix,
120                "ar" => Op::Ar,
121                _ => Op::Fail(txt),
122            },
123            Token::Indirect(s) => Op::Indirect(Box::new(Op::from(s))),
124            _ => unreachable!(),
125        }
126    }
127}
128
129pub type Span = Range<usize>;
130
131pub type WithSpan<T> = (Span, T);
132
133#[derive(Debug, Clone)]
134pub struct TokensWithError<'a>(pub Lexer<'a, Token>);
135
136impl TokensWithError<'_> {
137    pub fn lines(mut self) -> (Vec<Vec<WithSpan<Token>>>, ErrorMap) {
138        let mut errors = ErrorMap::new();
139        let acc = self.by_ref().fold(vec![Vec::new()], |mut acc, (r, t)| {
140            match t {
141                Ok(Token::Newline) => {
142                    acc.push(Vec::new());
143                }
144                Ok(t) => {
145                    acc.last_mut().unwrap().push((r, t));
146                }
147                Err(e) => {
148                    errors.entry(r).or_insert(e);
149                }
150            }
151
152            acc
153        });
154
155        (acc, errors)
156    }
157}
158
159impl Iterator for TokensWithError<'_> {
160    type Item = WithSpan<Result<Token, ErrorKind>>;
161
162    fn next(&mut self) -> Option<Self::Item> {
163        self.0.next().map(|token| (self.0.span(), token))
164    }
165}