Implement a working %include macro
This commit is contained in:
+2
-2
@@ -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
@@ -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
@@ -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)?;
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user