diff --git a/renrs-gui/src/lib.rs b/renrs-gui/src/lib.rs index 19c370a..5b09f76 100644 --- a/renrs-gui/src/lib.rs +++ b/renrs-gui/src/lib.rs @@ -3,7 +3,7 @@ use std::thread; use std::time::Duration; use eframe::egui; -use renrs::{State, Command}; +use renrs::State; use sfml::{ graphics::{Color, RenderTarget, RenderWindow, RectangleShape, Transformable}, @@ -41,7 +41,7 @@ impl App { } fn next(&mut self) { - if let Some(Command::Say { name, text }) = self.state.next_command() { + if let Some(renrs::Event::Say { name, text }) = self.state.next() { self.text = match name { Some(name) => format!("{name}: {text}"), None => text, diff --git a/renrs/src/lib.rs b/renrs/src/lib.rs index c347d82..0b6fd56 100644 --- a/renrs/src/lib.rs +++ b/renrs/src/lib.rs @@ -14,6 +14,7 @@ pub enum Token { Str(String), Array(Vec), Boolean(bool), + Number(f64), } impl Token { @@ -23,6 +24,7 @@ impl Token { Str(_) => "String", Array(_) => "Array", Boolean(_) => "Boolean", + Number(_) => "Number", } } } @@ -31,13 +33,28 @@ use Token::*; // Parsed script commands #[derive(Debug)] -pub enum Command { +#[allow(dead_code)] +enum Command { Say { name: Option, text: String }, Eat { food: String, politely: bool }, } use Command::*; +impl Command { + fn is_blocking(&self) -> bool { + match self { + Say { .. } => true, + _ => false, + } + } +} + +#[derive(Debug)] +pub enum Event { + Say { name: Option, text: String }, +} + // Tokenize raw script string fn tokenize(script: &str) -> Vec> { let file = RpyParser::parse(Rule::file, script) @@ -95,6 +112,7 @@ fn parse_pair(pair: pest::iterators::Pair) -> Token { "False" => false, _ => unreachable!(), }), + Rule::number => Token::Number(contents.as_str().parse().unwrap()), Rule::keyword => Token::Keyword(contents.as_str().to_owned()), __ => unreachable!(), } @@ -122,6 +140,11 @@ fn parse_file(file_path: PathBuf) -> Vec { let token_lines = tokenize_file(file_path); let mut commands = Vec::new(); for line in token_lines { + macro_rules! unknown { + () => { + panic!("Unknown command {}", describe_line(&line)) + }; + } commands.push(match line.as_slice() { [Str(text)] => Say { name: None, @@ -135,10 +158,10 @@ fn parse_file(file_path: PathBuf) -> Vec { food: food.to_owned(), politely: match tail { [Boolean(politely)] => *politely, - _ => false, + _ => unknown!(), }, }, - _ => panic!("Unknown command {}", describe_line(&line)), + _ => unknown!(), }); } commands @@ -159,7 +182,19 @@ impl State { } } - pub fn next_command(&mut self) -> Option { + pub fn next(&mut self) -> Option { + while let Some(command) = self.next_command() { + if command.is_blocking() { + return Some(match command { + Say { name, text } => Event::Say { name, text }, + _ => unimplemented!(), + }) + } + } + None + } + + fn next_command(&mut self) -> Option { if self.command_queue.len() == 0 { None } else { diff --git a/renrs/src/rpy.pest b/renrs/src/rpy.pest index a49b9e2..da8e3c3 100644 --- a/renrs/src/rpy.pest +++ b/renrs/src/rpy.pest @@ -8,7 +8,7 @@ char = { !NEWLINE ~ ANY } // http://pest.rs/book/grammars/syntax.html#atomic inner = @{ char* } -token = { string | array | boolean | keyword } +token = { string | array | boolean | number | keyword } // KEYWORDS // has to be atomic for no implicit separate (spaces) @@ -37,6 +37,13 @@ array = { // BOOLEAN boolean = { "True" | "False" } +// NUMBER +number = @{ + "-"? + ~ ("0" | ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*) + ~ ("." ~ ASCII_DIGIT*)? +} + // comments are a # followed by // any number of non-newline characters COMMENT = _{ "#" ~ char* }