Initial commit

This commit is contained in:
2026-07-06 11:34:44 -04:00
commit e57e319dec
10 changed files with 286 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
use super::{ Token };
macro_rules! ident_initial_chars {
() => {
'a' ..= 'z' | 'A' ..= 'Z'
}
}
macro_rules! ident_chars {
() => {
ident_initial_chars!() | '0' ..= '9' | '$' | '_'
}
}
pub fn parse_identifier(input: &str) -> Option<(Token, &str)> {
let mut chars = input.chars();
let first_char: char = match chars.next() {
a @ Some(ident_initial_chars!()) => a.unwrap(),
_ => return None,
};
let rest: String = chars.take_while(|&c| matches!(c, ident_chars!())).collect();
let full = format!("{}{}", first_char, rest);
let len = full.len();
Some((Token::Id(full), &input[len..]))
}
+19
View File
@@ -0,0 +1,19 @@
use super::{ whitespace_chars, Token };
#[derive(Debug)]
pub enum Keyword {
Let,
}
macro_rules! match_keyword {
($str:literal, $kw:expr, $val:ident) => {
if $val.starts_with($str) && matches!($val.chars().nth($str.len()), None | Some(whitespace_chars!())) {
return Some(($kw, &$val[$str.len()..]));
}
}
}
pub fn parse_keyword(input: &str) -> Option<(Token, &str)> {
match_keyword!("let", Token::Kw(Keyword::Let), input);
None
}
+101
View File
@@ -0,0 +1,101 @@
use super::{ Token, TeaValue };
macro_rules! dec_chars {
() => {
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
}
}
macro_rules! hex_chars {
() => {
dec_chars!() | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
}
}
fn parse_float(input: &str) -> Option<(f32, &str)> {
let (input, sign) = if input.starts_with("-") {
(input.strip_prefix("-").unwrap(), -1.0)
} else {
(input, 1.0)
};
let mut dec = false;
let mut e = false;
let s: String = input.chars().take_while(|&c| {
if matches!(c, dec_chars!()) {
return true;
}
match (dec, e) {
(true, true) => false,
(false, true) => {
if c == '.' {
dec = true;
return true;
}
false
},
(true, false) => {
if c == 'e' {
e = true;
return true;
}
false
},
(false, false) => {
if c == '.' {
dec = true;
return true;
}
if c == 'e' {
e = true;
return true;
}
false
},
}
}).collect();
if s.is_empty() || !(dec || e) {
return None;
}
Some((sign * s.parse::<f32>().unwrap(), &input[s.len()..]))
}
fn parse_hex_int(input: &str) -> Option<(i32, &str)> {
let (input, sign) = if input.starts_with("-") {
(input.strip_prefix("-").unwrap(), -1)
} else {
(input, 1)
};
let input = input.strip_prefix("0x")?;
let s: String = input.chars().take_while(|c| matches!(c, hex_chars!())).collect();
if s.is_empty() {
return None;
}
Some((sign * i32::from_str_radix(&s, 16).unwrap(), &input[s.len()..]))
}
fn parse_dec_int(input: &str) -> Option<(i32, &str)> {
let (input, sign) = if input.starts_with("-") {
(input.strip_prefix("-").unwrap(), -1)
} else {
(input, 1)
};
let s: String = input.chars().take_while(|c| matches!(c, dec_chars!())).collect();
if s.is_empty() {
return None;
}
Some((sign * s.parse::<i32>().unwrap(), &input[s.len()..]))
}
pub fn parse_literal(input: &str) -> Option<(Token, &str)> {
if let Some((val, s)) = parse_float(input) {
return Some((Token::Lit(TeaValue::Float(val)), s))
}
if let Some((val, s)) = parse_hex_int(input) {
return Some((Token::Lit(TeaValue::Int(val)), s))
}
if let Some((val, s)) = parse_dec_int(input) {
return Some((Token::Lit(TeaValue::Int(val)), s))
}
// TODO: other values
None
}
+21
View File
@@ -0,0 +1,21 @@
use super::Token;
#[derive(Debug)]
pub enum Operator {
Plus,
Minus,
Star, // multiplication
Slash, // division
}
pub fn parse_operator(input: &str) -> Option<(Token, &str)> {
let c: char = input.chars().next()?;
let input = &input[1..];
match c {
'+' => Some((Token::Op(Operator::Plus), input)),
'-' => Some((Token::Op(Operator::Minus), input)),
'*' => Some((Token::Op(Operator::Star), input)),
'/' => Some((Token::Op(Operator::Slash), input)),
_ => None
}
}
+17
View File
@@ -0,0 +1,17 @@
use super::Token;
#[derive(Debug)]
pub enum Symbol {
EqualSign,
Semicolon,
}
pub fn parse_symbol(input: &str) -> Option<(Token, &str)> {
let c: char = input.chars().next()?;
let input = &input[1..];
match c {
'=' => Some((Token::Sym(Symbol::EqualSign), input)),
';' => Some((Token::Sym(Symbol::Semicolon), input)),
_ => None
}
}