Compare commits
No commits in common. "a21b119e580e692b8796cc1220706b65167ee07f" and "a887bf4b3e8101bdc99554e5a9e25803e7dc5c6e" have entirely different histories.
a21b119e58
...
a887bf4b3e
5 changed files with 43 additions and 185 deletions
41
src/error.rs
41
src/error.rs
|
|
@ -1,41 +0,0 @@
|
||||||
use std::{error::Error, fmt::Display};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ParseError {
|
|
||||||
message: String
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParseError {
|
|
||||||
pub fn new(message: impl Into<String>) -> Self {
|
|
||||||
Self { message: message.into() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for ParseError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "parse error: {}", self.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for ParseError {}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct LexError {
|
|
||||||
message: String
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LexError {
|
|
||||||
pub fn new(message: impl Into<String>) -> Self {
|
|
||||||
Self { message: message.into() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for LexError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "lex error: {}", self.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for LexError {}
|
|
||||||
99
src/lexer.rs
99
src/lexer.rs
|
|
@ -1,6 +1,4 @@
|
||||||
use crate::{error::LexError, token::Token};
|
use crate::token::Token;
|
||||||
|
|
||||||
type LexResult<T> = Result<T, LexError>;
|
|
||||||
|
|
||||||
pub struct Lexer {
|
pub struct Lexer {
|
||||||
source: Vec<u8>,
|
source: Vec<u8>,
|
||||||
|
|
@ -29,7 +27,7 @@ impl Lexer {
|
||||||
self.source.get(self.pos).copied()
|
self.source.get(self.pos).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn number(&mut self) -> LexResult<Token> {
|
fn number(&mut self) -> Option<Token> {
|
||||||
let mut num = String::new();
|
let mut num = String::new();
|
||||||
|
|
||||||
while matches!(self.peek(), Some(b'0' ..= b'9')) {
|
while matches!(self.peek(), Some(b'0' ..= b'9')) {
|
||||||
|
|
@ -37,97 +35,42 @@ impl Lexer {
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Token::Number(num.parse().unwrap()))
|
Some(Token::Number(num.parse().unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ident(&mut self) -> LexResult<Token> {
|
fn ident(&mut self) -> Option<Token> {
|
||||||
let mut ident = String::new();
|
let mut ident = String::new();
|
||||||
|
|
||||||
while matches!(self.peek(), Some(b'a' ..= b'z' | b'A' ..= b'Z' | b'0' ..= b'9' | b'_')) {
|
while matches!(self.peek(), Some(b'a' ..= b'z' | b'A' ..= b'Z')) {
|
||||||
ident.push(self.peek().unwrap() as char);
|
ident.push(self.peek().unwrap() as char);
|
||||||
self.advance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let tok = match ident.as_str() {
|
Some(Token::Ident(ident))
|
||||||
"mov" => Token::Mov,
|
|
||||||
"if" => Token::If,
|
|
||||||
"else" => Token::Else,
|
|
||||||
"loop" => Token::Loop,
|
|
||||||
"while" => Token::While,
|
|
||||||
"for" => Token::For,
|
|
||||||
"in" => Token::In,
|
|
||||||
"fun" => Token::Fun,
|
|
||||||
"call" => Token::Call,
|
|
||||||
"break" => Token::Break,
|
|
||||||
"continue" => Token::Continue,
|
|
||||||
"true" => Token::True,
|
|
||||||
"false" => Token::False,
|
|
||||||
|
|
||||||
"eq" => Token::Eq,
|
|
||||||
"new" => Token::Neq,
|
|
||||||
"lt" => Token::Lt,
|
|
||||||
"gt" => Token::Gt,
|
|
||||||
"lte" => Token::Lte,
|
|
||||||
"gte" => Token::Gte,
|
|
||||||
|
|
||||||
_ => Token::Ident(ident)
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(tok)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string(&mut self) -> LexResult<Token> {
|
pub fn next(&mut self) -> Option<Token> {
|
||||||
self.advance();
|
|
||||||
let mut s = String::new();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match self.peek() {
|
|
||||||
Some(b'"') => { self.advance(); break; },
|
|
||||||
Some(c) => { s.push(c as char); self.advance(); }
|
|
||||||
None => { return Err(LexError::new(format!(
|
|
||||||
"expected closing \""
|
|
||||||
))); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Token::StringLit(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next(&mut self) -> LexResult<Token> {
|
|
||||||
self.skip_whitespace();
|
self.skip_whitespace();
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
Some(b'0' ..= b'9') => self.number(),
|
Some(b'0' ..= b'9') => self.number(),
|
||||||
Some(b'a' ..= b'z' | b'A' ..= b'Z') => self.ident(),
|
Some(b'a' ..= b'z' | b'A' ..= b'Z') => self.ident(),
|
||||||
|
|
||||||
Some(b'+') => {self.advance(); Ok(Token::Plus)},
|
Some(b'+') => {self.advance(); Some(Token::Plus)},
|
||||||
Some(b'-') => {self.advance(); Ok(Token::Minus)},
|
Some(b'-') => {self.advance(); Some(Token::Minus)},
|
||||||
Some(b'*') => {self.advance(); Ok(Token::Asterisk)},
|
Some(b'*') => {self.advance(); Some(Token::Asterisk)},
|
||||||
Some(b'/') => {self.advance(); Ok(Token::Slash)},
|
Some(b'/') => {self.advance(); Some(Token::Slash)},
|
||||||
Some(b'%') => {self.advance(); Ok(Token::Percent)},
|
Some(b'%') => {self.advance(); Some(Token::Percent)},
|
||||||
Some(b'^') => {self.advance(); Ok(Token::Caret)},
|
Some(b'^') => {self.advance(); Some(Token::Caret)},
|
||||||
|
|
||||||
Some(b'(') => {self.advance(); Ok(Token::LParen)},
|
Some(b'(') => {self.advance(); Some(Token::LParen)},
|
||||||
Some(b')') => {self.advance(); Ok(Token::RParen)},
|
Some(b')') => {self.advance(); Some(Token::RParen)},
|
||||||
Some(b'[') => {self.advance(); Ok(Token::LBracket)},
|
Some(b'[') => {self.advance(); Some(Token::LBracket)},
|
||||||
Some(b']') => {self.advance(); Ok(Token::RBracket)},
|
Some(b']') => {self.advance(); Some(Token::RBracket)},
|
||||||
Some(b'{') => {self.advance(); Ok(Token::LBrace)},
|
Some(b'{') => {self.advance(); Some(Token::LBrace)},
|
||||||
Some(b'}') => {self.advance(); Ok(Token::RBrace)},
|
Some(b'}') => {self.advance(); Some(Token::RBrace)},
|
||||||
|
|
||||||
Some(b';') => {self.advance(); Ok(Token::Semicolon)},
|
Some(b';') => {self.advance(); Some(Token::Semicolon)}
|
||||||
Some(b',') => {self.advance(); Ok(Token::Comma)},
|
|
||||||
Some(b'.') => {
|
|
||||||
self.advance();
|
|
||||||
|
|
||||||
match self.peek() {
|
_ => None
|
||||||
Some(b'.') => { self.advance(); Ok(Token::DotDot) },
|
|
||||||
c => Err(LexError::new(format!(
|
|
||||||
"unexpected character after '.': {c:?}"
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Some(b'"') => self.string(),
|
|
||||||
|
|
||||||
_ => Ok(Token::EOF)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,7 +3,6 @@ use std::{fs::File, io::Read};
|
||||||
mod token;
|
mod token;
|
||||||
mod expr;
|
mod expr;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
mod error;
|
|
||||||
use lexer::Lexer;
|
use lexer::Lexer;
|
||||||
mod parser;
|
mod parser;
|
||||||
use parser::Parser;
|
use parser::Parser;
|
||||||
|
|
@ -21,8 +20,7 @@ fn main() -> std::io::Result<()> {
|
||||||
let mut lexer = Lexer::new(&source);
|
let mut lexer = Lexer::new(&source);
|
||||||
|
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
while let Ok(tok) = lexer.next() {
|
while let Some(tok) = lexer.next() {
|
||||||
if tok == token::Token::EOF { break; }
|
|
||||||
print!("{tok:?}, ");
|
print!("{tok:?}, ");
|
||||||
tokens.push(tok);
|
tokens.push(tok);
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +29,7 @@ fn main() -> std::io::Result<()> {
|
||||||
|
|
||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
loop {
|
loop {
|
||||||
let parsed = parser.parse().unwrap_or(expr::Expr::EOL);
|
let parsed = parser.parse();
|
||||||
match parsed {
|
match parsed {
|
||||||
expr::Expr::EOL => break,
|
expr::Expr::EOL => break,
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::expr::{Expr, UnaryOp, BinaryOp, infix_bp, prefix_bp};
|
use crate::expr::{Expr, UnaryOp, BinaryOp, infix_bp, prefix_bp};
|
||||||
use crate::error::ParseError;
|
|
||||||
|
|
||||||
type ParseResult<T> = Result<T, ParseError>;
|
|
||||||
|
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
tokens: Vec<Token>,
|
tokens: Vec<Token>,
|
||||||
|
|
@ -31,49 +28,39 @@ impl Parser {
|
||||||
tok
|
tok
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect(&mut self, expected: &Token) -> ParseResult<Token> {
|
fn parse_atom(&mut self) -> Expr {
|
||||||
match self.next() {
|
match self.next() {
|
||||||
Some(tok) if &tok == expected => Ok(tok),
|
Some(Token::Number(n)) => Expr::Number(n),
|
||||||
other => Err(ParseError::new(format!(
|
Some(Token::Ident(id)) => Expr::Ident(id),
|
||||||
"expected {expected:?}, got {other:?}"
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_atom(&mut self) -> ParseResult<Expr> {
|
|
||||||
match self.next() {
|
|
||||||
Some(Token::Number(n)) => Ok(Expr::Number(n)),
|
|
||||||
Some(Token::Ident(id)) => Ok(Expr::Ident(id)),
|
|
||||||
Some(Token::LParen) => {
|
Some(Token::LParen) => {
|
||||||
let expr = self.parse_expr(0)?;
|
let expr = self.parse_expr(0);
|
||||||
|
|
||||||
self.expect(&Token::RParen)?;
|
match self.next() {
|
||||||
|
Some(Token::RParen) => expr,
|
||||||
Ok(expr)
|
_ => panic!("expected ')'")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
tok => Err(ParseError::new(format!(
|
tok => panic!("unknown token: {tok:?}")
|
||||||
"unexpected token: {tok:?}"
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_prefix(&mut self) -> ParseResult<Expr> {
|
fn parse_prefix(&mut self) -> Expr {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
Some(Token::Minus) => {
|
Some(Token::Minus) => {
|
||||||
self.advance();
|
self.advance();
|
||||||
let op = UnaryOp::Neg;
|
let op = UnaryOp::Neg;
|
||||||
|
|
||||||
let bp = prefix_bp(&op);
|
let bp = prefix_bp(&op);
|
||||||
let rhs = self.parse_expr(bp)?;
|
let rhs = self.parse_expr(bp);
|
||||||
|
|
||||||
Ok(Expr::Unary { op, right: Box::new(rhs) })
|
Expr::Unary { op, right: Box::new(rhs) }
|
||||||
},
|
},
|
||||||
_ => self.parse_atom()
|
_ => self.parse_atom()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expr(&mut self, min_bp: u8) -> ParseResult<Expr> {
|
fn parse_expr(&mut self, min_bp: u8) -> Expr {
|
||||||
let mut lhs = self.parse_prefix()?;
|
let mut lhs = self.parse_prefix();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let op = match self.peek() {
|
let op = match self.peek() {
|
||||||
|
|
@ -94,16 +81,16 @@ impl Parser {
|
||||||
|
|
||||||
self.advance();
|
self.advance();
|
||||||
|
|
||||||
let rhs = self.parse_expr(right_bp)?;
|
let rhs = self.parse_expr(right_bp);
|
||||||
|
|
||||||
lhs = Expr::Binary { left: Box::new(lhs), op, right: Box::new(rhs) }
|
lhs = Expr::Binary { left: Box::new(lhs), op, right: Box::new(rhs) }
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(lhs)
|
lhs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self) -> ParseResult<Expr> {
|
pub fn parse(&mut self) -> Expr {
|
||||||
if self.peek().is_none() {return Ok(Expr::EOL)}
|
if self.peek().is_none() {return Expr::EOL}
|
||||||
self.parse_expr(0)
|
self.parse_expr(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
31
src/token.rs
31
src/token.rs
|
|
@ -2,7 +2,6 @@
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
Number(i64),
|
Number(i64),
|
||||||
Ident(String),
|
Ident(String),
|
||||||
StringLit(String),
|
|
||||||
|
|
||||||
// Operators
|
// Operators
|
||||||
Plus,
|
Plus,
|
||||||
|
|
@ -20,33 +19,5 @@ pub enum Token {
|
||||||
LBracket,
|
LBracket,
|
||||||
RBracket,
|
RBracket,
|
||||||
|
|
||||||
// Separators
|
Semicolon
|
||||||
Semicolon,
|
|
||||||
Comma,
|
|
||||||
|
|
||||||
// Keywords
|
|
||||||
Mov,
|
|
||||||
If,
|
|
||||||
Else,
|
|
||||||
Loop,
|
|
||||||
While,
|
|
||||||
For,
|
|
||||||
In,
|
|
||||||
Fun,
|
|
||||||
Call,
|
|
||||||
Break,
|
|
||||||
Continue,
|
|
||||||
True,
|
|
||||||
False,
|
|
||||||
DotDot,
|
|
||||||
|
|
||||||
// Conditionals
|
|
||||||
Eq,
|
|
||||||
Neq,
|
|
||||||
Lt,
|
|
||||||
Gt,
|
|
||||||
Lte,
|
|
||||||
Gte,
|
|
||||||
|
|
||||||
EOF
|
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue