parser lexer split from phone
This commit is contained in:
parent
ce817c9f89
commit
e773c40ea9
4 changed files with 178 additions and 174 deletions
|
|
@ -1,2 +1,4 @@
|
||||||
|
pub mod types;
|
||||||
|
pub mod scanner;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub use parser::*;
|
pub use parser::*;
|
||||||
|
|
|
||||||
|
|
@ -1,178 +1,4 @@
|
||||||
use crate::ast;
|
use crate::ast;
|
||||||
use chumsky::text::Char;
|
|
||||||
use log;
|
|
||||||
use lyn::Scanner;
|
|
||||||
|
|
||||||
struct LocatedToken {
|
|
||||||
start: usize,
|
|
||||||
end: usize,
|
|
||||||
token: Token,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
enum Token {
|
|
||||||
Let,
|
|
||||||
Fn,
|
|
||||||
Equals,
|
|
||||||
Semicolon,
|
|
||||||
OpenParen,
|
|
||||||
CloseParen,
|
|
||||||
OpenBracket,
|
|
||||||
CloseBracket,
|
|
||||||
OpenCurly,
|
|
||||||
CloseCurly,
|
|
||||||
Dot,
|
|
||||||
Comma,
|
|
||||||
Name(String),
|
|
||||||
Number(u32),
|
|
||||||
String(String),
|
|
||||||
Identifier(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scan(source: String) -> Vec<LocatedToken> {
|
|
||||||
let mut scanner = Scanner::new(&source);
|
|
||||||
let mut tokens = Vec::new();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let start = scanner.cursor();
|
|
||||||
if let Some(c) = scanner.pop() {
|
|
||||||
match *c {
|
|
||||||
'.' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::Dot,
|
|
||||||
}),
|
|
||||||
',' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::Comma,
|
|
||||||
}),
|
|
||||||
';' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::Semicolon,
|
|
||||||
}),
|
|
||||||
'{' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::OpenCurly,
|
|
||||||
}),
|
|
||||||
'}' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::CloseCurly,
|
|
||||||
}),
|
|
||||||
'(' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::OpenParen,
|
|
||||||
}),
|
|
||||||
')' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::CloseParen,
|
|
||||||
}),
|
|
||||||
'[' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::OpenBracket,
|
|
||||||
}),
|
|
||||||
']' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::CloseBracket,
|
|
||||||
}),
|
|
||||||
'=' => tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::Equals,
|
|
||||||
}),
|
|
||||||
// comments
|
|
||||||
'#' => {
|
|
||||||
let mut str = "".to_string();
|
|
||||||
while let Some(ch) = scanner.pop() {
|
|
||||||
if ch.is_newline() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str.push(*ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// strings
|
|
||||||
'"' => {
|
|
||||||
let mut str = "".to_string();
|
|
||||||
while let Some(ch) = scanner.pop() {
|
|
||||||
if *ch == '"' {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str.push(*ch);
|
|
||||||
}
|
|
||||||
tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::String(str),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
_ if c.is_whitespace() => {}
|
|
||||||
// numbers
|
|
||||||
_ if c.is_numeric() => {
|
|
||||||
let mut str = "".to_string();
|
|
||||||
loop {
|
|
||||||
if let Some(ch) = scanner.peek()
|
|
||||||
&& !ch.is_numeric()
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if let Some(ch) = scanner.pop() {
|
|
||||||
str.push(*ch);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let i = str.parse::<u32>().unwrap();
|
|
||||||
tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: Token::Number(i),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// identifiers and keywords
|
|
||||||
_ if c.is_alphabetic() => {
|
|
||||||
let mut str = "".to_string();
|
|
||||||
loop {
|
|
||||||
if let Some(ch) = scanner.peek()
|
|
||||||
&& !ch.is_alphanumeric()
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if let Some(ch) = scanner.pop() {
|
|
||||||
str.push(*ch);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tokens.push(LocatedToken {
|
|
||||||
start,
|
|
||||||
end: scanner.cursor(),
|
|
||||||
token: match str.as_str() {
|
|
||||||
"fn" => Token::Fn,
|
|
||||||
"let" => Token::Let,
|
|
||||||
_ => Token::Identifier(str),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// error
|
|
||||||
_ => {
|
|
||||||
log::error!("Unexpected character: {c}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tokens
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_expr(tokens: &mut Vec<LocatedToken>) -> Result<ast::Expr, Error> {
|
fn parse_expr(tokens: &mut Vec<LocatedToken>) -> Result<ast::Expr, Error> {
|
||||||
todo!()
|
todo!()
|
||||||
|
|
|
||||||
149
src/parser/scanner.rs
Normal file
149
src/parser/scanner.rs
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
use chumsky::text::Char;
|
||||||
|
use log;
|
||||||
|
use lyn::Scanner;
|
||||||
|
use super::types::*;
|
||||||
|
|
||||||
|
fn scan(source: String) -> Vec<LocatedToken> {
|
||||||
|
let mut scanner = Scanner::new(&source);
|
||||||
|
let mut tokens = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let start = scanner.cursor();
|
||||||
|
if let Some(c) = scanner.pop() {
|
||||||
|
match *c {
|
||||||
|
'.' => tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::Dot,
|
||||||
|
}),
|
||||||
|
',' => tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::Comma,
|
||||||
|
}),
|
||||||
|
';' => tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::Semicolon,
|
||||||
|
}),
|
||||||
|
'{' => tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::OpenCurly,
|
||||||
|
}),
|
||||||
|
'}' => tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::CloseCurly,
|
||||||
|
}),
|
||||||
|
'(' => tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::OpenParen,
|
||||||
|
}),
|
||||||
|
')' => tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::CloseParen,
|
||||||
|
}),
|
||||||
|
'[' => tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::OpenBracket,
|
||||||
|
}),
|
||||||
|
']' => tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::CloseBracket,
|
||||||
|
}),
|
||||||
|
'=' => tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::Equals,
|
||||||
|
}),
|
||||||
|
// comments
|
||||||
|
'#' => {
|
||||||
|
let mut str = "".to_string();
|
||||||
|
while let Some(ch) = scanner.pop() {
|
||||||
|
if ch.is_newline() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str.push(*ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// strings
|
||||||
|
'"' => {
|
||||||
|
let mut str = "".to_string();
|
||||||
|
while let Some(ch) = scanner.pop() {
|
||||||
|
if *ch == '"' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
str.push(*ch);
|
||||||
|
}
|
||||||
|
tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::String(str),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ if c.is_whitespace() => {}
|
||||||
|
// numbers
|
||||||
|
_ if c.is_numeric() => {
|
||||||
|
let mut str = "".to_string();
|
||||||
|
loop {
|
||||||
|
if let Some(ch) = scanner.peek()
|
||||||
|
&& !ch.is_numeric()
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(ch) = scanner.pop() {
|
||||||
|
str.push(*ch);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let i = str.parse::<u32>().unwrap();
|
||||||
|
tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: Token::Number(i),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// identifiers and keywords
|
||||||
|
_ if c.is_alphabetic() => {
|
||||||
|
let mut str = "".to_string();
|
||||||
|
loop {
|
||||||
|
if let Some(ch) = scanner.peek()
|
||||||
|
&& !ch.is_alphanumeric()
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(ch) = scanner.pop() {
|
||||||
|
str.push(*ch);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.push(LocatedToken {
|
||||||
|
start,
|
||||||
|
end: scanner.cursor(),
|
||||||
|
token: match str.as_str() {
|
||||||
|
"fn" => Token::Fn,
|
||||||
|
"let" => Token::Let,
|
||||||
|
_ => Token::Identifier(str),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// error
|
||||||
|
_ => {
|
||||||
|
log::error!("Unexpected character: {c}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens
|
||||||
|
}
|
||||||
27
src/parser/types.rs
Normal file
27
src/parser/types.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
struct LocatedToken {
|
||||||
|
start: usize,
|
||||||
|
end: usize,
|
||||||
|
token: Token,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
enum Token {
|
||||||
|
Let,
|
||||||
|
Fn,
|
||||||
|
Equals,
|
||||||
|
Semicolon,
|
||||||
|
OpenParen,
|
||||||
|
CloseParen,
|
||||||
|
OpenBracket,
|
||||||
|
CloseBracket,
|
||||||
|
OpenCurly,
|
||||||
|
CloseCurly,
|
||||||
|
Dot,
|
||||||
|
Comma,
|
||||||
|
Name(String),
|
||||||
|
Number(u32),
|
||||||
|
String(String),
|
||||||
|
Identifier(String),
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue