Initial commit
This commit is contained in:
@@ -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..]))
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user