Implement a working %include macro

This commit is contained in:
2024-06-08 19:50:57 -07:00
parent 0ac9ee4a3f
commit c1af3290d5
4 changed files with 37 additions and 22 deletions
+2 -2
View File
@@ -2,7 +2,7 @@ use anyhow::{anyhow, Result};
use codepage_437::CP437_WINGDINGS; use codepage_437::CP437_WINGDINGS;
// Serialize multi-line content with CR-terminated lines // Serialize multi-line content with CR-terminated lines
fn encode_multiline(input: &str) -> Result<Vec<u8>> { pub fn encode_multiline(input: &str) -> Result<Vec<u8>> {
input input
.chars() .chars()
.map(|c| { .map(|c| {
@@ -17,7 +17,7 @@ fn encode_multiline(input: &str) -> Result<Vec<u8>> {
.collect() .collect()
} }
fn decode_multiline(input: &[u8]) -> String { pub fn decode_multiline(input: &[u8]) -> String {
input input
.iter() .iter()
.map(|&x| { .map(|&x| {
+19 -12
View File
@@ -2,11 +2,12 @@ mod encoding;
mod preprocess; mod preprocess;
mod world; mod world;
use std::{env, error::Error, fs, process::exit}; use anyhow::anyhow;
use encoding::{decode_multiline, encode_multiline};
use preprocess::eval::Context;
use std::{env, error::Error, fs, path::PathBuf, process::exit};
use world::World; use world::World;
use crate::preprocess::scan::scan;
fn to_latin1(bytes: &[u8]) -> String { fn to_latin1(bytes: &[u8]) -> String {
bytes.iter().map(|&x| x as char).collect() bytes.iter().map(|&x| x as char).collect()
} }
@@ -18,16 +19,20 @@ fn main() -> Result<(), Box<dyn Error>> {
exit(1); exit(1);
} }
let bytes = fs::read(&args[1])?; let world_filename = &args[1];
let bytes = fs::read(world_filename)?;
let mut world = World::from_bytes(&bytes)?; let mut world = World::from_bytes(&bytes)?;
// Print some of the data parsed. // Prepare to evaluate macros from the world file's directory
// TODO: Implement some macros, or other code modification let world_pathbuf = PathBuf::from(&world_filename);
// Then, we can try writing a copy to disk. let world_dir = world_pathbuf.parent().ok_or(anyhow!("Couldn't get world's directory"))?;
let eval_context = Context::new(&world_dir);
println!("num boards: {}", &world.boards.len()); println!("num boards: {}", &world.boards.len());
for board in &world.boards { for board in &mut world.boards {
println!("board: {}", to_latin1(&board.name)); println!("board: {}", to_latin1(&board.name));
for stat in &board.stats { for stat in &mut board.stats {
// Print some of the data parsed.
let (x, y) = (stat.x as usize, stat.y as usize); let (x, y) = (stat.x as usize, stat.y as usize);
println!( println!(
" stat at ({}, {}): {:?}, {:?}", " stat at ({}, {}): {:?}, {:?}",
@@ -36,13 +41,15 @@ fn main() -> Result<(), Box<dyn Error>> {
board.terrain[(x - 1) + (y - 1) * 60], board.terrain[(x - 1) + (y - 1) * 60],
to_latin1(&stat.code) to_latin1(&stat.code)
); );
scan("todo: convert [u8] to strings and scan here");
// Evaluate macros
let old_code = decode_multiline(&stat.code);
let new_code = eval_context.eval_program(&old_code)?;
stat.code = encode_multiline(&new_code)?;
} }
} }
// Try to write a modified world file // Try to write a modified world file
world.boards.reverse();
world.starting_board = (world.boards.len() as i16 - 1) - world.starting_board;
fs::write("tmp.zzt", world.to_bytes()?)?; fs::write("tmp.zzt", world.to_bytes()?)?;
Ok(()) Ok(())
+16 -3
View File
@@ -1,4 +1,4 @@
use std::{fs, path::Path}; use std::{fs, path::{Path, PathBuf}};
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
@@ -15,14 +15,19 @@ trait FileLoaderTrait {
fn load(&self, path: &Path) -> Result<String>; fn load(&self, path: &Path) -> Result<String>;
} }
struct FileLoader; struct FileLoader {
working_dir: PathBuf,
}
struct MockFileLoader { struct MockFileLoader {
content: String, content: String,
} }
impl FileLoaderTrait for FileLoader { impl FileLoaderTrait for FileLoader {
fn load(&self, path: &Path) -> Result<String> { fn load(&self, path: &Path) -> Result<String> {
fs::read_to_string(path).map_err(|e| anyhow!("Couldn't load file: {}", e)) // let mut full_path = self.working_dir.clone();
// full_path.extend(path);
let full_path = self.working_dir.join(path);
fs::read_to_string(full_path).map_err(|e| anyhow!("Couldn't load {:?}: {}", path, e))
} }
} }
@@ -33,6 +38,14 @@ impl FileLoaderTrait for MockFileLoader {
} }
impl Context { impl Context {
pub fn new(working_directory: &Path) -> Self {
Context {
file_loader: Box::new(FileLoader {
working_dir: working_directory.into()
}),
}
}
pub fn eval_program(&self, input: &str) -> Result<String> { pub fn eval_program(&self, input: &str) -> Result<String> {
let tokens = scan(input).0; let tokens = scan(input).0;
let exprs = parse(tokens)?; let exprs = parse(tokens)?;
-5
View File
@@ -394,7 +394,6 @@ fn board_slice(bytes: &[u8]) -> IResult<&[u8], &[u8], LoadError> {
trait SerializationHelpers { trait SerializationHelpers {
fn push_bool(&mut self, value: bool); fn push_bool(&mut self, value: bool);
fn push_i16(&mut self, value: i16); fn push_i16(&mut self, value: i16);
fn push_u16(&mut self, value: u16);
fn push_string(&mut self, cap: u8, value: &[u8]) -> Result<(), &'static str>; fn push_string(&mut self, cap: u8, value: &[u8]) -> Result<(), &'static str>;
fn push_padding(&mut self, size: usize); fn push_padding(&mut self, size: usize);
} }
@@ -408,10 +407,6 @@ impl SerializationHelpers for Vec<u8> {
self.extend(value.to_le_bytes()); self.extend(value.to_le_bytes());
} }
fn push_u16(&mut self, value: u16) {
self.extend(value.to_le_bytes());
}
fn push_string(&mut self, cap: u8, value: &[u8]) -> Result<(), &'static str> { fn push_string(&mut self, cap: u8, value: &[u8]) -> Result<(), &'static str> {
if value.len() > cap as usize { if value.len() > cap as usize {
return Err("string too long"); return Err("string too long");