Get the parser working in Rust

This commit is contained in:
Dane Johnson 2022-01-07 13:48:36 -06:00
parent 54163136e1
commit 9fcb145b55
5 changed files with 264 additions and 0 deletions

1
src/rust-base/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
target/

61
src/rust-base/Cargo.lock generated Normal file
View File

@ -0,0 +1,61 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "peg"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af728fe826811af3b38c37e93de6d104485953ea373d656eebae53d6987fcd2c"
dependencies = [
"peg-macros",
"peg-runtime",
]
[[package]]
name = "peg-macros"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4536be147b770b824895cbad934fccce8e49f14b4c4946eaa46a6e4a12fcdc16"
dependencies = [
"peg-runtime",
"proc-macro2",
"quote",
]
[[package]]
name = "peg-runtime"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9b0efd3ba03c3a409d44d60425f279ec442bcf0b9e63ff4e410da31c8b0f69f"
[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "storybook"
version = "0.1.0"
dependencies = [
"peg",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"

10
src/rust-base/Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "storybook"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
peg = "0.8.0"

19
src/rust-base/my_header.h Normal file
View File

@ -0,0 +1,19 @@
#include <cstdarg>
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <new>
struct Page;
template<typename T = void, typename E = void>
struct Result;
template<typename T = void>
struct Vec;
extern "C" {
Result<Vec<Page>, ParseError<LineCol>> parse_story(const str *string);
} // extern "C"

173
src/rust-base/src/lib.rs Normal file
View File

@ -0,0 +1,173 @@
#[derive(Debug, PartialEq)]
pub struct Page {
id: String,
body: String,
footer: Footer,
}
#[derive(Debug, PartialEq)]
pub enum Footer {
Ending,
Goto(String),
Choices(Vec<Choice>)
}
#[derive(Debug, PartialEq)]
pub struct Choice {
option: u32,
flavor: String,
redirect: String,
stat_check: Option<StatCheck>,
stat_change: Option<StatChange>
}
#[derive(Debug, PartialEq)]
pub struct StatCheck {
stat: String,
value: i32,
rel: char,
}
#[derive(Debug, PartialEq)]
pub struct StatChange {
stat: String,
addend: i32,
}
peg::parser! {
grammar storybook_parser() for str {
pub rule story() -> Vec<Page>
= blankline()* ps:page()+ eof() { ps }
rule page() -> Page
= h:header() b:body() f:footer() blankline()* {
Page {
id: h,
body: b,
footer: f
}
}
rule header() -> String
= i:id() __ blankline()* { i }
rule id() -> String
= i:$(['A'..='Z'|'_']+) _ { String::from(i) }
rule body() -> String
= b:$((!footer() [_])+) { String::from(b.trim()) }
rule footer() -> Footer
= "THE END" __ { Footer::Ending } /
"GOTO" _ i:id() __ { Footer::Goto(i) } /
c:choice()+ { Footer::Choices(c) }
rule choice() -> Choice
= o:$(['0'..='9']+) ")" _ f:$((!redirect() [_])+) r:redirect() __ {
let (redirect, stat_change, stat_check) = r;
Choice {
option: o.parse().unwrap(),
flavor: String::from(f.trim()),
redirect,
stat_change,
stat_check
}
}
rule redirect() -> (String, Option<StatChange>, Option<StatCheck>)
= ck:stat_check()? "[" i:id() "]" _ cg:stat_change()? { (i, cg, ck) }
rule stat_change() -> StatChange
= "(" a:$(['+'|'-'] ['0'..='9']+) _ n:stat_name() ")" _ { StatChange {
addend: a.parse().unwrap(),
stat: n
}}
rule stat_check() -> StatCheck
= "<" n:stat_name() _ v:$(['0'..='9']+) r:['+'|'-'] ">" _ { StatCheck {
stat: n,
value: v.parse().unwrap(),
rel: r
}}
rule stat_name() -> String
= n:$(['a'..='z'|'A'..='Z']+) { String::from(n) }
rule blankline()
= _ __
rule _
= [' '|'\t']*
rule __
= "\r\n" / "\r" / "\n"
rule eof()
= ![_]
}
}
pub fn parse_story(string: &str) -> Result<Vec<Page>,
peg::error::ParseError<
peg::str::LineCol>> {
storybook_parser::story(string)
}
#[cfg(test)]
mod tests {
use super::*;
const STORY: &str = r"
START
One day, Dane took a really big shit.
GOTO DIALOG
DIALOG
Dane: 'Wow, that was a really big shit!'
1) Die [DIE]
2) Don't die <Strength 100+> [DONTDIE] (-1 Honor)
DIE
Then he died.
Fuck you, Dane!
THE END
";
#[test]
fn storybook_parser_test() {
assert_eq!(
parse_story(STORY),
Ok(vec![
Page {
id: String::from("START"),
body: String::from("One day, Dane took a really big shit."),
footer: Footer::Goto(String::from("DIALOG"))
},
Page {
id: String::from("DIALOG"),
body: String::from("Dane: 'Wow, that was a really big shit!'"),
footer: Footer::Choices(vec![
Choice {
option: 1,
flavor: String::from("Die"),
redirect: String::from("DIE"),
stat_check: None,
stat_change: None,
},
Choice {
option: 2,
flavor: String::from("Don't die"),
redirect: String::from("DONTDIE"),
stat_change: Some(StatChange {
stat: String::from("Honor"),
addend: -1,
}),
stat_check: Some(StatCheck {
stat: String::from("Strength"),
value: 100,
rel: '+',
})
}
])
},
Page {
id: String::from("DIE"),
body: String::from("Then he died.\n\nFuck you, Dane!"),
footer: Footer::Ending,
}
])
);
}
}