parse some things maybe

This commit is contained in:
nora 2022-03-21 16:29:47 +01:00
parent 9e87a4ce91
commit 1bd5859f0c
8 changed files with 315 additions and 74 deletions

3
.rustfmt.toml Normal file
View file

@ -0,0 +1,3 @@
imports_granularity = "Crate"
newline_style = "Unix"
group_imports = "StdExternalCrate"

View file

@ -1,16 +1,17 @@
use crate::span::Span; use std::{ops::Range, path::PathBuf};
use std::path::PathBuf;
type Span = Range<usize>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct File { pub struct File {
name: PathBuf, pub name: PathBuf,
items: Vec<Item>, pub items: Vec<Stmt>, // todo make item
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Ty { pub struct Ty {
span: Span, pub span: Span,
kind: TyKind, pub kind: TyKind,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -28,31 +29,31 @@ pub enum Item {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct FnDecl { pub struct FnDecl {
name: String, pub name: String,
params: Vec<FnParam>, pub params: Vec<FnParam>,
ret_ty: Ty, pub ret_ty: Ty,
span: Span, pub span: Span,
body: Vec<Stmt>, pub body: Vec<Stmt>,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct FnParam { pub struct FnParam {
name: String, pub name: String,
ty: Ty, pub ty: Ty,
span: Span, pub span: Span,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct StructDecl { pub struct StructDecl {
name: String, pub name: String,
span: Span, pub span: Span,
fields: Vec<StructField>, pub fields: Vec<StructField>,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct StructField { pub struct StructField {
name: String, pub name: String,
ty: Ty, pub ty: Ty,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -68,25 +69,25 @@ pub enum Stmt {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct VarDecl { pub struct VarDecl {
name: String, pub name: String,
ty: Ty, pub ty: Ty,
rhs: Option<Expr>, pub rhs: Option<Expr>,
span: Span, pub span: Span,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Assignment { pub struct Assignment {
place: Place, pub place: Expr,
rhs: Expr, pub rhs: Expr,
span: Span, pub span: Span,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct IfStmt { pub struct IfStmt {
cond: Expr, pub cond: Expr,
body: Vec<Stmt>, pub body: Vec<Stmt>,
else_part: Option<ElsePart>, pub else_part: Option<ElsePart>,
span: Span, pub span: Span,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -97,35 +98,44 @@ pub enum ElsePart {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct WhileStmt { pub struct WhileStmt {
cond: Expr, pub cond: Expr,
body: Vec<Stmt>, pub body: Vec<Stmt>,
span: Span, pub span: Span,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct LoopStmt { pub struct LoopStmt {
body: Vec<Stmt>, pub body: Vec<Stmt>,
span: Span, pub span: Span,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Expr { pub enum Expr {
BinOp(BinOp), BinOp(BinOp),
Place(Place), FieldAccess(FieldAccess),
Call(Call), Call(Call),
Deref(Box<Expr>), Deref(Box<Expr>),
Literal(Literal),
Name(String),
Array(Vec<Expr>),
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct BinOp { pub struct BinOp {
kind: BinOpKind, pub kind: BinOpKind,
lhs: Box<Expr>, pub lhs: Box<Expr>,
rhs: Box<Expr>, pub rhs: Box<Expr>,
span: Span, pub span: Span,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum BinOpKind { pub enum BinOpKind {
Eq,
Neq,
Gt,
Lt,
GtEq,
LtEq,
Add, Add,
Sub, Sub,
Mul, Mul,
@ -140,20 +150,20 @@ pub enum BinOpKind {
Xor, Xor,
} }
#[derive(Debug, Clone, PartialEq)]
pub enum Place {
FieldAccess(FieldAccess),
Name(String),
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct FieldAccess { pub struct FieldAccess {
expr: Box<Expr>, pub expr: Box<Expr>,
field_name: String, pub field_name: String,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Call { pub struct Call {
callee: Box<Expr>, pub callee: Box<Expr>,
args: Vec<Expr>, pub args: Vec<Expr>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Literal {
String(String, Span),
Integer(u64, Span),
} }

View file

@ -1,6 +1,6 @@
use logos::Logos; use logos::Logos;
#[derive(Logos, Debug, PartialEq)] #[derive(Logos, Debug, Clone, Hash, PartialEq, Eq)]
pub enum Token<'a> { pub enum Token<'a> {
#[regex("//[^\n]*", logos::skip)] #[regex("//[^\n]*", logos::skip)]
Comment, Comment,

View file

@ -5,7 +5,7 @@ use std::path::PathBuf;
mod ast; mod ast;
mod lexer; mod lexer;
mod span; mod parser;
pub fn parse(_str: &str, _file_name: PathBuf) -> Result<ast::File, ()> { pub fn parse(_str: &str, _file_name: PathBuf) -> Result<ast::File, ()> {
todo!() todo!()

168
ub_parser/src/parser.rs Normal file
View file

@ -0,0 +1,168 @@
use std::{ops::Range, path::PathBuf};
use chumsky::{prelude::*, Stream};
use crate::{
ast::{BinOp, BinOpKind, Call, Expr, File, Literal, Stmt},
lexer::Token,
};
type Error<'src> = Simple<Token<'src>>;
type Span = Range<usize>;
fn ident_parser<'src>() -> impl Parser<Token<'src>, &'src str, Error = Error<'src>> + Clone {
filter_map(|span, tok| match tok {
Token::Ident(ident) => Ok(ident),
_ => Err(Simple::expected_input_found(span, Vec::new(), Some(tok))),
})
.labelled("identifier")
}
fn expr_parser<'src>() -> impl Parser<Token<'src>, Expr, Error = Error<'src>> + Clone {
recursive(|expr| {
let literal = filter_map(|span, token| match token {
Token::String(str) => Ok(Expr::Literal(Literal::String(
str[1..str.len() - 2].to_owned(),
span,
))),
// todo lol unwrap
Token::Integer(int) => Ok(Expr::Literal(Literal::Integer(int.parse().unwrap(), span))),
_ => Err(Simple::expected_input_found(span, Vec::new(), Some(token))),
})
.labelled("literal");
// A list of expressions
let items = expr
.clone()
.chain(just(Token::Comma).ignore_then(expr.clone()).repeated())
.then_ignore(just(Token::Comma).or_not())
.or_not()
.map(|item| item.unwrap_or_else(Vec::new));
let array = items
.clone()
.delimited_by(just(Token::BracketO), just(Token::BracketC))
.map(Expr::Array);
let atom = literal
.or(ident_parser().map(|str| Expr::Name(str.to_owned())))
.or(array)
.or(expr
.clone()
.delimited_by(just(Token::ParenO), just(Token::ParenC)));
let call = atom
.then(
items
.delimited_by(just(Token::ParenO), just(Token::ParenC))
.repeated(),
)
.foldl(|callee, args| {
Expr::Call(Call {
callee: Box::new(callee),
args,
})
});
let op = just(Token::Asterisk)
.to(BinOpKind::Mul)
.or(just(Token::Slash).to(BinOpKind::Div));
let product = call
.clone()
.then(op.then(call).repeated())
.foldl(|a, (kind, b)| {
Expr::BinOp(BinOp {
kind,
lhs: Box::new(a),
rhs: Box::new(b),
span: 0..0, // lol todo
})
});
// Sum ops (add and subtract) have equal precedence
let op = just(Token::Plus)
.to(BinOpKind::Add)
.or(just(Token::Minus).to(BinOpKind::Sub));
let sum = product
.clone()
.then(op.then(product).repeated())
.foldl(|a, (kind, b)| {
Expr::BinOp(BinOp {
kind,
lhs: Box::new(a),
rhs: Box::new(b),
span: 0..0, // lol todo
})
});
// Comparison ops (equal, not-equal) have equal precedence
let op = just(Token::EqEq)
.to(BinOpKind::Eq)
.or(just(Token::BangEq).to(BinOpKind::Neq));
let compare = sum
.clone()
.then(op.then(sum).repeated())
.foldl(|a, (kind, b)| {
Expr::BinOp(BinOp {
kind,
lhs: Box::new(a),
rhs: Box::new(b),
span: 0..0, // lol todo
})
});
compare
})
}
fn file_parser<'src>(
file_name: PathBuf,
) -> impl Parser<Token<'src>, File, Error = Error<'src>> + Clone {
expr_parser()
.map(move |expr| File {
name: file_name.clone(),
items: vec![Stmt::Expr(expr)],
})
.then_ignore(just(Token::Semi))
}
pub fn parse<'src, I>(lexer: I, len: usize, file_name: PathBuf) -> (Option<File>, Vec<Error<'src>>)
where
I: 'src,
I: Iterator<Item = (Token<'src>, Span)>,
{
file_parser(file_name).parse_recovery(Stream::from_iter(len..len + 1, lexer))
}
#[cfg(test)]
mod tests {
use std::{fmt::Debug, path::PathBuf};
use logos::Logos;
use crate::lexer::Token;
fn parse(src: &str) -> impl Debug + '_ {
let lexer = Token::lexer(src);
let len = lexer.source().len();
super::parse(
lexer.spanned(),
len,
PathBuf::from(module_path!().replace("::", "__")),
)
}
#[test]
fn addition() {
let r = parse("1 + 4;");
insta::assert_debug_snapshot!(r);
}
#[test]
fn expression() {
let r = parse("(4 / hallo()) + 5;");
insta::assert_debug_snapshot!(r)
}
}

View file

@ -0,0 +1,34 @@
---
source: ub_parser/src/parser.rs
expression: r
---
(
Some(
File {
name: "ub_parser__parser__tests",
items: [
Expr(
BinOp(
BinOp {
kind: Add,
lhs: Literal(
Integer(
1,
0..1,
),
),
rhs: Literal(
Integer(
4,
4..5,
),
),
span: 0..0,
},
),
),
],
},
),
[],
)

View file

@ -0,0 +1,48 @@
---
source: ub_parser/src/parser.rs
expression: r
---
(
Some(
File {
name: "ub_parser__parser__tests",
items: [
Expr(
BinOp(
BinOp {
kind: Add,
lhs: BinOp(
BinOp {
kind: Div,
lhs: Literal(
Integer(
4,
1..2,
),
),
rhs: Call(
Call {
callee: Name(
"hallo",
),
args: [],
},
),
span: 0..0,
},
),
rhs: Literal(
Integer(
5,
16..17,
),
),
span: 0..0,
},
),
),
],
},
),
[],
)

View file

@ -1,22 +0,0 @@
use std::ops::Range;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Span {
start: usize,
len: usize,
}
impl Span {
pub fn start_end(start: usize, end: usize) -> Self {
Self {
start,
len: end - start,
}
}
}
impl From<Range<usize>> for Span {
fn from(r: Range<usize>) -> Self {
Self::start_end(r.start, r.end)
}
}