feat(parser): parse tokens into commands
This commit is contained in:
parent
f634da3318
commit
d568653a17
17 changed files with 381 additions and 0 deletions
|
|
@ -179,6 +179,14 @@ CLOCK: [2025-05-04 dim. 13:45]--[2025-05-04 dim. 13:56] => 0:11
|
||||||
:EFFORT: 10
|
:EFFORT: 10
|
||||||
:END:
|
:END:
|
||||||
|
|
||||||
|
*** DONE create a generic parse command that parses string into tokens into Command
|
||||||
|
:PROPERTIES:
|
||||||
|
:EFFORT: 10
|
||||||
|
:END:
|
||||||
|
:LOGBOOK:
|
||||||
|
CLOCK: [2025-05-04 dim. 14:01]--[2025-05-04 dim. 14:14] => 0:13
|
||||||
|
:END:
|
||||||
|
|
||||||
*** TODO parse tokens into meta-commands
|
*** TODO parse tokens into meta-commands
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:EFFORT: 10
|
:EFFORT: 10
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,6 @@ pub mod cli;
|
||||||
pub mod command;
|
pub mod command;
|
||||||
pub mod error_display;
|
pub mod error_display;
|
||||||
pub mod meta_commands;
|
pub mod meta_commands;
|
||||||
|
pub mod parser;
|
||||||
pub mod statements;
|
pub mod statements;
|
||||||
pub mod tokens;
|
pub mod tokens;
|
||||||
|
|
|
||||||
83
src/parser.rs
Normal file
83
src/parser.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
command::{Command, CommandParseError},
|
||||||
|
statements::Statement,
|
||||||
|
tokens::tokenize,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn parse(file: String, input: String) -> Result<Vec<Command>, Vec<CommandParseError>> {
|
||||||
|
let mut tokens: VecDeque<_> = tokenize(input, file)
|
||||||
|
.map_err(|x| x.into_iter().map(|x| x.into()).collect::<Vec<_>>())?
|
||||||
|
.into();
|
||||||
|
let mut cmds = Vec::new();
|
||||||
|
let errs = Vec::new();
|
||||||
|
while let Some(token) = tokens.pop_front() {
|
||||||
|
match token.data {
|
||||||
|
crate::tokens::TokenData::Insert => cmds.push(Command::Statement(Statement::Insert)),
|
||||||
|
crate::tokens::TokenData::Select => cmds.push(Command::Statement(Statement::Select)),
|
||||||
|
crate::tokens::TokenData::MetaCommand(meta_command) => {
|
||||||
|
cmds.push(Command::MetaCommand(meta_command))
|
||||||
|
}
|
||||||
|
crate::tokens::TokenData::EndOfFile => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if errs.is_empty() {
|
||||||
|
Ok(cmds)
|
||||||
|
} else {
|
||||||
|
Err(errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use insta::assert_debug_snapshot;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_single_correct() {
|
||||||
|
let file = String::from("<stdin>");
|
||||||
|
assert_debug_snapshot!(parse(file.clone(), String::from(".exit")));
|
||||||
|
assert_debug_snapshot!(parse(file.clone(), String::from("select")));
|
||||||
|
assert_debug_snapshot!(parse(file.clone(), String::from("sElEcT")));
|
||||||
|
assert_debug_snapshot!(parse(file.clone(), String::from("INSERT")));
|
||||||
|
assert_debug_snapshot!(parse(file.clone(), String::from("InSErT")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_single_incorrect() {
|
||||||
|
let file = String::from("<stdin>");
|
||||||
|
assert_debug_snapshot!(parse(file.clone(), String::from(".halp")));
|
||||||
|
assert_debug_snapshot!(parse(file.clone(), String::from("salect")));
|
||||||
|
assert_debug_snapshot!(parse(file.clone(), String::from("sAlEcT")));
|
||||||
|
assert_debug_snapshot!(parse(file.clone(), String::from("INSART")));
|
||||||
|
assert_debug_snapshot!(parse(file.clone(), String::from("InSArT")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_multiple_correct() {
|
||||||
|
let file = String::from("<stdin>");
|
||||||
|
assert_debug_snapshot!(parse(
|
||||||
|
file.clone(),
|
||||||
|
String::from(".exit select select insert select")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_multiple_incorrect() {
|
||||||
|
let file = String::from("<stdin>");
|
||||||
|
assert_debug_snapshot!(parse(
|
||||||
|
file.clone(),
|
||||||
|
String::from(".halp salect selact inset seiect")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_multiple_mixed() {
|
||||||
|
let file = String::from("<stdin>");
|
||||||
|
assert_debug_snapshot!(parse(
|
||||||
|
file.clone(),
|
||||||
|
String::from(".exit selct select nsert select")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/snapshots/osdb__parser__tests__parse_exit.snap
Normal file
11
src/snapshots/osdb__parser__tests__parse_exit.snap
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file, String::from(\".exit\"))"
|
||||||
|
---
|
||||||
|
Ok(
|
||||||
|
[
|
||||||
|
MetaCommand(
|
||||||
|
Exit,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\".exit select select insert select\"))"
|
||||||
|
---
|
||||||
|
Ok(
|
||||||
|
[
|
||||||
|
MetaCommand(
|
||||||
|
Exit,
|
||||||
|
),
|
||||||
|
Statement(
|
||||||
|
Select,
|
||||||
|
),
|
||||||
|
Statement(
|
||||||
|
Select,
|
||||||
|
),
|
||||||
|
Statement(
|
||||||
|
Insert,
|
||||||
|
),
|
||||||
|
Statement(
|
||||||
|
Select,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\".halp salect selact inset seiect\"))"
|
||||||
|
---
|
||||||
|
Err(
|
||||||
|
[
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 0,
|
||||||
|
length: 5,
|
||||||
|
},
|
||||||
|
kind: UnknownMetaCommand(
|
||||||
|
".halp",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 6,
|
||||||
|
length: 6,
|
||||||
|
},
|
||||||
|
kind: UnknownKeyword(
|
||||||
|
"salect",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 13,
|
||||||
|
length: 6,
|
||||||
|
},
|
||||||
|
kind: UnknownKeyword(
|
||||||
|
"selact",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 20,
|
||||||
|
length: 5,
|
||||||
|
},
|
||||||
|
kind: UnknownKeyword(
|
||||||
|
"inset",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 26,
|
||||||
|
length: 6,
|
||||||
|
},
|
||||||
|
kind: UnknownKeyword(
|
||||||
|
"seiect",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
32
src/snapshots/osdb__parser__tests__parse_multiple_mixed.snap
Normal file
32
src/snapshots/osdb__parser__tests__parse_multiple_mixed.snap
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\".exit selct select nsert select\"))"
|
||||||
|
---
|
||||||
|
Err(
|
||||||
|
[
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 6,
|
||||||
|
length: 5,
|
||||||
|
},
|
||||||
|
kind: UnknownKeyword(
|
||||||
|
"selct",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 19,
|
||||||
|
length: 5,
|
||||||
|
},
|
||||||
|
kind: UnknownKeyword(
|
||||||
|
"nsert",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\"select\"))"
|
||||||
|
---
|
||||||
|
Ok(
|
||||||
|
[
|
||||||
|
Statement(
|
||||||
|
Select,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\"sElEcT\"))"
|
||||||
|
---
|
||||||
|
Ok(
|
||||||
|
[
|
||||||
|
Statement(
|
||||||
|
Select,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\"INSERT\"))"
|
||||||
|
---
|
||||||
|
Ok(
|
||||||
|
[
|
||||||
|
Statement(
|
||||||
|
Insert,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\"InSErT\"))"
|
||||||
|
---
|
||||||
|
Ok(
|
||||||
|
[
|
||||||
|
Statement(
|
||||||
|
Insert,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
11
src/snapshots/osdb__parser__tests__parse_single_correct.snap
Normal file
11
src/snapshots/osdb__parser__tests__parse_single_correct.snap
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\".exit\"))"
|
||||||
|
---
|
||||||
|
Ok(
|
||||||
|
[
|
||||||
|
MetaCommand(
|
||||||
|
Exit,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\"salect\"))"
|
||||||
|
---
|
||||||
|
Err(
|
||||||
|
[
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 0,
|
||||||
|
length: 6,
|
||||||
|
},
|
||||||
|
kind: UnknownKeyword(
|
||||||
|
"salect",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\"sAlEcT\"))"
|
||||||
|
---
|
||||||
|
Err(
|
||||||
|
[
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 0,
|
||||||
|
length: 6,
|
||||||
|
},
|
||||||
|
kind: UnknownKeyword(
|
||||||
|
"sAlEcT",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\"INSART\"))"
|
||||||
|
---
|
||||||
|
Err(
|
||||||
|
[
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 0,
|
||||||
|
length: 6,
|
||||||
|
},
|
||||||
|
kind: UnknownKeyword(
|
||||||
|
"INSART",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\"InSArT\"))"
|
||||||
|
---
|
||||||
|
Err(
|
||||||
|
[
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 0,
|
||||||
|
length: 6,
|
||||||
|
},
|
||||||
|
kind: UnknownKeyword(
|
||||||
|
"InSArT",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: src/parser.rs
|
||||||
|
expression: "parse(file.clone(), String::from(\".halp\"))"
|
||||||
|
---
|
||||||
|
Err(
|
||||||
|
[
|
||||||
|
Scan(
|
||||||
|
ScanError {
|
||||||
|
location: Location {
|
||||||
|
file: "<stdin>",
|
||||||
|
offset: 0,
|
||||||
|
length: 5,
|
||||||
|
},
|
||||||
|
kind: UnknownMetaCommand(
|
||||||
|
".halp",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue