pub mod cst;
pub mod diag;
pub mod hir;
pub mod lexer;
pub mod lower;
pub mod manifest;
pub mod parser;
pub mod preprocess;
pub mod settings;
pub mod support;
pub mod tooling;
use std::path::Path;
use diag::Span;
pub use diag::{OpyError, OpyResult};
pub use lower::lower;
pub use parser::parse;
pub use preprocess::{preprocess, preprocess_with_overlay};
#[cfg(test)]
mod tests {
use super::compile;
use std::path::Path;
#[test]
fn unsupported_operator_aliases_fail_at_the_source_boundary() {
for expression in ["a // 2", "a //= 2", "a ^ 2", "a && 2", "a || 2", "a = !2"] {
let source = format!(
"globalvar a\nrule \"unsupported operator\":\n @Event global\n {expression}\n"
);
let error = compile(&source, "unsupported-operator.opy", Path::new("."))
.expect_err("unsupported operator alias unexpectedly compiled");
assert!(matches!(error.code.as_str(), "lex-error" | "parse-error"));
assert!(error.span.is_some(), "{expression}: missing source span");
}
}
#[test]
fn implicit_event_player_defaults_satisfy_hir_reference_validation() {
let hir = compile(
"rule \"implicit player\":\n @Event eachPlayer\n eventPlayer.A = 1\n",
"implicit-player.opy",
Path::new("."),
)
.expect("implicit event-player default must resolve");
hir.validate()
.expect("implicit event-player default must satisfy HIR invariants");
}
}
pub const LANGUAGE_NAME: &str = "opy-rs";
pub const LANGUAGE_VERSION: &str = env!("CARGO_PKG_VERSION");
pub fn compile(source: &str, main_path: &str, root: &Path) -> OpyResult<hir::Program> {
compile_with_overlay(source, main_path, root, &std::collections::BTreeMap::new())
}
pub fn compile_with_overlay(
source: &str,
main_path: &str,
root: &Path,
overlay: &std::collections::BTreeMap<String, String>,
) -> OpyResult<hir::Program> {
let outcome = compile_with_overlay_outcome(source, main_path, root, overlay);
match outcome.hir {
Some(hir) => Ok(hir),
None => Err(outcome
.error
.expect("a failed compile outcome always carries an error")),
}
}
pub struct CompileOutcome {
pub hir: Option<hir::Program>,
pub error: Option<OpyError>,
pub files: Vec<preprocess::FileRecord>,
pub post_compile_hook: Option<PostCompileHookRecord>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PostCompileHookRecord {
pub script: String,
pub source: String,
pub span: Option<Span>,
}
pub fn compile_with_overlay_outcome(
source: &str,
main_path: &str,
root: &Path,
overlay: &std::collections::BTreeMap<String, String>,
) -> CompileOutcome {
let outcome = tooling::check_with_overlay(source, main_path, root, overlay);
let error = outcome.diagnostics.first().map(|diagnostic| OpyError {
code: diagnostic.code.clone(),
message: diagnostic.message.clone(),
span: diagnostic
.span
.as_ref()
.map(tooling::SourceLocation::to_span),
});
let post_compile_hook = outcome.post_compile_hook.map(|hook| PostCompileHookRecord {
script: hook.path,
source: hook.source,
span: Some(hook.span),
});
CompileOutcome {
hir: outcome.model.map(|model| model.hir),
error,
files: outcome.files,
post_compile_hook,
}
}