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 {
brah: int,
blah: int,

View file

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

View file

@ -724,7 +724,7 @@ impl<'a> Codegen<'a> {
match *expr {
E::Ident { id, .. } if ident::is_null(id) => id,
E::UnOp {
op: T::Star, val, ..
op: T::Mul, val, ..
} => {
let ty = self.ty(val);
self.alloc_pointer(ty)
@ -918,7 +918,7 @@ impl<'a> Codegen<'a> {
Some(Value { ty, loc })
}
E::UnOp {
op: T::Amp,
op: T::Band,
val,
pos,
} => {
@ -953,7 +953,7 @@ impl<'a> Codegen<'a> {
})
}
E::UnOp {
op: T::Star,
op: T::Mul,
val,
pos,
} => {
@ -1198,7 +1198,7 @@ impl<'a> Codegen<'a> {
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);
if bt::is_signed(ty) && min_size < size {
let operand = if lsize < rsize { lhs.0 } else { rhs.0 };
@ -1280,16 +1280,16 @@ impl<'a> Codegen<'a> {
use instrs as i;
Some(
match op {
T::Plus => [i::add8, i::add16, i::add32, i::add64],
T::Minus => [i::sub8, i::sub16, i::sub32, i::sub64],
T::Star => [i::mul8, i::mul16, i::mul32, i::mul64],
T::FSlash if signed => [
T::Add => [i::add8, i::add16, i::add32, i::add64],
T::Sub => [i::sub8, i::sub16, i::sub32, i::sub64],
T::Mul => [i::mul8, i::mul16, i::mul32, i::mul64],
T::Div if signed => [
|a, b, c| i::dirs8(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::dirs64(a, ZERO, b, c),
],
T::FSlash => [
T::Div => [
|a, b, c| i::diru8(a, ZERO, b, c),
|a, b, c| i::diru16(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,
)*
#[ops] $(
#[prec = $prec:literal] $(
$op:ident = $op_lit:literal,
#[$prec:ident] $(
$op:ident = $op_lit:literal $(=> $assign:ident)?,
)*
)*
}
@ -42,7 +42,8 @@ macro_rules! gen_token_kind {
$( Self::$keyword => stringify!($keyword_lit), )*
$( Self::$punkt => stringify!($punkt_lit), )*
$($( Self::$op => $op_lit, )*)*
$($( Self::$op => $op_lit,
$(Self::$assign => concat!($op_lit, "="),)?)*)*
};
f.write_str(s)
}
@ -52,9 +53,10 @@ macro_rules! gen_token_kind {
#[inline(always)]
pub fn precedence(&self) -> Option<u8> {
Some(match self {
$($(Self::$op)|* => $prec,)*
$($(Self::$op => ${ignore($prec)} ${index(1)},
$(Self::$assign => 0,)?)*)*
_ => return None,
})
} + 1)
}
#[inline(always)]
@ -64,6 +66,13 @@ macro_rules! gen_token_kind {
_ => Self::Ident,
}
}
pub fn assign_op(&self) -> Option<Self> {
Some(match self {
$($($(Self::$assign => Self::$op,)?)*)*
_ => return None,
})
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@ -71,7 +80,7 @@ macro_rules! gen_token_kind {
$( $pattern, )*
$( $keyword, )*
$( $punkt, )*
$($( $op, )*)*
$($( $op, $($assign,)? )*)*
}
};
}
@ -104,26 +113,39 @@ gen_token_kind! {
Comma = ",",
Dot = ".",
Ctor = ".{",
Tupl = ".(",
Tupl = ".(",
#[ops]
#[prec = 1]
#[prec]
Decl = ":=",
Assign = "=",
#[prec = 21]
#[prec]
Or = "||",
#[prec]
And = "&&",
#[prec]
Bor = "|" => BorAss,
#[prec]
Xor = "^" => XorAss,
#[prec]
Band = "&" => BandAss,
#[prec]
Eq = "==",
Ne = "!=",
#[prec]
Le = "<=",
Ge = ">=",
Lt = "<",
Gt = ">",
Eq = "==",
Ne = "!=",
#[prec = 22]
Amp = "&",
#[prec = 23]
Plus = "+",
Minus = "-",
#[prec = 24]
Star = "*",
FSlash = "/",
#[prec]
Shl = "<<" => ShlAss,
Shr = ">>" => ShrAss,
#[prec]
Add = "+" => AddAss,
Sub = "-" => SubAss,
#[prec]
Mul = "*" => MulAss,
Div = "/" => DivAss,
Mod = "%" => ModAss,
}
}
@ -155,11 +177,92 @@ impl<'a> Lexer<'a> {
}
pub fn next(&mut self) -> Token {
Iterator::next(self).unwrap_or(Token {
kind: TokenKind::Eof,
start: self.pos,
end: self.pos,
})
use TokenKind as T;
loop {
let mut start = self.pos;
let Some(c) = self.advance() else {
return Token {
kind: T::Eof,
start,
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 {
@ -232,11 +335,11 @@ impl<'a> Iterator for Lexer<'a> {
b'<' => T::Lt,
b'>' if self.advance_if(b'=') => T::Ge,
b'>' => T::Gt,
b'+' => T::Plus,
b'-' => T::Minus,
b'*' => T::Star,
b'/' => T::FSlash,
b'&' => T::Amp,
b'+' => T::Add,
b'-' => T::Sub,
b'*' => T::Mul,
b'/' => T::Div,
b'&' => T::Band,
b'(' => T::LParen,
b')' => T::RParen,
b'{' => T::LBrace,

View file

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

View file

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