adding '<op>=' syntax

This commit is contained in:
mlokr 2024-05-15 10:37:39 +02:00
parent 70955c1792
commit 3c09a5f23e
6 changed files with 166 additions and 56 deletions

View file

@ -1,4 +1,3 @@
Type := struct { Type := struct {
brah: int, brah: int,
blah: int, blah: int,

View file

@ -12,7 +12,7 @@ fib := fn(n: int): int {
c := a + b; c := a + b;
a = b; a = b;
b = c; b = c;
n = n - 1; n -= 1;
stack_reclamation_edge_case := 0; stack_reclamation_edge_case := 0;

View file

@ -724,7 +724,7 @@ impl<'a> Codegen<'a> {
match *expr { match *expr {
E::Ident { id, .. } if ident::is_null(id) => id, E::Ident { id, .. } if ident::is_null(id) => id,
E::UnOp { E::UnOp {
op: T::Star, val, .. op: T::Mul, val, ..
} => { } => {
let ty = self.ty(val); let ty = self.ty(val);
self.alloc_pointer(ty) self.alloc_pointer(ty)
@ -918,7 +918,7 @@ impl<'a> Codegen<'a> {
Some(Value { ty, loc }) Some(Value { ty, loc })
} }
E::UnOp { E::UnOp {
op: T::Amp, op: T::Band,
val, val,
pos, pos,
} => { } => {
@ -953,7 +953,7 @@ impl<'a> Codegen<'a> {
}) })
} }
E::UnOp { E::UnOp {
op: T::Star, op: T::Mul,
val, val,
pos, pos,
} => { } => {
@ -1198,7 +1198,7 @@ impl<'a> Codegen<'a> {
self.display_ty(right.ty) self.display_ty(right.ty)
); );
if matches!(op, T::Plus | T::Minus) { if matches!(op, T::Add | T::Sub) {
let min_size = lsize.min(rsize); let min_size = lsize.min(rsize);
if bt::is_signed(ty) && min_size < size { if bt::is_signed(ty) && min_size < size {
let operand = if lsize < rsize { lhs.0 } else { rhs.0 }; let operand = if lsize < rsize { lhs.0 } else { rhs.0 };
@ -1280,16 +1280,16 @@ impl<'a> Codegen<'a> {
use instrs as i; use instrs as i;
Some( Some(
match op { match op {
T::Plus => [i::add8, i::add16, i::add32, i::add64], T::Add => [i::add8, i::add16, i::add32, i::add64],
T::Minus => [i::sub8, i::sub16, i::sub32, i::sub64], T::Sub => [i::sub8, i::sub16, i::sub32, i::sub64],
T::Star => [i::mul8, i::mul16, i::mul32, i::mul64], T::Mul => [i::mul8, i::mul16, i::mul32, i::mul64],
T::FSlash if signed => [ T::Div if signed => [
|a, b, c| i::dirs8(a, ZERO, b, c), |a, b, c| i::dirs8(a, ZERO, b, c),
|a, b, c| i::dirs16(a, ZERO, b, c), |a, b, c| i::dirs16(a, ZERO, b, c),
|a, b, c| i::dirs32(a, ZERO, b, c), |a, b, c| i::dirs32(a, ZERO, b, c),
|a, b, c| i::dirs64(a, ZERO, b, c), |a, b, c| i::dirs64(a, ZERO, b, c),
], ],
T::FSlash => [ T::Div => [
|a, b, c| i::diru8(a, ZERO, b, c), |a, b, c| i::diru8(a, ZERO, b, c),
|a, b, c| i::diru16(a, ZERO, b, c), |a, b, c| i::diru16(a, ZERO, b, c),
|a, b, c| i::diru32(a, ZERO, b, c), |a, b, c| i::diru32(a, ZERO, b, c),

View file

@ -29,8 +29,8 @@ macro_rules! gen_token_kind {
$punkt:ident = $punkt_lit:literal, $punkt:ident = $punkt_lit:literal,
)* )*
#[ops] $( #[ops] $(
#[prec = $prec:literal] $( #[$prec:ident] $(
$op:ident = $op_lit:literal, $op:ident = $op_lit:literal $(=> $assign:ident)?,
)* )*
)* )*
} }
@ -42,7 +42,8 @@ macro_rules! gen_token_kind {
$( Self::$keyword => stringify!($keyword_lit), )* $( Self::$keyword => stringify!($keyword_lit), )*
$( Self::$punkt => stringify!($punkt_lit), )* $( Self::$punkt => stringify!($punkt_lit), )*
$($( Self::$op => $op_lit, )*)* $($( Self::$op => $op_lit,
$(Self::$assign => concat!($op_lit, "="),)?)*)*
}; };
f.write_str(s) f.write_str(s)
} }
@ -52,9 +53,10 @@ macro_rules! gen_token_kind {
#[inline(always)] #[inline(always)]
pub fn precedence(&self) -> Option<u8> { pub fn precedence(&self) -> Option<u8> {
Some(match self { Some(match self {
$($(Self::$op)|* => $prec,)* $($(Self::$op => ${ignore($prec)} ${index(1)},
$(Self::$assign => 0,)?)*)*
_ => return None, _ => return None,
}) } + 1)
} }
#[inline(always)] #[inline(always)]
@ -64,6 +66,13 @@ macro_rules! gen_token_kind {
_ => Self::Ident, _ => Self::Ident,
} }
} }
pub fn assign_op(&self) -> Option<Self> {
Some(match self {
$($($(Self::$assign => Self::$op,)?)*)*
_ => return None,
})
}
} }
#[derive(Debug, PartialEq, Eq, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
@ -71,7 +80,7 @@ macro_rules! gen_token_kind {
$( $pattern, )* $( $pattern, )*
$( $keyword, )* $( $keyword, )*
$( $punkt, )* $( $punkt, )*
$($( $op, )*)* $($( $op, $($assign,)? )*)*
} }
}; };
} }
@ -106,24 +115,37 @@ gen_token_kind! {
Ctor = ".{", Ctor = ".{",
Tupl = ".(", Tupl = ".(",
#[ops] #[ops]
#[prec = 1] #[prec]
Decl = ":=", Decl = ":=",
Assign = "=", Assign = "=",
#[prec = 21] #[prec]
Or = "||",
#[prec]
And = "&&",
#[prec]
Bor = "|" => BorAss,
#[prec]
Xor = "^" => XorAss,
#[prec]
Band = "&" => BandAss,
#[prec]
Eq = "==",
Ne = "!=",
#[prec]
Le = "<=", Le = "<=",
Ge = ">=", Ge = ">=",
Lt = "<", Lt = "<",
Gt = ">", Gt = ">",
Eq = "==", #[prec]
Ne = "!=", Shl = "<<" => ShlAss,
#[prec = 22] Shr = ">>" => ShrAss,
Amp = "&", #[prec]
#[prec = 23] Add = "+" => AddAss,
Plus = "+", Sub = "-" => SubAss,
Minus = "-", #[prec]
#[prec = 24] Mul = "*" => MulAss,
Star = "*", Div = "/" => DivAss,
FSlash = "/", Mod = "%" => ModAss,
} }
} }
@ -155,11 +177,92 @@ impl<'a> Lexer<'a> {
} }
pub fn next(&mut self) -> Token { pub fn next(&mut self) -> Token {
Iterator::next(self).unwrap_or(Token { use TokenKind as T;
kind: TokenKind::Eof, loop {
start: self.pos, let mut start = self.pos;
let Some(c) = self.advance() else {
return Token {
kind: T::Eof,
start,
end: self.pos, end: self.pos,
}) };
};
let kind = match c {
b'\n' | b'\r' | b'\t' | b' ' => continue,
b'0'..=b'9' => {
while let Some(b'0'..=b'9') = self.peek() {
self.advance();
}
T::Number
}
c @ (b'a'..=b'z' | b'A'..=b'Z' | b'_' | b'@') => {
while let Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_') = self.peek() {
self.advance();
}
if c == b'@' {
start += 1;
T::Driective
} else {
let ident = &self.bytes[start as usize..self.pos as usize];
T::from_ident(ident)
}
}
b':' if self.advance_if(b'=') => T::Decl,
b':' => T::Colon,
b',' => T::Comma,
b'.' if self.advance_if(b'{') => T::Ctor,
b'.' if self.advance_if(b'(') => T::Tupl,
b'.' => T::Dot,
b';' => T::Semi,
b'!' if self.advance_if(b'=') => T::Ne,
b'=' if self.advance_if(b'=') => T::Eq,
b'=' => T::Assign,
b'<' if self.advance_if(b'=') => T::Le,
b'<' if self.advance_if(b'<') => match self.advance_if(b'=') {
true => T::ShlAss,
false => T::Shl,
},
b'<' => T::Lt,
b'>' if self.advance_if(b'=') => T::Ge,
b'>' if self.advance_if(b'>') => match self.advance_if(b'=') {
true => T::ShrAss,
false => T::Shr,
},
b'>' => T::Gt,
b'+' if self.advance_if(b'=') => T::AddAss,
b'+' => T::Add,
b'-' if self.advance_if(b'=') => T::SubAss,
b'-' => T::Sub,
b'*' if self.advance_if(b'=') => T::MulAss,
b'*' => T::Mul,
b'/' if self.advance_if(b'=') => T::DivAss,
b'/' => T::Div,
b'%' if self.advance_if(b'=') => T::ModAss,
b'%' => T::Mod,
b'&' if self.advance_if(b'=') => T::BandAss,
b'&' if self.advance_if(b'&') => T::And,
b'&' => T::Band,
b'^' if self.advance_if(b'=') => T::XorAss,
b'^' => T::Xor,
b'|' if self.advance_if(b'=') => T::BorAss,
b'|' if self.advance_if(b'|') => T::Or,
b'|' => T::Bor,
b'(' => T::LParen,
b')' => T::RParen,
b'{' => T::LBrace,
b'}' => T::RBrace,
_ => T::Error,
};
return Token {
kind,
start,
end: self.pos,
};
}
} }
fn advance_if(&mut self, arg: u8) -> bool { fn advance_if(&mut self, arg: u8) -> bool {
@ -232,11 +335,11 @@ impl<'a> Iterator for Lexer<'a> {
b'<' => T::Lt, b'<' => T::Lt,
b'>' if self.advance_if(b'=') => T::Ge, b'>' if self.advance_if(b'=') => T::Ge,
b'>' => T::Gt, b'>' => T::Gt,
b'+' => T::Plus, b'+' => T::Add,
b'-' => T::Minus, b'-' => T::Sub,
b'*' => T::Star, b'*' => T::Mul,
b'/' => T::FSlash, b'/' => T::Div,
b'&' => T::Amp, b'&' => T::Band,
b'(' => T::LParen, b'(' => T::LParen,
b')' => T::RParen, b')' => T::RParen,
b'{' => T::LBrace, b'{' => T::LBrace,

View file

@ -74,7 +74,7 @@ impl<'a, 'b> Parser<'a, 'b> {
self.bin_expr(left, 0) self.bin_expr(left, 0)
} }
fn bin_expr(&mut self, mut left: Expr<'a>, min_prec: u8) -> Expr<'a> { fn bin_expr(&mut self, mut fold: Expr<'a>, min_prec: u8) -> Expr<'a> {
loop { loop {
let Some(prec) = self.token.kind.precedence() else { let Some(prec) = self.token.kind.precedence() else {
break; break;
@ -87,14 +87,22 @@ impl<'a, 'b> Parser<'a, 'b> {
let op = self.next().kind; let op = self.next().kind;
let right = self.unit_expr(); let right = self.unit_expr();
let right = self.bin_expr(right, prec); let right = self.bin_expr(right, prec);
left = Expr::BinOp { let right = &*self.arena.alloc(right);
left: self.arena.alloc(left), let left = &*self.arena.alloc(fold);
if let Some(op) = op.assign_op() {
let right = Expr::BinOp { left, op, right };
fold = Expr::BinOp {
left,
op: TokenKind::Assign,
right: self.arena.alloc(right), right: self.arena.alloc(right),
op,
}; };
} else {
fold = Expr::BinOp { left, right, op };
}
} }
left fold
} }
fn try_resolve_builtin(name: &str) -> Option<Ident> { fn try_resolve_builtin(name: &str) -> Option<Ident> {
@ -220,7 +228,7 @@ impl<'a, 'b> Parser<'a, 'b> {
}, },
body: self.ptr_expr(), body: self.ptr_expr(),
}, },
T::Amp | T::Star => E::UnOp { T::Band | T::Mul => E::UnOp {
pos: token.start, pos: token.start,
op: token.kind, op: token.kind,
val: self.ptr_unit_expr(), val: self.ptr_unit_expr(),

View file

@ -8,23 +8,23 @@ Ident "int"
LBrace "{" LBrace "{"
Return "return" Return "return"
Number "10" Number "10"
Minus "-" Sub "-"
Number "20" Number "20"
FSlash "/" Div "/"
Number "2" Number "2"
Plus "+" Add "+"
Number "4" Number "4"
Star "*" Mul "*"
LParen "(" LParen "("
Number "2" Number "2"
Plus "+" Add "+"
Number "2" Number "2"
RParen ")" RParen ")"
Minus "-" Sub "-"
Number "4" Number "4"
Star "*" Mul "*"
Number "4" Number "4"
Plus "+" Add "+"
Number "1" Number "1"
Semi ";" Semi ";"
RBrace "}" RBrace "}"