mirror of
https://github.com/Noratrieb/ub.git
synced 2026-01-16 09:35:05 +01:00
something works at least
This commit is contained in:
parent
aa4da62e2c
commit
b1756c7c21
7 changed files with 234 additions and 64 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
|
@ -11,6 +11,15 @@ dependencies = [
|
||||||
"const-random",
|
"const-random",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ariadne"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1cb2a2046bea8ce5e875551f5772024882de0b540c7f93dfc5d6cf1ca8b030c"
|
||||||
|
dependencies = [
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
@ -190,6 +199,7 @@ checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||||
name = "parser"
|
name = "parser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ariadne",
|
||||||
"chumsky",
|
"chumsky",
|
||||||
"insta",
|
"insta",
|
||||||
"logos",
|
"logos",
|
||||||
|
|
@ -365,3 +375,9 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
ariadne = "0.1.5"
|
||||||
chumsky = "0.8.0"
|
chumsky = "0.8.0"
|
||||||
logos = "0.12.0"
|
logos = "0.12.0"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
|
|
||||||
#[derive(Logos, Debug, Clone, Hash, PartialEq, Eq)]
|
#[derive(Logos, Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
|
|
@ -91,6 +93,52 @@ pub enum Token<'a> {
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Display for Token<'a> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Token::Comment => f.write_str("comment"),
|
||||||
|
Token::BraceO => f.write_str("{"),
|
||||||
|
Token::BraceC => f.write_str("}"),
|
||||||
|
Token::BracketO => f.write_str("["),
|
||||||
|
Token::BracketC => f.write_str("]"),
|
||||||
|
Token::ParenO => f.write_str("("),
|
||||||
|
Token::ParenC => f.write_str(")"),
|
||||||
|
Token::Dot => f.write_str("."),
|
||||||
|
Token::Comma => f.write_str(","),
|
||||||
|
Token::Semi => f.write_str(";"),
|
||||||
|
Token::Eq => f.write_str("="),
|
||||||
|
Token::EqEq => f.write_str("=="),
|
||||||
|
Token::Bang => f.write_str("!"),
|
||||||
|
Token::BangEq => f.write_str("!="),
|
||||||
|
Token::Greater => f.write_str(">"),
|
||||||
|
Token::Less => f.write_str("<"),
|
||||||
|
Token::GreaterEq => f.write_str(">="),
|
||||||
|
Token::LessEq => f.write_str("<="),
|
||||||
|
Token::Asterisk => f.write_str("*"),
|
||||||
|
Token::Slash => f.write_str("/"),
|
||||||
|
Token::Plus => f.write_str("+"),
|
||||||
|
Token::Minus => f.write_str("-"),
|
||||||
|
Token::Or => f.write_str("|"),
|
||||||
|
Token::And => f.write_str("&"),
|
||||||
|
Token::OrOr => f.write_str("||"),
|
||||||
|
Token::AndAnd => f.write_str("&&"),
|
||||||
|
Token::Caret => f.write_str("^"),
|
||||||
|
Token::Arrow => f.write_str("->"),
|
||||||
|
Token::Colon => f.write_str(":"),
|
||||||
|
Token::Struct => f.write_str("struct"),
|
||||||
|
Token::Fn => f.write_str("fn"),
|
||||||
|
Token::If => f.write_str("if"),
|
||||||
|
Token::Else => f.write_str("else"),
|
||||||
|
Token::While => f.write_str("while"),
|
||||||
|
Token::Loop => f.write_str("loop"),
|
||||||
|
Token::Ident(ident) => write!(f, "identifier `{ident}`"),
|
||||||
|
Token::String(str) => write!(f, "\"{str}\""),
|
||||||
|
Token::Integer(int) => write!(f, "{int}"),
|
||||||
|
Token::Error => f.write_str("error"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lex<'src>(code: &'src str) -> logos::Lexer<'_, Token<'src>> {
|
pub fn lex<'src>(code: &'src str) -> logos::Lexer<'_, Token<'src>> {
|
||||||
Token::lexer(code)
|
Token::lexer(code)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use ariadne::{Color, Fmt, Label, Report, ReportKind, Source};
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
|
|
||||||
use crate::lexer::Token;
|
use crate::lexer::Token;
|
||||||
|
|
@ -16,16 +17,89 @@ pub fn parse(_str: &str, _file_name: PathBuf) -> Result<ast::File, ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test() {
|
pub fn test() {
|
||||||
let lexer = Token::lexer(
|
let src = "
|
||||||
"
|
|
||||||
fn main() {
|
fn main() {
|
||||||
if 1 { 5 + 5; }
|
// if 1 { 5 + 5; }
|
||||||
|
u64 hello = 5;
|
||||||
}
|
}
|
||||||
",
|
";
|
||||||
);
|
|
||||||
|
let lexer = Token::lexer(src);
|
||||||
let len = lexer.source().len();
|
let len = lexer.source().len();
|
||||||
|
|
||||||
let r = parser::parse(lexer.spanned(), len, "test_file".into());
|
let (file, errors) = parser::parse(lexer.spanned(), len, "test_file".into());
|
||||||
|
|
||||||
println!("{r:#?}");
|
if let Some(file) = file {
|
||||||
|
println!("AST: {file:#?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
errors
|
||||||
|
.into_iter()
|
||||||
|
.map(|e| e.map(|c| c.to_string()))
|
||||||
|
.for_each(|e| {
|
||||||
|
let report = Report::build(ReportKind::Error, (), e.span().start);
|
||||||
|
|
||||||
|
let report = match e.reason() {
|
||||||
|
chumsky::error::SimpleReason::Unclosed { span, delimiter } => report
|
||||||
|
.with_message(format!(
|
||||||
|
"Unclosed delimiter {}",
|
||||||
|
delimiter.fg(Color::Yellow)
|
||||||
|
))
|
||||||
|
.with_label(
|
||||||
|
Label::new(span.clone())
|
||||||
|
.with_message(format!(
|
||||||
|
"Unclosed delimiter {}",
|
||||||
|
delimiter.fg(Color::Yellow)
|
||||||
|
))
|
||||||
|
.with_color(Color::Yellow),
|
||||||
|
)
|
||||||
|
.with_label(
|
||||||
|
Label::new(e.span())
|
||||||
|
.with_message(format!(
|
||||||
|
"Must be closed before this {}",
|
||||||
|
e.found()
|
||||||
|
.unwrap_or(&"end of file".to_string())
|
||||||
|
.fg(Color::Red)
|
||||||
|
))
|
||||||
|
.with_color(Color::Red),
|
||||||
|
),
|
||||||
|
chumsky::error::SimpleReason::Unexpected => report
|
||||||
|
.with_message(format!(
|
||||||
|
"{}, expected {}",
|
||||||
|
if e.found().is_some() {
|
||||||
|
"Unexpected token in input"
|
||||||
|
} else {
|
||||||
|
"Unexpected end of input"
|
||||||
|
},
|
||||||
|
if e.expected().len() == 0 {
|
||||||
|
"something else".to_string()
|
||||||
|
} else {
|
||||||
|
e.expected()
|
||||||
|
.map(|expected| match expected {
|
||||||
|
Some(expected) => expected.to_string(),
|
||||||
|
None => "end of input".to_string(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
}
|
||||||
|
))
|
||||||
|
.with_label(
|
||||||
|
Label::new(e.span())
|
||||||
|
.with_message(format!(
|
||||||
|
"Unexpected token {}",
|
||||||
|
e.found()
|
||||||
|
.unwrap_or(&"end of file".to_string())
|
||||||
|
.fg(Color::Red)
|
||||||
|
))
|
||||||
|
.with_color(Color::Red),
|
||||||
|
),
|
||||||
|
chumsky::error::SimpleReason::Custom(msg) => report.with_message(msg).with_label(
|
||||||
|
Label::new(e.span())
|
||||||
|
.with_message(format!("{}", msg.fg(Color::Red)))
|
||||||
|
.with_color(Color::Red),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
report.finish().print(Source::from(&src)).unwrap();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -156,35 +156,38 @@ fn statement_parser<'src>() -> impl Parser<Token<'src>, Stmt, Error = Error<'src
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let if_stmt = recursive(|if_stmt| {
|
// let if_stmt = recursive(|if_stmt| {
|
||||||
just(Token::If)
|
// just(Token::If)
|
||||||
.ignore_then(expr_parser())
|
// .ignore_then(expr_parser())
|
||||||
.then(
|
// .then(
|
||||||
stmt.clone()
|
// stmt.clone()
|
||||||
.repeated()
|
// .repeated()
|
||||||
.delimited_by(just(Token::BraceO), just(Token::BraceC)),
|
// .delimited_by(just(Token::BraceO), just(Token::BraceC)),
|
||||||
)
|
// )
|
||||||
.then(
|
// .then(
|
||||||
just(Token::Else).ignore_then(
|
// just(Token::Else).ignore_then(
|
||||||
if_stmt
|
// if_stmt
|
||||||
.map(|if_stmt| ElsePart::ElseIf(Box::new(if_stmt)))
|
// .map(|if_stmt| ElsePart::ElseIf(Box::new(if_stmt)))
|
||||||
.or(stmt
|
// .or(stmt
|
||||||
.clone()
|
// .clone()
|
||||||
.repeated()
|
// .repeated()
|
||||||
.delimited_by(just(Token::BraceO), just(Token::BraceC))
|
// .delimited_by(just(Token::BraceO), just(Token::BraceC))
|
||||||
.map_with_span(ElsePart::Else))
|
// .map_with_span(ElsePart::Else))
|
||||||
.or_not(),
|
// .or_not(),
|
||||||
),
|
// ),
|
||||||
)
|
// )
|
||||||
.map_with_span(|((cond, body), else_part), span| IfStmt {
|
// .map_with_span(|((cond, body), else_part), span| IfStmt {
|
||||||
cond,
|
// cond,
|
||||||
body,
|
// body,
|
||||||
else_part,
|
// else_part,
|
||||||
span,
|
// span,
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
.map(Stmt::IfStmt);
|
// .map(Stmt::IfStmt);
|
||||||
choice((var_decl, assignment, if_stmt, expr_parser().map(Stmt::Expr)))
|
|
||||||
|
var_decl
|
||||||
|
.or(assignment)
|
||||||
|
.or(expr_parser().map(Stmt::Expr))
|
||||||
.then_ignore(just(Token::Semi))
|
.then_ignore(just(Token::Semi))
|
||||||
})
|
})
|
||||||
.labelled("statement")
|
.labelled("statement")
|
||||||
|
|
@ -257,10 +260,10 @@ fn file_parser<'src>(
|
||||||
file_name: PathBuf,
|
file_name: PathBuf,
|
||||||
) -> impl Parser<Token<'src>, File, Error = Error<'src>> + Clone {
|
) -> impl Parser<Token<'src>, File, Error = Error<'src>> + Clone {
|
||||||
item_parser()
|
item_parser()
|
||||||
.repeated()
|
// .repeated()
|
||||||
.map(move |items| File {
|
.map(move |items| File {
|
||||||
name: file_name.clone(),
|
name: file_name.clone(),
|
||||||
items,
|
items: vec![items],
|
||||||
})
|
})
|
||||||
.labelled("file")
|
.labelled("file")
|
||||||
}
|
}
|
||||||
|
|
@ -301,30 +304,24 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn expression() {
|
fn expression() {
|
||||||
let r = parse("fn main() { (4 / hallo()) + 5; }");
|
let r = parse("fn main() { (4 / hallo()) + 5; }");
|
||||||
insta::assert_debug_snapshot!(r)
|
insta::assert_debug_snapshot!(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn function() {
|
fn function() {
|
||||||
let r = parse("fn foo() -> u64 { 1 + 5; }");
|
let r = parse("fn foo() -> u64 { 1 + 5; }");
|
||||||
insta::assert_debug_snapshot!(r)
|
insta::assert_debug_snapshot!(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#[test]
|
|
||||||
//fn nested_function() {
|
|
||||||
// let r = parse("fn foo() { fn foo2() {} fn foo3() {} }");
|
|
||||||
// insta::assert_debug_snapshot!(r)
|
|
||||||
//}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nested_function2() {
|
fn var_decl() {
|
||||||
let r = parse("fn foo() { fn foo2() {} 1 + 5; }");
|
let r = parse("fn foo() -> u64 { u64 hello = 5; }");
|
||||||
insta::assert_debug_snapshot!(r)
|
insta::assert_debug_snapshot!(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn struct_() {
|
fn struct_() {
|
||||||
let r = parse("struct X { y: u64, x: u64 }");
|
let r = parse("struct X { y: u64, x: u64 }");
|
||||||
insta::assert_debug_snapshot!(r)
|
insta::assert_debug_snapshot!(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
---
|
|
||||||
source: parser/src/parser.rs
|
|
||||||
assertion_line: 330
|
|
||||||
expression: r
|
|
||||||
---
|
|
||||||
(
|
|
||||||
Some(
|
|
||||||
File {
|
|
||||||
name: "parser__parser__tests",
|
|
||||||
items: [],
|
|
||||||
},
|
|
||||||
),
|
|
||||||
[],
|
|
||||||
)
|
|
||||||
48
parser/src/snapshots/parser__parser__tests__var_decl.snap
Normal file
48
parser/src/snapshots/parser__parser__tests__var_decl.snap
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
---
|
||||||
|
source: parser/src/parser.rs
|
||||||
|
assertion_line: 319
|
||||||
|
expression: r
|
||||||
|
---
|
||||||
|
(
|
||||||
|
Some(
|
||||||
|
File {
|
||||||
|
name: "parser__parser__tests",
|
||||||
|
items: [
|
||||||
|
FnDecl(
|
||||||
|
FnDecl {
|
||||||
|
name: "foo",
|
||||||
|
params: [],
|
||||||
|
ret_ty: Some(
|
||||||
|
Ty {
|
||||||
|
span: 12..15,
|
||||||
|
kind: U64,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
span: 0..2,
|
||||||
|
body: [
|
||||||
|
VarDecl(
|
||||||
|
VarDecl {
|
||||||
|
name: "hello",
|
||||||
|
ty: Ty {
|
||||||
|
span: 18..21,
|
||||||
|
kind: U64,
|
||||||
|
},
|
||||||
|
rhs: Some(
|
||||||
|
Literal(
|
||||||
|
Integer(
|
||||||
|
5,
|
||||||
|
30..31,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
span: 0..0,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue