Compare commits
2 Commits
fb78d1519f
...
dc014272c3
| Author | SHA1 | Date | |
|---|---|---|---|
|
dc014272c3
|
|||
|
563f608a46
|
30
src/lexer.rs
30
src/lexer.rs
@@ -1,4 +1,6 @@
|
|||||||
#[derive(Debug)]
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum TokenKind {
|
pub enum TokenKind {
|
||||||
// keywords
|
// keywords
|
||||||
Func,
|
Func,
|
||||||
@@ -17,9 +19,9 @@ pub enum TokenKind {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
kind: TokenKind,
|
pub kind: TokenKind,
|
||||||
value: Box<str>,
|
pub value: Rc<str>,
|
||||||
pos: usize,
|
pub pos: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Lexer {
|
pub struct Lexer {
|
||||||
@@ -28,18 +30,22 @@ pub struct Lexer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Lexer {
|
impl Lexer {
|
||||||
pub fn new(src: impl Into<Box<str>>) -> Self {
|
pub fn new(src: impl AsRef<str>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
src: src.into(),
|
src: src.as_ref().into(),
|
||||||
pos: 0,
|
pos: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eof(&self) -> bool {
|
||||||
|
self.pos >= self.src.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lex(&mut self) -> Result<Vec<Token>, String> {
|
pub fn lex(&mut self) -> Result<Vec<Token>, String> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
let chars = self.src.chars().collect::<Vec<char>>();
|
let chars = self.src.chars().collect::<Vec<char>>();
|
||||||
|
|
||||||
while self.pos < self.src.len() {
|
while !self.eof() {
|
||||||
let ch = chars[self.pos];
|
let ch = chars[self.pos];
|
||||||
|
|
||||||
match ch {
|
match ch {
|
||||||
@@ -67,7 +73,7 @@ impl Lexer {
|
|||||||
}
|
}
|
||||||
ch if ch.is_ascii_digit() => {
|
ch if ch.is_ascii_digit() => {
|
||||||
let start = self.pos;
|
let start = self.pos;
|
||||||
while self.pos < self.src.len() && chars[self.pos].is_ascii_digit() {
|
while !self.eof() && chars[self.pos].is_ascii_digit() {
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
}
|
}
|
||||||
output.push(Token {
|
output.push(Token {
|
||||||
@@ -79,11 +85,11 @@ impl Lexer {
|
|||||||
}
|
}
|
||||||
ch if ch.is_ascii_alphabetic() => {
|
ch if ch.is_ascii_alphabetic() => {
|
||||||
let start = self.pos;
|
let start = self.pos;
|
||||||
while self.pos < self.src.len() && chars[self.pos].is_ascii_alphanumeric() {
|
while !self.eof() && chars[self.pos].is_ascii_alphanumeric() {
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
}
|
}
|
||||||
let word: Box<str> = self.src[start..self.pos].into();
|
let word = &self.src[start..self.pos];
|
||||||
let kind = match word.as_ref() {
|
let kind = match word {
|
||||||
"func" => TokenKind::Func,
|
"func" => TokenKind::Func,
|
||||||
"do" => TokenKind::Do,
|
"do" => TokenKind::Do,
|
||||||
"end" => TokenKind::End,
|
"end" => TokenKind::End,
|
||||||
@@ -91,7 +97,7 @@ impl Lexer {
|
|||||||
};
|
};
|
||||||
output.push(Token {
|
output.push(Token {
|
||||||
kind,
|
kind,
|
||||||
value: word,
|
value: word.into(),
|
||||||
pos: start,
|
pos: start,
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
94
src/main.rs
94
src/main.rs
@@ -1,8 +1,98 @@
|
|||||||
|
use std::{fmt::Display, rc::Rc};
|
||||||
|
|
||||||
mod lexer;
|
mod lexer;
|
||||||
|
use lexer::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum InfixOp {
|
||||||
|
Add,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InfixOp {
|
||||||
|
fn bp(&self) -> (f32, f32) {
|
||||||
|
match self {
|
||||||
|
Self::Add => (1.0, 1.1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<TokenKind> for InfixOp {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: TokenKind) -> Result<Self, Self::Error> {
|
||||||
|
Ok(match value {
|
||||||
|
TokenKind::Plus => Self::Add,
|
||||||
|
_ => return Err(()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Expr {
|
||||||
|
Integer(u64),
|
||||||
|
Variable(Rc<str>),
|
||||||
|
Infix(InfixOp, Box<Expr>, Box<Expr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Expr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Expr::Integer(i) => write!(f, "{}", i),
|
||||||
|
Expr::Variable(v) => write!(f, "{}", v),
|
||||||
|
Expr::Infix(op, e1, e2) => write!(f, "({:?} {} {})", op, e1, e2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_atom(tokens: &[Token]) -> Result<(Expr, &[Token]), String> {
|
||||||
|
let t = &tokens[0];
|
||||||
|
|
||||||
|
Ok(match t.kind {
|
||||||
|
TokenKind::Integer => {
|
||||||
|
let Ok(int) = t.value.parse() else {
|
||||||
|
return Err(format!("failed to parse integer at position {}", t.pos));
|
||||||
|
};
|
||||||
|
(Expr::Integer(int), &tokens[1..])
|
||||||
|
}
|
||||||
|
TokenKind::Identifier => (Expr::Variable(Rc::clone(&t.value)), &tokens[1..]),
|
||||||
|
_ => {
|
||||||
|
return Err(format!("unexpected token at position {}", t.pos));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_expr(tokens: &[Token], bp: f32) -> Result<(Expr, &[Token]), String> {
|
||||||
|
let mut left: Expr;
|
||||||
|
let mut tokens = tokens;
|
||||||
|
|
||||||
|
(left, tokens) = parse_atom(tokens)?;
|
||||||
|
|
||||||
|
while !tokens.is_empty() {
|
||||||
|
let t = &tokens[0];
|
||||||
|
let op: InfixOp = t
|
||||||
|
.kind
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| format!("invalid operator '{}' at position {}", t.value, t.pos))?;
|
||||||
|
|
||||||
|
let (lbp, rbp) = op.bp();
|
||||||
|
if lbp < bp {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (right, rest) = parse_expr(&tokens[1..], rbp)?;
|
||||||
|
left = Expr::Infix(op, Box::new(left), Box::new(right));
|
||||||
|
tokens = rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok((left, tokens));
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut lexer = lexer::Lexer::new("func do end foo(123)door+1");
|
let mut lexer = Lexer::new("34 + 35");
|
||||||
let tokens = lexer.lex().expect("failed to lex");
|
let tokens = lexer.lex().expect("failed to lex");
|
||||||
|
let (expr, rest) = parse_expr(&tokens, 0.0).expect("failed to parse");
|
||||||
|
|
||||||
eprintln!("{:#?}", tokens);
|
assert!(rest.is_empty(), "unexpected tokens");
|
||||||
|
|
||||||
|
eprintln!("{}", expr);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user