Skip to content

Commit ff0fd08

Browse files
committed
chore: parsing tests
1 parent 25d8b0c commit ff0fd08

File tree

11 files changed

+160
-42
lines changed

11 files changed

+160
-42
lines changed

README.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,39 @@
1-
# another "scripting language" lol
2-
this one will transpile to bash
1+
# Another "scripting language"
2+
This one will transpile to various targets (BASH, PowerShell etc.)
33

4-
```ruby
4+
```js
55
var my_variable = 512
66

77
fn awesome(name: String): String {
8-
$echo "Hello {name}!"
8+
$echo "Hello #{name}!"
99

1010
$echo hello world
1111

12-
return $echo(this gets returned to the function explicitly)
12+
return $echo this gets returned to the function explicitly
1313
}
1414

15-
$echo "return value: {awesome("Rust")}"
15+
$echo "return value: #{awesome("Rust")}"
16+
```
1617
18+
```js
1719
fn add(a: Int, b: Int): Int {
1820
a + b # implicit return
1921
}
2022
21-
$echo(5 + 2 = { add(5, 2) }) # prints '5 + 2 = 7'
23+
for i in 0..=5 {
24+
// prints '1 + 2 = 3', '2 + 3 = 4'...
25+
$echo "#{i} + #{i + 1} = #{add(i, i + 1)}
26+
}
27+
```
28+
29+
```js
30+
$read(-p "login: ") // sets the $REPLY variable
31+
32+
var input = REPLY // shell variables are treated like normal variables
33+
var msg = match input {
34+
"Admin" => "Access granted."
35+
* => "Denied."
36+
}
37+
38+
$echo #{msg} // templating
2239
```

packages/engine/src/component.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub trait ComponentErrors {
1919
fn source(&self) -> &crate::error::SourceFile;
2020

2121
#[cfg(feature = "cli")]
22-
fn get_source_sliced(&self, start: crate::Cursor, end: crate::Cursor) -> crate::error::SourceFile {
22+
fn get_source_sliced(&self, start: crate::cursor::Cursor, end: crate::cursor::Cursor) -> crate::error::SourceFile {
2323
let source_file = self.source();
2424

2525
let start_index = start.index() as usize;

packages/engine/src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ pub trait CodeError<T>
2828
where T: lang_macro::EnumVariantsTrait + ToString {
2929
fn kind(&self) -> &T;
3030
fn source_file(&self) -> &SourceFile;
31-
fn start(&self) -> &crate::Cursor;
32-
fn end(&self) -> &crate::Cursor;
31+
fn start(&self) -> &crate::cursor::Cursor;
32+
fn end(&self) -> &crate::cursor::Cursor;
3333

3434
fn format_error(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3535
writeln!(f,

packages/engine/src/lexer/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
component::{ComponentErrors, ComponentIter},
88
constants::{MAX_I32_LEN, MAX_I64_LEN},
99
error::{EngineErrorKind, ErrorList},
10-
Cursor,
10+
cursor::Cursor,
1111
};
1212

1313
pub use error::{LexerError, LexerErrorKind};

packages/engine/src/lexer/tokens.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use lang_macro::EnumVariantsTrait;
44

55
use crate::{
66
error::{EngineErrorKind, EngineResult},
7-
Cursor,
7+
cursor::Cursor,
88
};
99

1010
#[repr(u8)]

packages/engine/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ use lexer::Lexer;
1313

1414
pub mod component;
1515
pub mod constants;
16-
mod cursor;
16+
pub mod cursor;
1717
pub mod error;
1818
pub mod lexer;
1919
pub mod parser;
2020

21-
pub use cursor::Cursor;
2221
use parser::Parser;
2322

2423
#[derive(Default)]

packages/engine/src/parser/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ impl CodeError<ParserErrorKind> for ParserError {
5454
&self.source_file
5555
}
5656

57-
fn start(&self) -> &crate::Cursor {
57+
fn start(&self) -> &crate::cursor::Cursor {
5858
&self.start
5959
}
6060

61-
fn end(&self) -> &crate::Cursor {
61+
fn end(&self) -> &crate::cursor::Cursor {
6262
&self.end
6363
}
6464
}

packages/engine/src/parser/mod.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@ use error::ParserResult;
88

99
use crate::{
1010
component::{ComponentErrors, ComponentIter},
11-
cursor::WithCursor,
11+
cursor::{Cursor, WithCursor},
1212
error::{EngineErrorKind, ErrorList},
1313
lexer::tokens::{LexerToken, LexerTokenKind, LexerTokenList},
14-
Cursor,
1514
};
1615

1716
pub use error::{ParserError, ParserErrorKind};
@@ -25,6 +24,7 @@ pub struct Parser<'a> {
2524
token: Option<LexerToken>,
2625
cursor: Cursor,
2726
errors: ErrorList,
27+
tree: ProgramTree,
2828

2929
#[cfg(feature = "cli")]
3030
source: crate::error::SourceFile,
@@ -54,6 +54,7 @@ impl<'a> Parser<'a> {
5454
token: None,
5555
cursor: Cursor::create(),
5656
errors: ErrorList::new(),
57+
tree: ProgramTree::new(),
5758

5859
#[cfg(feature = "cli")]
5960
source,
@@ -64,12 +65,10 @@ impl<'a> Parser<'a> {
6465
}
6566

6667
// MARK: Parser Main
67-
pub fn parse(&mut self) -> ProgramTree {
68-
let mut statements = ProgramTree::new();
69-
68+
pub fn parse(&mut self) -> &ProgramTree {
7069
while let Some(token) = self.peek().cloned() {
7170
match self.parse_statement(token) {
72-
Ok(Some(statement)) => statements.push(statement),
71+
Ok(Some(statement)) => self.tree.push(statement),
7372
Err(err) => {
7473
debug!("adding error {err:?}");
7574
let token = self.token.as_ref().unwrap_or(token);
@@ -81,7 +80,7 @@ impl<'a> Parser<'a> {
8180
self.next();
8281
}
8382

84-
statements
83+
&self.tree
8584
}
8685

8786
fn add_error(&mut self, start: Cursor, end: Cursor, kind: ParserErrorKind) {
@@ -444,23 +443,24 @@ impl<'a> Parser<'a> {
444443

445444
// MARK: Unary
446445
fn expr_unary(&mut self) -> ParserResult<Option<WithCursor<Expression>>> {
447-
let_expr!(mut lhs = self.expr_func_invoke()?);
448-
449-
while let Some(token_unary) = self.next_if_eq(&&LexerTokenKind::Not) {
446+
let start = self.cursor;
447+
if let Some(token_unary) = self.next_if_eq(&&LexerTokenKind::Not) {
450448
let_expr!(rhs = self.expr_unary()?);
451-
449+
452450
let operator: UnaryOperator = token_unary.kind.clone().try_into()?;
453-
454-
lhs = WithCursor::create_with(
455-
lhs.start,
451+
452+
return Ok(Some(WithCursor::create_with(
453+
start,
456454
rhs.end,
457455
Expression::Unary(Box::from((
458456
WithCursor::create_with(token_unary.start, token_unary.end, operator),
459-
lhs,
457+
rhs,
460458
))),
461-
);
459+
)));
462460
}
463461

462+
let_expr!(lhs = self.expr_func_invoke()?);
463+
464464
Ok(Some(lhs))
465465
}
466466

@@ -762,10 +762,13 @@ impl<'a> Parser<'a> {
762762
match self.expect_any(&[&LexerTokenKind::EOL, &LexerTokenKind::EOF]) {
763763
Ok(found) => Ok(Some(found)),
764764
Err(None) => Ok(None),
765-
Err(Some(found)) => Err(ParserErrorKind::ExpectedToken(
766-
vec![LexerTokenKind::EOL, LexerTokenKind::EOF],
767-
Some(found.kind.clone()),
768-
)),
765+
Err(Some(found)) => {
766+
self.next();
767+
Err(ParserErrorKind::ExpectedToken(
768+
vec![LexerTokenKind::EOL, LexerTokenKind::EOF],
769+
Some(found.kind.clone()),
770+
))
771+
},
769772
}
770773
}
771774
}

packages/engine/tests/lexing.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ macro_rules! token_list_comparison {
1515

1616
pretty_assertions::assert_eq!(&expected, token_list);
1717

18-
use lang_engine::{Cursor, component::ComponentErrors};
18+
use lang_engine::{cursor::Cursor, component::ComponentErrors};
1919
if lexer.has_errors() {
2020
println!("{:#?}", lexer.fetch_errors());
2121
}

packages/engine/tests/parsing.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
macro_rules! token_list_comparison {
2+
($name:ident, $code:tt, [$($exp:expr),+]) => {
3+
#[test]
4+
fn $name() -> lang_engine::error::EngineResult<()> {
5+
#[allow(unused_imports)]
6+
use lang_engine::{parser::ast::{Statement, Expression, Variable, Function, Literal}, cursor::{WithCursor, Cursor}, component::ComponentErrors};
7+
let code = $code;
8+
9+
// Step 1
10+
let mut lexer = lang_engine::lexer::Lexer::create(code, None);
11+
lexer.tokens();
12+
13+
if lexer.has_errors() {
14+
println!("{:#?}", lexer.fetch_errors());
15+
}
16+
17+
// Step 2
18+
let source = lexer.source().clone();
19+
let mut parser = lang_engine::parser::Parser::create(lexer.tokens(), source);
20+
parser.parse();
21+
22+
let expected = vec![
23+
$($exp),+
24+
];
25+
26+
pretty_assertions::assert_eq!(&expected, parser.parse());
27+
28+
if parser.has_errors() {
29+
println!("{:#?}", parser.fetch_errors());
30+
}
31+
32+
Ok(())
33+
}
34+
};
35+
}
36+
37+
token_list_comparison!(
38+
basic_variable,
39+
"var test = 50",
40+
[Statement::Variable(Box::new(Variable {
41+
name: String::from("test"),
42+
strict_type: None,
43+
value: Some(WithCursor {
44+
value: Expression::Literal(Box::new(Literal::Integer(50))),
45+
start: Cursor::from(1, 12),
46+
end: Cursor::from(1, 14),
47+
})
48+
}))]
49+
);
50+
51+
token_list_comparison!(
52+
for_loop,
53+
"
54+
for i in 0..5 {
55+
$echo #{i}
56+
}
57+
",
58+
[Statement::For(Box::from((
59+
Variable {
60+
name: String::from("i"),
61+
strict_type: None,
62+
value: None,
63+
},
64+
WithCursor::create_with(
65+
Cursor::from_full(1, 10, 9),
66+
Cursor::from_full(1, 14, 13),
67+
Expression::Range(Box::from((
68+
WithCursor::create_with(
69+
Cursor::from_full(1, 10, 9),
70+
Cursor::from_full(1, 11, 10),
71+
Expression::Literal(Box::from(Literal::Integer(0)))
72+
),
73+
WithCursor::create_with(
74+
Cursor::from_full(1, 13, 12),
75+
Cursor::from_full(1, 14, 13),
76+
Expression::Literal(Box::from(Literal::Integer(5)))
77+
),
78+
false
79+
)))
80+
),
81+
WithCursor::create_with(
82+
Cursor::from_full(2, 1, 16),
83+
Cursor::from_full(3, 2, 32),
84+
vec![
85+
Statement::Expression(Box::from(
86+
WithCursor::create_with(
87+
Cursor::from_full(2, 5, 20),
88+
Cursor::from_full(2, 15, 30),
89+
Expression::ShellCommand(
90+
Box::from((
91+
String::from("echo"),
92+
Some(
93+
String::from("#{i}"),
94+
),
95+
)),
96+
)),
97+
),
98+
),
99+
],
100+
),
101+
)))]
102+
);

0 commit comments

Comments
 (0)