feat(ir, parser): Support if/while/break/logical expr/cmp in parser and ir generator

This commit is contained in:
2026-05-14 15:54:31 +08:00
parent 41284dc14e
commit 7b6eede961
10 changed files with 1260 additions and 357 deletions
+36 -16
View File
@@ -17,7 +17,7 @@ pub struct Lexer {
const WHITESPACE_CHARS: &[char] = &[' ', '\t', '\n', '\r'];
const DELIMITER_CHARS: &[char] = &[
'+', '-', '*', '/', '%', '=', '!', '<', '>', '(', ')', ',', ';'
'+', '-', '*', '/', '%', '=', '!', '<', '>', '(', ')', ',', ';', '{', '|', '&'
];
struct Cursor {
chars: Vec<char>,
@@ -185,22 +185,10 @@ fn parse_litint(
) -> Result<TokenValue, LexParseError> {
let mut c1 = str_iter.peek().ok_or(LexParseError::NotMatched)?;
// c1 is the peek value from here
let mut sign_base: i64 = 1;
let mut base: i64 = 10;
if !(c1.is_ascii_digit() || c1 == '-') {
if !(c1.is_ascii_digit()) {
return Err(LexParseError::NotMatched);
}
if c1 == '-' {
sign_base = -1;
str_iter.advance(1);
c1 = str_iter.peek().ok_or(LexParseError::NotMatched)?;
if !c1.is_ascii_digit() {
// only a minus sign, not a number
// back one so cursor still points to the minus sign
str_iter.back(1);
return Err(LexParseError::NotMatched);
}
}
let mut number = 0i64;
let mut has_digits = false;
if c1 == '0' {
@@ -248,7 +236,6 @@ fn parse_litint(
// No valid digits found, add a diagnostic
return Err(LexParseError::InvalidInMatch(LexingError::InvalidIntLiteral));
}
number *= sign_base;
Ok(TokenValue::IntLit(number))
}
@@ -293,6 +280,7 @@ fn parse_puncuation(
if let Some('=') = str_iter.peek() {
TokenValue::NotEqual
} else {
str_iter.back(1);
TokenValue::Not
}
},
@@ -301,7 +289,24 @@ fn parse_puncuation(
',' => TokenValue::Comma,
';' => TokenValue::Semicolon,
'|' => {
str_iter.advance(1);
if let Some('|') = str_iter.peek() {
TokenValue::Or
} else {
// unrecognized token starting with '|'
return Err(LexParseError::InvalidInMatch(LexingError::UnrecognizedToken("|".to_string())));
}
},
'&' => {
str_iter.advance(1);
if let Some('&') = str_iter.peek() {
TokenValue::And
} else {
// unrecognized token starting with '&'
return Err(LexParseError::InvalidInMatch(LexingError::UnrecognizedToken("&".to_string())));
}
},
_ => return Err(LexParseError::NotMatched),
};
str_iter.advance(1);
@@ -330,6 +335,21 @@ fn parse_ident(
if name.eq("return") {
return Ok(TokenValue::Return);
}
if name.eq("if") {
return Ok(TokenValue::If);
}
if name.eq("else") {
return Ok(TokenValue::Else);
}
if name.eq("while") {
return Ok(TokenValue::While);
}
if name.eq("break") {
return Ok(TokenValue::Break);
}
if name.eq("continue") {
return Ok(TokenValue::Continue);
}
if let Some(type_ident) = TypeIdent::from_str(&name).ok() {
return Ok(TokenValue::TypeIdent(type_ident));
}