feat(parser): parse tokens into commands

This commit is contained in:
Khaïs COLIN 2025-05-04 14:09:33 +02:00
parent f634da3318
commit d568653a17
17 changed files with 381 additions and 0 deletions

View file

@ -3,5 +3,6 @@ pub mod cli;
pub mod command;
pub mod error_display;
pub mod meta_commands;
pub mod parser;
pub mod statements;
pub mod tokens;

83
src/parser.rs Normal file
View 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")
));
}
}

View file

@ -0,0 +1,11 @@
---
source: src/parser.rs
expression: "parse(file, String::from(\".exit\"))"
---
Ok(
[
MetaCommand(
Exit,
),
],
)

View file

@ -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,
),
],
)

View file

@ -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",
),
},
),
],
)

View 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",
),
},
),
],
)

View file

@ -0,0 +1,11 @@
---
source: src/parser.rs
expression: "parse(file.clone(), String::from(\"select\"))"
---
Ok(
[
Statement(
Select,
),
],
)

View file

@ -0,0 +1,11 @@
---
source: src/parser.rs
expression: "parse(file.clone(), String::from(\"sElEcT\"))"
---
Ok(
[
Statement(
Select,
),
],
)

View file

@ -0,0 +1,11 @@
---
source: src/parser.rs
expression: "parse(file.clone(), String::from(\"INSERT\"))"
---
Ok(
[
Statement(
Insert,
),
],
)

View file

@ -0,0 +1,11 @@
---
source: src/parser.rs
expression: "parse(file.clone(), String::from(\"InSErT\"))"
---
Ok(
[
Statement(
Insert,
),
],
)

View file

@ -0,0 +1,11 @@
---
source: src/parser.rs
expression: "parse(file.clone(), String::from(\".exit\"))"
---
Ok(
[
MetaCommand(
Exit,
),
],
)

View file

@ -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",
),
},
),
],
)

View file

@ -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",
),
},
),
],
)

View file

@ -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",
),
},
),
],
)

View file

@ -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",
),
},
),
],
)

View file

@ -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",
),
},
),
],
)