Compare commits
2 Commits
fb78d1519f
...
main
| 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 {
|
||||
// keywords
|
||||
Func,
|
||||
@@ -17,9 +19,9 @@ pub enum TokenKind {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Token {
|
||||
kind: TokenKind,
|
||||
value: Box<str>,
|
||||
pos: usize,
|
||||
pub kind: TokenKind,
|
||||
pub value: Rc<str>,
|
||||
pub pos: usize,
|
||||
}
|
||||
|
||||
pub struct Lexer {
|
||||
@@ -28,18 +30,22 @@ pub struct Lexer {
|
||||
}
|
||||
|
||||
impl Lexer {
|
||||
pub fn new(src: impl Into<Box<str>>) -> Self {
|
||||
pub fn new(src: impl AsRef<str>) -> Self {
|
||||
Self {
|
||||
src: src.into(),
|
||||
src: src.as_ref().into(),
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn eof(&self) -> bool {
|
||||
self.pos >= self.src.len()
|
||||
}
|
||||
|
||||
pub fn lex(&mut self) -> Result<Vec<Token>, String> {
|
||||
let mut output = vec![];
|
||||
let chars = self.src.chars().collect::<Vec<char>>();
|
||||
|
||||
while self.pos < self.src.len() {
|
||||
while !self.eof() {
|
||||
let ch = chars[self.pos];
|
||||
|
||||
match ch {
|
||||
@@ -67,7 +73,7 @@ impl Lexer {
|
||||
}
|
||||
ch if ch.is_ascii_digit() => {
|
||||
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;
|
||||
}
|
||||
output.push(Token {
|
||||
@@ -79,11 +85,11 @@ impl Lexer {
|
||||
}
|
||||
ch if ch.is_ascii_alphabetic() => {
|
||||
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;
|
||||
}
|
||||
let word: Box<str> = self.src[start..self.pos].into();
|
||||
let kind = match word.as_ref() {
|
||||
let word = &self.src[start..self.pos];
|
||||
let kind = match word {
|
||||
"func" => TokenKind::Func,
|
||||
"do" => TokenKind::Do,
|
||||
"end" => TokenKind::End,
|
||||
@@ -91,7 +97,7 @@ impl Lexer {
|
||||
};
|
||||
output.push(Token {
|
||||
kind,
|
||||
value: word,
|
||||
value: word.into(),
|
||||
pos: start,
|
||||
});
|
||||
continue;
|
||||
|
||||
94
src/main.rs
94
src/main.rs
@@ -1,8 +1,98 @@
|
||||
use std::{fmt::Display, rc::Rc};
|
||||
|
||||
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() {
|
||||
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 (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