1use crate::token::Token;
3pub struct Lexer {
4 input: Vec<char,>,
5 pos: usize,
6}
7impl Lexer {
8 pub fn new(input: &str,) -> Self {
9 Self { input: input.chars().collect(), pos: 0, }
10 }
11 fn peek(&self,) -> Option<char,> {
12 self.input.get(self.pos,).copied()
13 }
14 fn advance(&mut self,) {
15 self.pos += 1;
16 }
17 fn skip_whitespace(&mut self,) {
18 while let Some(c,) = self.peek() {
19 if !c.is_whitespace() {
20 break;
21 }
22 self.advance();
23 }
24 }
25 fn read_identifier(&mut self,) -> String {
26 let start = self.pos;
27 while let Some(c,) = self.peek() {
28 if c.is_alphanumeric() || c == '_' {
29 self.advance();
30 } else {
31 break;
32 }
33 }
34 self.input[start..self.pos].iter().collect()
35 }
36 fn read_string(&mut self,) -> Result<String, String,> {
37 self.advance(); let start = self.pos;
39 while let Some(c,) = self.peek() {
40 match c {
41 '"' => {
42 let s: String =
43 self.input[start..self.pos].iter().collect();
44 self.advance();
45 return Ok(s,);
46 },
47 '\\' => {
48 self.advance();
49 if self.peek().is_none() {
50 return Err("Unterminated escape".to_string(),);
51 }
52 self.advance();
53 },
54 _ => self.advance(),
55 }
56 }
57 Err("Unterminated string literal".to_string(),)
58 }
59 pub fn next_token(&mut self,) -> Result<Token, String,> {
60 self.skip_whitespace();
61 let c = match self.peek() {
62 Some(ch,) => ch,
63 None => return Ok(Token::Eof,),
64 };
65 match c {
66 '(' => {
67 self.advance();
68 Ok(Token::LParen,)
69 },
70 ')' => {
71 self.advance();
72 Ok(Token::RParen,)
73 },
74 '{' => {
75 self.advance();
76 Ok(Token::LBrace,)
77 },
78 '}' => {
79 self.advance();
80 Ok(Token::RBrace,)
81 },
82 ',' => {
83 self.advance();
84 Ok(Token::Comma,)
85 },
86 ':' => {
87 self.advance();
88 Ok(Token::Colon,)
89 },
90 '.' => {
91 self.advance();
92 Ok(Token::Dot,)
93 },
94 '=' => {
95 self.advance();
96 Ok(Token::Equal,)
97 },
98 '"' => {
99 let lit = self.read_string()?;
100 Ok(Token::StringLiteral(lit,),)
101 },
102 _ if c.is_alphabetic() || c == '_' => {
103 let ident = self.read_identifier();
104 match ident.as_str() {
105 "text" => Ok(Token::KeywordText,),
106 "print" => Ok(Token::KeywordPrint,),
107 "external" => Ok(Token::KeywordExternal,),
108 "lua" => Ok(Token::KeywordLua,),
109 "mod" => Ok(Token::KeywordMod,),
110 "Upper" => Ok(Token::Upper,),
111 "empty" => Ok(Token::Empty,),
112 _ => Ok(Token::Identifier(ident,),),
113 }
114 },
115 _ => Err(format!("Unexpected character: '{}'", c),),
116 }
117 }
118}