Get the parser working in Rust
This commit is contained in:
parent
54163136e1
commit
9fcb145b55
1
src/rust-base/.gitignore
vendored
Normal file
1
src/rust-base/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
target/
|
61
src/rust-base/Cargo.lock
generated
Normal file
61
src/rust-base/Cargo.lock
generated
Normal 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
10
src/rust-base/Cargo.toml
Normal 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
19
src/rust-base/my_header.h
Normal 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
173
src/rust-base/src/lib.rs
Normal 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,
|
||||||
|
}
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user