From 3c09a5f23e2b1c8fa979bfa405387c8cae64cfe5 Mon Sep 17 00:00:00 2001 From: mlokr Date: Wed, 15 May 2024 10:37:39 +0200 Subject: [PATCH] adding '=' syntax --- hblang/examples/directives.hb | 1 - hblang/examples/loops.hb | 2 +- hblang/src/codegen.rs | 18 +-- hblang/src/lexer.rs | 161 +++++++++++++++++++----- hblang/src/parser.rs | 24 ++-- hblang/tests/lexer_tests_arithmetic.txt | 16 +-- 6 files changed, 166 insertions(+), 56 deletions(-) diff --git a/hblang/examples/directives.hb b/hblang/examples/directives.hb index 54540cf..b371db4 100644 --- a/hblang/examples/directives.hb +++ b/hblang/examples/directives.hb @@ -1,4 +1,3 @@ - Type := struct { brah: int, blah: int, diff --git a/hblang/examples/loops.hb b/hblang/examples/loops.hb index 8520da2..91fc44b 100644 --- a/hblang/examples/loops.hb +++ b/hblang/examples/loops.hb @@ -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; diff --git a/hblang/src/codegen.rs b/hblang/src/codegen.rs index f4f7c94..47b6c96 100644 --- a/hblang/src/codegen.rs +++ b/hblang/src/codegen.rs @@ -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), diff --git a/hblang/src/lexer.rs b/hblang/src/lexer.rs index f3a6ee7..aea842e 100644 --- a/hblang/src/lexer.rs +++ b/hblang/src/lexer.rs @@ -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 { 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 { + 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, diff --git a/hblang/src/parser.rs b/hblang/src/parser.rs index a83a436..ef1c0b6 100644 --- a/hblang/src/parser.rs +++ b/hblang/src/parser.rs @@ -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 { @@ -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(), diff --git a/hblang/tests/lexer_tests_arithmetic.txt b/hblang/tests/lexer_tests_arithmetic.txt index 6e255bf..26de539 100644 --- a/hblang/tests/lexer_tests_arithmetic.txt +++ b/hblang/tests/lexer_tests_arithmetic.txt @@ -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 "}"