Files
I never open a file myself, even for IMPORT. Every file a
script touches comes through something you give me, so scripts can only
reach what you decide they can.
Where scripts come from
/// Scripts kept wherever the host keeps things: here, inside the program.
struct Bundled;
const MATHS: &str = "NAMESPACE Maths
FUNCTION twice(n)
RETURN n * 2
END FUNCTION
END NAMESPACE";
impl Files for Bundled {
fn read_text(&self, path: &str) -> Result<String, String> {
match path {
"main.crash" => Ok("IMPORT \"lib/maths\"\nPRINT Maths.twice(21)".to_string()),
"lib/maths.crash" => Ok(MATHS.to_string()),
_ => Err("there is no such file".to_string()),
}
}
}
engine.files(Bundled);
let script = engine.load_file("main.crash")?;
Files is a trait. Only read_text is required. The rest — read_binary,
write_text, write_binary, exists, delete, list — refuse unless you
provide them, so nothing ever reports a save that didn’t happen.
Two kinds come with me:
DiskFiles::new("games/asteroids")is one folder on disk.MemoryFiles::new().with("main.crash", text)keeps everything in memory, which is what tests and this book use.
Whichever you use:
IMPORT "lib/maths"readslib/maths.crashthrough it.- Your own functions reach it as
call.files, so aLOADyou write sees exactly the filesIMPORTdoes. - An
IMPORTcan’t climb out. Its path uses/, is relative to the file doing the importing, and is refused if it would leave the root you chose, with..or an absolute path.DiskFilesrefuses the same for every path it’s given.
Scripts that aren’t in files
A script doesn’t have to come from a file at all. engine.load takes the
text directly, with a name to report errors against. Its imports still go
through your Files.
let script = engine.load(&Source { file: "console".to_string(), text: typed_by_the_user })?;
Crash-tan’s Tip: A file ending in
.basis the older Crash BASIC, and I’ll say so if you hand me one. Mine end in.crash.