use super::ir;
use super::lex;
pub(crate) fn parse(src: &str, symtab: &mut super::SymbolTable) -> Result<ir::ExprList, Error> {
let mut parser = Parser::new(src, symtab);
let exprs = parser.expr_list()?;
assert_eq!(parser.depth, 0);
Ok(exprs)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Span(u32, u32);
#[cfg(not(any(test, small_max)))]
type LiteralExponent = i32;
#[cfg(any(test, small_max))]
type LiteralExponent = i8;
impl Span {
pub(crate) fn new(start: usize, end: usize) -> Self {
assert!(start <= end);
Span(start.try_into().unwrap(), end.try_into().unwrap())
}
#[must_use]
pub fn start(self) -> usize {
self.0 as usize
}
#[must_use]
pub fn of(self, input: &str) -> &str {
&input[self.0 as usize..self.1 as usize]
}
}
impl std::ops::Add for Span {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
assert!(self.0 <= rhs.1);
Span(self.0, rhs.1)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct Error(pub ErrorKind, pub Span);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorKind {
InvalidToken,
LiteralTooLarge,
RecursionLimitExceeded,
UnexpectedEof,
UnexpectedToken,
WidthOutOfRange,
}
impl From<Error> for super::Error {
fn from(e: Error) -> Self {
Self {
kind: super::ErrorKind::Parse(e.0),
span: e.1,
}
}
}
impl std::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::InvalidToken => write!(f, "invalid token"),
Self::LiteralTooLarge => write!(f, "literal too large"),
Self::RecursionLimitExceeded => write!(f, "recursion limit exceeded"),
Self::UnexpectedEof => write!(f, "unexpected EOF"),
Self::UnexpectedToken => write!(f, "unexpected token"),
Self::WidthOutOfRange => write!(f, "bit width out of range"),
}
}
}
struct Parser<'a> {
src: &'a str,
symtab: &'a mut super::SymbolTable,
next_token: lex::Token,
pos: usize,
span: Span,
depth: usize,
}
impl<'a> Parser<'a> {
#[must_use]
fn new(src: &'a str, symtab: &'a mut super::SymbolTable) -> Self {
let next_token = lex::Lexer::new(src).next_token();
Self {
src,
symtab,
pos: next_token.len,
next_token,
span: Span::new(0, 0),
depth: 0,
}
}
fn step(&mut self) -> lex::Token {
let token = lex::Lexer::new(&self.src[self.pos..]).next_token();
self.pos += token.len;
std::mem::replace(&mut self.next_token, token)
}
fn eat(&mut self) -> lex::TokenKind {
loop {
let end = self.pos;
let token = self.step();
if !matches!(token.kind, lex::TokenKind::Whitespace) {
self.span = Span::new(end - token.len, end);
return token.kind;
}
}
}
fn peek(&mut self) -> &lex::TokenKind {
if matches!(self.next_token.kind, lex::TokenKind::Whitespace) {
let _whitespace = self.step();
}
&self.next_token.kind
}
fn token_src(&self) -> &str {
self.span.of(self.src)
}
fn err(&self, kind: ErrorKind) -> Error {
let span = self.span;
Error(kind, span)
}
fn err_eat(&mut self, kind: ErrorKind) -> Error {
self.eat();
self.err(kind)
}
fn expr_list(&mut self) -> Result<ir::ExprList, Error> {
let mut list = ir::ExprList::new();
loop {
match self.peek() {
lex::TokenKind::Eof => break,
lex::TokenKind::Semicolon => {
self.eat(); }
_ => {
let elem = self.expr()?;
list.push(elem);
}
};
}
Ok(list)
}
fn expr(&mut self) -> Result<ir::Expr, Error> {
self.expr_prec(0)
}
fn expr_prec(&mut self, min_precedence: u8) -> Result<ir::Expr, Error> {
self.depth += 1;
if self.depth > super::RECURSION_LIMIT {
return Err(self.err(ErrorKind::RecursionLimitExceeded));
}
let mut lhs = match self.eat() {
lex::TokenKind::OpenParen => {
let span_start = self.span;
let expr = self.expr()?;
let token_kind = self.eat();
let span_end = self.span;
if matches!(token_kind, lex::TokenKind::CloseParen) {
ir::Expr {
kind: expr.kind,
span: span_start + span_end,
}
} else if matches!(token_kind, lex::TokenKind::Eof) {
return Err(self.err(ErrorKind::UnexpectedEof));
} else {
assert!(matches!(token_kind, lex::TokenKind::Semicolon));
return Err(self.err(ErrorKind::UnexpectedToken));
}
}
lex::TokenKind::Sym(s) => {
let op = match s {
lex::Symbol::Minus => ir::UnOp::Neg,
lex::Symbol::Bang => ir::UnOp::Not,
_ => return Err(self.err(ErrorKind::UnexpectedToken)),
};
let span_op = self.span;
let expr = self.expr_prec(op.precedence())?;
let span = span_op + expr.span;
let kind = ir::ExprKind::Un(op, Box::new(expr));
ir::Expr { kind, span }
}
lex::TokenKind::Num(n) => {
let span_num = self.span;
ir::Expr {
kind: ir::ExprKind::Num(self.num(&n)?),
span: span_num + self.span,
}
}
lex::TokenKind::Ident => {
let span = self.span;
let kind = ir::ExprKind::Ident(self.symtab.insert(self.span.of(self.src)));
ir::Expr { kind, span }
}
lex::TokenKind::Eof => return Err(self.err(ErrorKind::UnexpectedEof)),
lex::TokenKind::Invalid => return Err(self.err(ErrorKind::InvalidToken)),
_ => return Err(self.err(ErrorKind::UnexpectedToken)),
};
loop {
match self.peek() {
lex::TokenKind::CloseParen | lex::TokenKind::Eof | lex::TokenKind::Semicolon => {
break
}
lex::TokenKind::Ty(..) => {
let ty = self.ty()?;
let span = lhs.span + self.span;
let kind = ir::ExprKind::Cast {
ty,
expr: Box::new(lhs),
};
lhs = ir::Expr { kind, span };
}
lex::TokenKind::Sym(lex::Symbol::Eq) => {
self.eat(); if let ir::ExprKind::Ident(s) = lhs.kind {
let rhs = self.expr_prec(1)?;
let span = lhs.span + self.span;
let kind = ir::ExprKind::Assign(s, rhs.into());
lhs = ir::Expr { kind, span };
} else {
return Err(self.err(ErrorKind::UnexpectedToken));
}
}
lex::TokenKind::Sym(s) => {
let op = match s {
lex::Symbol::Plus => ir::BinOp::Add,
lex::Symbol::Minus => ir::BinOp::Sub,
lex::Symbol::Star => ir::BinOp::Mul,
lex::Symbol::Star2 => ir::BinOp::Pow,
lex::Symbol::Slash => ir::BinOp::Div,
lex::Symbol::Percentage => ir::BinOp::Rem,
lex::Symbol::Ampersand => ir::BinOp::And,
lex::Symbol::Caret => ir::BinOp::Xor,
lex::Symbol::Pipe => ir::BinOp::Or,
lex::Symbol::Lt2 => ir::BinOp::Shl,
lex::Symbol::Gt2 => ir::BinOp::Shr,
_ => return Err(self.err_eat(ErrorKind::UnexpectedToken)),
};
let lfix = op.precedence();
if lfix < min_precedence {
break;
}
self.eat(); let rhs = self.expr_prec(lfix + 1)?;
let span = lhs.span + self.span;
let kind = ir::ExprKind::Bin(op, Box::new(lhs), Box::new(rhs));
lhs = ir::Expr { kind, span };
}
lex::TokenKind::Invalid => return Err(self.err_eat(ErrorKind::InvalidToken)),
_ => return Err(self.err_eat(ErrorKind::UnexpectedToken)),
}
}
self.depth -= 1;
Ok(lhs)
}
fn num(&mut self, num: &lex::Num) -> Result<ir::Num, Error> {
let src = self.token_src();
let src = if num.truncated {
&src[..src.len() - 2]
} else {
src
};
let int_start = if num.prefixed { 2 } else { 0 } + if num.infinite_digit { 3 } else { 0 };
let int_end = num.point.or(num.exp).map_or(src.len(), usize::from);
let int = &src[int_start..int_end];
let int = int.replace('_', "");
let int_len = int.len();
let int = if int.is_empty() {
ir::Int::default()
} else {
ir::Int::parse_bytes(int.as_bytes(), num.base.radix().into()).unwrap()
};
let int = if num.infinite_digit {
let bits_int = int_len * num.base.bits_per_digit() as usize;
let inf_ones = !((ir::Int::from(1) << bits_int) - ir::Int::from(1));
inf_ones | int
} else {
int
};
let frac_start = num
.point
.map(|d| {
d.checked_add(1)
.ok_or_else(|| self.err(ErrorKind::InvalidToken))
})
.transpose()?
.or(num.exp)
.map_or(src.len(), usize::from);
let frac_end = num.repeat.or(num.exp).map_or(src.len(), usize::from);
let frac = &src[frac_start..frac_end];
let frac = frac.replace('_', "");
let numer = if frac.is_empty() {
ir::Int::default()
} else {
ir::Int::parse_bytes(frac.as_bytes(), num.base.radix().into()).unwrap()
};
let denom = ir::Int::from(num.base.radix()).pow(frac.len().try_into().unwrap());
let frac = ir::Val::from((numer, denom.clone()));
let frac_repeating = if let Some(start) = num.repeat {
let repeat = &src[usize::from(start) + 1..num.exp.map_or(src.len(), usize::from) - 1];
let repeat = repeat.replace('_', "");
let n = repeat.len().try_into().unwrap();
if n > 0 {
let numer =
ir::Int::parse_bytes(repeat.as_bytes(), num.base.radix().into()).unwrap();
let denom = denom * (ir::Int::from(num.base.radix()).pow(n) - ir::Int::from(1));
ir::Val::new(numer, denom)
} else {
ir::Val::default()
}
} else {
ir::Val::default()
};
let frac = frac + frac_repeating;
let exp: LiteralExponent = if let Some(e) = num.exp {
let exp = &src[e as usize + 1..];
let exp = exp.replace('_', "");
assert_eq!(num.base, super::Base::Dec);
if let Ok(e) = exp.parse() {
e
} else {
return Err(self.err(ErrorKind::WidthOutOfRange));
}
} else {
0
};
#[allow(clippy::useless_conversion)]
let exp = ir::Val::from(ir::Int::from(10)).pow(exp.into());
let val = (ir::Val::from_integer(int) + frac) * exp;
let ty = self.ty()?;
ir::Num::new(val)
.ok_or_else(|| self.err(ErrorKind::LiteralTooLarge))
.map(|v| v.with_ty(ty))
}
fn ty(&mut self) -> Result<ir::Ty, Error> {
let ty = if matches!(self.peek(), lex::TokenKind::Ty(..)) {
if let lex::TokenKind::Ty(ty) = self.eat() {
ty
} else {
unreachable!()
}
} else {
return Ok(ir::Ty::default());
};
let signed = ty.prefix.map(lex::TyPrefix::signed);
let fixed_point = ty.prefix.map_or(true, lex::TyPrefix::fixed_point);
let width_start = usize::from(ty.has_apostrophe) + ty.prefix.map_or(0, lex::TyPrefix::len);
let width_str = &self.token_src()[width_start..];
let mut widths = width_str.split('.');
let w = widths
.next()
.and_then(|s| if s.is_empty() { None } else { Some(s) })
.map(str::parse)
.transpose()
.map_err(|_| self.err(ErrorKind::WidthOutOfRange))?;
let wf = if fixed_point {
widths
.next()
.map(str::parse)
.transpose()
.map_err(|_| self.err(ErrorKind::WidthOutOfRange))?
} else {
assert!(widths.next().is_none());
Some(0)
};
ir::Ty::new(signed, w, wf).ok_or_else(|| self.err(ErrorKind::WidthOutOfRange))
}
}
#[cfg(test)]
mod test {
use crate::ir;
use crate::SymbolTable;
use ir::BinOp::*;
use ir::ExprKind::*;
use ir::Num;
use ir::UnOp::*;
impl ir::ExprKind {
fn span(self, start: usize, end: usize) -> ir::Expr {
ir::Expr {
kind: self,
span: super::Span::new(start, end),
}
}
}
impl super::ErrorKind {
pub fn span(self, start: usize, end: usize) -> super::Error {
super::Error(self, super::Span::new(start, end))
}
}
use super::ErrorKind::*;
macro_rules! test_parse {
($src:expr $(, $($expected:expr),*)? $(,)?) => {
let mut st = SymbolTable::default();
test_parse!(&mut st; $src $(, $($expected),*)?);
};
($st:expr; $src:expr $(, $($expected:expr),*)? $(,)?) => {
let actual = super::parse($src, $st).unwrap();
let expected = &[$($($expected),*)?];
assert_eq!(actual, expected, "{}", $src);
};
}
#[test]
fn expr_list() {
test_parse!("");
test_parse!(";");
test_parse!("1;2", Num(Num::n(1)).span(0, 1), Num(Num::n(2)).span(2, 3));
test_parse!(";1", Num(Num::n(1)).span(1, 2));
test_parse!("1;", Num(Num::n(1)).span(0, 1));
test_parse!("1;;2", Num(Num::n(1)).span(0, 1), Num(Num::n(2)).span(3, 4));
}
#[test]
fn expr_int() {
test_parse!("100", Num(Num::n(100)).span(0, 3));
test_parse!("22u", Num(Num::u(22)).span(0, 3));
test_parse!("22'u", Num(Num::u(22)).span(0, 4));
test_parse!("0b1101u", Num(Num::u(0b1101)).span(0, 7));
test_parse!("0xffi8", Num(Num::i(0xff).w(8)).span(0, 6));
test_parse!(
"0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff",
Num(Num::new(ir::Val::from_integer(
(ir::Int::from(1) << 255) - ir::Int::from(1)
))
.unwrap())
.span(0, 81),
);
}
#[test]
fn expr_int_inf() {
test_parse!("0b(1)010", Num(Num::n(-6)).span(0, 8));
test_parse!("0o(7)123", Num(Num::n(-429)).span(0, 8));
test_parse!("0x(f)abc", Num(Num::n(-1348)).span(0, 8));
}
#[test]
fn expr_fix() {
test_parse!("0b1101.10", Num(Num::nd(0b1101_10, 0b1_00)).span(0, 9));
test_parse!("10.75", Num(Num::nd(10_75, 1_00)).span(0, 5));
test_parse!("0xa.cq.2", Num(Num::q(0xa_c, 0x1_0).wf(2)).span(0, 8));
test_parse!("0b.1uq0.1", Num(Num::uq(1, 2).w(0).wf(1)).span(0, 9));
test_parse!("0xa.cuq.2", Num(Num::uq(0xa_c, 0x1_0).wf(2)).span(0, 9));
test_parse!("0b1q1.0", Num(Num::i(1).w(1).wf(0)).span(0, 7));
test_parse!(
"0b1101.1010..",
Num(Num::nd(0b1101_1010, 0b1_0000)).span(0, 13)
);
}
#[test]
fn expr_fix_repeat() {
test_parse!("1.(1)", Num(Num::nd(10, 9)).span(0, 5));
test_parse!("1.0(1)", Num(Num::nd(91, 90)).span(0, 6));
test_parse!("1.(01)", Num(Num::nd(100, 99)).span(0, 6));
test_parse!("0b.0(0011)", Num(Num::nd(1, 10)).span(0, 10));
test_parse!("0.(9)", Num(Num::n(1)).span(0, 5));
test_parse!("0.(999)", Num(Num::n(1)).span(0, 7));
test_parse!("0._(_9_9_)", Num(Num::n(1)).span(0, 10));
test_parse!("0.(_)", Num(Num::n(0)).span(0, 5));
test_parse!("0.()", Num(Num::n(0)).span(0, 4));
}
#[test]
fn expr_ident() {
let mut st = SymbolTable::default();
test_parse!(&mut st; "a", Ident(st.insert("a")).span(0, 1));
test_parse!(
&mut st;
"5 + abc",
Bin(
Add,
Num(Num::n(5)).span(0, 1).into(),
Ident(st.insert("abc")).span(4, 7).into()
)
.span(0, 7)
);
}
#[test]
fn expr_assign() {
let mut st = SymbolTable::default();
test_parse!(
&mut st;
"ab = 5",
Assign(st.insert("ab"), Num(Num::n(5)).span(5, 6).into()).span(0, 6)
);
test_parse!(
&mut st;
"ab = 5 + ab",
Assign(
st.insert("ab"),
Bin(
Add,
Num(Num::n(5)).span(5, 6).into(),
Ident(st.insert("ab")).span(9, 11).into()
)
.span(5, 11)
.into()
)
.span(0, 11)
);
}
#[test]
fn expr_un() {
test_parse!("!22", Un(Not, Num(Num::n(22)).span(1, 3).into()).span(0, 3));
test_parse!("-3", Un(Neg, Num(Num::n(3)).span(1, 2).into()).span(0, 2));
}
#[test]
fn expr_bin() {
test_parse!(
"1 + 2",
Bin(
Add,
Num(Num::n(1)).span(0, 1).into(),
Num(Num::n(2)).span(4, 5).into()
)
.span(0, 5)
);
test_parse!(
"100^0x4",
Bin(
Xor,
Num(Num::n(100)).span(0, 3).into(),
Num(Num::n(4)).span(4, 7).into()
)
.span(0, 7)
);
test_parse!(
"1+2+3",
Bin(
Add,
Box::new(
Bin(
Add,
Num(Num::n(1)).span(0, 1).into(),
Num(Num::n(2)).span(2, 3).into(),
)
.span(0, 3)
),
Num(Num::n(3)).span(4, 5).into(),
)
.span(0, 5)
);
test_parse!(
"1 + 2*3",
Bin(
Add,
Num(Num::n(1)).span(0, 1).into(),
Box::new(
Bin(
Mul,
Num(Num::n(2)).span(4, 5).into(),
Num(Num::n(3)).span(6, 7).into()
)
.span(4, 7)
),
)
.span(0, 7)
);
test_parse!(
"5**2",
Bin(
Pow,
Num(Num::n(5)).span(0, 1).into(),
Num(Num::n(2)).span(3, 4).into(),
)
.span(0, 4)
);
}
#[test]
fn expr_paren() {
test_parse!("((((((1))))))", Num(Num::n(1)).span(0, 13));
test_parse!(
"(1+2)*3",
Bin(
Mul,
Box::new(
Bin(
Add,
Num(Num::n(1)).span(1, 2).into(),
Num(Num::n(2)).span(3, 4).into()
)
.span(0, 5)
),
Num(Num::n(3)).span(6, 7).into(),
)
.span(0, 7)
);
}
#[test]
fn expr_cast() {
test_parse!(
"5u8'8",
Cast {
ty: ir::Ty::default().w(8),
expr: Box::new(Num(Num::u(5).w(8).wf(0)).span(0, 3)),
}
.span(0, 5)
);
test_parse!(
"5i8'i8",
Cast {
ty: ir::Ty::default().s().w(8).wf(0),
expr: Box::new(Num(Num::i(5).w(8).wf(0)).span(0, 3)),
}
.span(0, 6)
);
test_parse!(
"5i8'u8",
Cast {
ty: ir::Ty::default().u().w(8).wf(0),
expr: Box::new(Num(Num::i(5).w(8).wf(0)).span(0, 3)),
}
.span(0, 6)
);
}
#[test]
fn expr_cast_f() {
test_parse!(
"5.5q7.8'8",
Cast {
ty: ir::Ty::default().w(8),
expr: Box::new(Num(Num::q(11, 2).w(7).wf(8)).span(0, 7)),
}
.span(0, 9)
);
test_parse!(
"(1.5)'uq1.2",
Cast {
ty: ir::Ty::default().u().w(1).wf(2),
expr: Box::new(Num(Num::nd(3, 2)).span(0, 5)),
}
.span(0, 11)
);
}
#[test]
fn expr_exp() {
test_parse!("1e1", Num(Num::n(10)).span(0, 3));
test_parse!("0d1e1", Num(Num::n(10)).span(0, 5));
test_parse!("1e0", Num(Num::n(1)).span(0, 3));
test_parse!("0.01e3", Num(Num::n(10)).span(0, 6));
test_parse!("5e12", Num(Num::n(5_000_000_000_000)).span(0, 4));
test_parse!("5e_1_2_", Num(Num::n(5_000_000_000_000)).span(0, 7));
test_parse!("5e-3", Num(Num::nd(1, 200)).span(0, 4));
test_parse!("1e-9", Num(Num::nd(1, 1_000_000_000)).span(0, 4));
test_parse!("1e-12", Num(Num::nd(1, 1_000_000_000_000)).span(0, 5));
test_parse!("1.5(123)e3", Num(Num::nd(503600, 333)).span(0, 10));
test_parse!("1e-_1", Num(Num::nd(1, 10)).span(0, 5));
}
macro_rules! test_err {
($src:expr, $expected:expr $(,)?) => {
let mut st = SymbolTable::default();
let actual = super::parse($src, &mut st);
let expected = Err($expected);
assert_eq!(actual, expected, "{}", $src);
};
}
#[test]
fn trailing() {
test_err!("5 + 6)", UnexpectedToken.span(5, 6));
test_err!("0)", UnexpectedToken.span(1, 2));
}
#[test]
fn invalid_sym() {
test_err!("*5", UnexpectedToken.span(0, 1));
test_err!("#5", InvalidToken.span(0, 1));
test_err!("5 ! 6", UnexpectedToken.span(2, 3));
test_err!("5 # 6", InvalidToken.span(2, 3));
}
#[test]
fn empty_grouping() {
test_err!("()", UnexpectedToken.span(1, 2));
}
#[test]
fn unclosed_paren() {
test_err!("(", UnexpectedEof.span(1, 1));
test_err!("((((1)))", UnexpectedEof.span(8, 8));
test_err!("(5", UnexpectedEof.span(2, 2));
test_err!("(5;", UnexpectedToken.span(2, 3));
}
#[test]
fn unopened_paren() {
test_err!(")", UnexpectedToken.span(0, 1));
}
#[test]
fn invalid_op() {
test_err!("5 ++ 2", UnexpectedToken.span(3, 4));
test_err!("+5", UnexpectedToken.span(0, 1));
test_err!("5+", UnexpectedEof.span(2, 2));
test_err!("5!5", UnexpectedToken.span(1, 2));
}
#[test]
fn invalid_width() {
test_err!("5i0", WidthOutOfRange.span(1, 3));
test_err!("5q0.0", WidthOutOfRange.span(1, 5));
test_err!("5i256", WidthOutOfRange.span(1, 5));
test_err!("5q0.256", WidthOutOfRange.span(1, 7));
test_err!("1q255.1", WidthOutOfRange.span(1, 7));
}
#[test]
fn invalid_width_exp() {
let src = format!("1e{}", super::LiteralExponent::MIN);
let val = Num(Num::new(ir::Val::new(
1.into(),
ir::Int::from(10).pow(
i32::from(super::LiteralExponent::MIN)
.abs()
.try_into()
.unwrap(),
),
))
.unwrap())
.span(0, src.len());
test_parse!(&src, val);
let src = format!("1e{}", i64::from(super::LiteralExponent::MIN) - 1i64);
test_err!(&src, WidthOutOfRange.span(0, src.len()));
let src = format!("1e{}", super::LiteralExponent::MAX);
test_err!(&src, LiteralTooLarge.span(0, src.len()));
let src = format!("1e{}", i64::from(super::LiteralExponent::MAX) + 1i64);
test_err!(&src, WidthOutOfRange.span(0, src.len()));
}
#[test]
fn invalid_value() {
test_err!(
"0xffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff_ffff",
LiteralTooLarge.span(0, 81),
);
}
#[test]
fn invalid_token() {
test_err!("ยค", InvalidToken.span(0, 2));
}
#[test]
fn invalid_token_decimal_point_long() {
const MAX: usize = crate::lex::W::MAX as usize;
test_parse!(
&format!("{}.1", "0".repeat(MAX - 1)),
Num(Num::nd(1, 10)).span(0, MAX + 1)
);
test_err!(
&format!("{}.1", "0".repeat(MAX)),
InvalidToken.span(0, MAX + 2),
);
test_err!(
&format!("{}.1", "0".repeat(MAX + 1)),
InvalidToken.span(0, MAX + 1),
);
}
#[test]
fn invalid_assign() {
test_err!("6 = 5", UnexpectedToken.span(2, 3));
}
}