41 Commits

Author SHA1 Message Date
Tom Alexander
f4eff5ca56 Fix wasm build.
Some checks failed
clippy Build clippy has failed
rust-build Build rust-build has succeeded
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-test Build rust-test has succeeded
2023-12-27 16:00:16 -05:00
Tom Alexander
5b02c21ebf Progress on comparing properties in the wasm_compare macro. 2023-12-27 15:58:31 -05:00
Tom Alexander
5f1668702a Starting the wasm_compare macro.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has succeeded
2023-12-27 15:38:30 -05:00
Tom Alexander
1faaeeebf1 Simplify wasm diff result types.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-27 14:19:25 -05:00
Tom Alexander
20a7c89084 Improving WasmElispCompare. 2023-12-27 13:21:20 -05:00
Tom Alexander
e83417b243 Introducing a trait for running compares.
This should enable us to invoke compares without needing a reference ast node type.
2023-12-27 12:38:21 -05:00
Tom Alexander
36b80dc093 Separate out rust parsing step to support references to values stored in the parsed state.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-27 12:24:21 -05:00
Tom Alexander
1812b1a56e Remove phantom data. 2023-12-27 12:24:21 -05:00
Tom Alexander
1a70b3d2c0 Add a lifetime for data in the parsed result but not from the source. 2023-12-27 12:24:21 -05:00
Tom Alexander
abf066701e Add category and path to WasmDocument. 2023-12-27 11:31:35 -05:00
Tom Alexander
4984ea4179 More of the test structure. 2023-12-27 11:10:40 -05:00
Tom Alexander
3cb251ea6c Move terminal colors to the shared util module. 2023-12-27 10:57:40 -05:00
Tom Alexander
4bfea41291 Add more structure to the wasm compare. 2023-12-27 10:52:59 -05:00
Tom Alexander
99376515ef Invoking wasm_compare_document.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-27 09:31:54 -05:00
Tom Alexander
23f4ba4205 Serialize to wasm during wasm compare.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has failed
rust-test Build rust-test has succeeded
2023-12-27 08:57:56 -05:00
Tom Alexander
55ad136283 Fix imports for wasm. 2023-12-27 08:49:34 -05:00
Tom Alexander
c717541099 Move the parsing of the elisp to the util module. 2023-12-27 08:46:18 -05:00
Tom Alexander
c2e921c2dc Move wasm test to a top-level module.
For some unknown reason, this makes rust-analyzer not angry.
2023-12-27 08:42:13 -05:00
Tom Alexander
e499169f0e Fix imports for wasm_test.
Some checks failed
clippy Build clippy has failed
rust-build Build rust-build has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-test Build rust-test has succeeded
2023-12-27 08:37:34 -05:00
Tom Alexander
84c088df67 Add wasm targets to the build test in the CI.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-27 08:04:03 -05:00
Tom Alexander
f210f95f99 Use a temporary folder for the builds. 2023-12-26 21:23:20 -05:00
Tom Alexander
17b81c7c72 Add a script to build every possible feature combination. 2023-12-26 21:05:40 -05:00
Tom Alexander
2911fce7cc Put util under the library. 2023-12-26 20:18:41 -05:00
Tom Alexander
e622d9fa6b Remove the old implementation of print_versions.
Some checks failed
clippy Build clippy has failed
rust-foreign-document-test Build rust-foreign-document-test has succeeded
rust-build Build rust-build has succeeded
rust-test Build rust-test has succeeded
2023-12-26 19:15:02 -05:00
Tom Alexander
8186fbb8b3 Move print_versions into a util crate. 2023-12-26 19:06:12 -05:00
Tom Alexander
68ccff74fa Outline for the wasm compare function. 2023-12-26 18:55:28 -05:00
Tom Alexander
9a13cb72c6 Make the wasm test binary async. 2023-12-25 14:32:01 -05:00
Tom Alexander
65abaa332f Separate out the wasm test into its own feature/binary. 2023-12-25 13:12:32 -05:00
Tom Alexander
67e5829fd9 Populating document's children. 2023-12-25 12:55:48 -05:00
Tom Alexander
995b41e697 Remove deserialize to support borrows. 2023-12-25 12:42:38 -05:00
Tom Alexander
eb51bdfe2f Add original field name to wasm macro. 2023-12-25 12:32:35 -05:00
Tom Alexander
bbb9ec637a Add code to test the wasm code path without actually dropping into wasm. 2023-12-25 12:14:50 -05:00
Tom Alexander
dc012b49f5 Add a generic WasmAstNode enum. 2023-12-25 11:51:39 -05:00
Tom Alexander
13863a68f7 Add placeholders for all the wasm ast nodes. 2023-12-25 11:33:43 -05:00
Tom Alexander
2962f76c81 Add lifetime to wasm objects. 2023-12-25 11:19:09 -05:00
Tom Alexander
b9b3ef6e74 Populate standard properties. 2023-12-25 10:47:10 -05:00
Tom Alexander
310ab2eab2 Add standard properties to wasm. 2023-12-24 15:26:45 -05:00
Tom Alexander
53320070da Define a wasm document. 2023-12-24 15:17:41 -05:00
Tom Alexander
2d5593681f Start defining the return type. 2023-12-24 13:02:34 -05:00
Tom Alexander
b3f97dbb40 Add wasm-bindgen. 2023-12-24 00:59:41 -05:00
Tom Alexander
a48d76321e Building basic wasm. 2023-12-24 00:47:32 -05:00
82 changed files with 2981 additions and 121 deletions

View File

@@ -192,6 +192,54 @@ spec:
]
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
- name: run-image-wasm
taskRef:
name: run-docker-image
workspaces:
- name: source
workspace: git-source
- name: cargo-cache
workspace: cargo-cache
runAfter:
- run-image-all
params:
- name: args
value:
[
"--target",
"wasm32-unknown-unknown",
"--profile",
"wasm",
"--bin",
"wasm",
"--no-default-features",
"--features",
"wasm",
]
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
- name: run-image-wasm-test
taskRef:
name: run-docker-image
workspaces:
- name: source
workspace: git-source
- name: cargo-cache
workspace: cargo-cache
runAfter:
- run-image-wasm
params:
- name: args
value:
[
"--bin",
"wasm_test",
"--no-default-features",
"--features",
"wasm_test",
]
- name: docker-image
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
finally:
- name: report-success
when:

View File

@@ -39,17 +39,31 @@ path = "src/lib.rs"
path = "src/bin_foreign_document_test.rs"
required-features = ["foreign_document_test"]
[[bin]]
name = "wasm"
path = "src/bin_wasm.rs"
required-features = ["wasm"]
[[bin]]
name = "wasm_test"
path = "src/bin_wasm_test.rs"
required-features = ["wasm_test"]
[dependencies]
futures = { version = "0.3.28", optional = true }
nom = "7.1.1"
opentelemetry = { version = "0.20.0", optional = true, default-features = false, features = ["trace", "rt-tokio"] }
opentelemetry-otlp = { version = "0.13.0", optional = true }
opentelemetry-semantic-conventions = { version = "0.12.0", optional = true }
serde = { version = "1.0.193", optional = true, features = ["derive"] }
serde-wasm-bindgen = { version = "0.6.3", optional = true }
serde_json = { version = "1.0.108", optional = true }
tokio = { version = "1.30.0", optional = true, default-features = false, features = ["rt", "rt-multi-thread"] }
tracing = { version = "0.1.37", optional = true }
tracing-opentelemetry = { version = "0.20.0", optional = true }
tracing-subscriber = { version = "0.3.17", optional = true, features = ["env-filter"] }
walkdir = { version = "2.3.3", optional = true }
wasm-bindgen = { version = "0.2.89", optional = true }
[build-dependencies]
walkdir = "2.3.3"
@@ -60,6 +74,8 @@ compare = ["tokio/process", "tokio/macros"]
foreign_document_test = ["compare", "dep:futures", "tokio/sync", "dep:walkdir", "tokio/process"]
tracing = ["dep:opentelemetry", "dep:opentelemetry-otlp", "dep:opentelemetry-semantic-conventions", "dep:tokio", "dep:tracing", "dep:tracing-opentelemetry", "dep:tracing-subscriber"]
event_count = []
wasm = ["dep:serde", "dep:wasm-bindgen", "dep:serde-wasm-bindgen"]
wasm_test = ["wasm", "dep:serde_json", "tokio/process", "tokio/macros"]
# Optimized build for any sort of release.
[profile.release-lto]
@@ -79,3 +95,8 @@ strip = "symbols"
inherits = "release"
lto = true
debug = true
[profile.wasm]
inherits = "release"
lto = true
strip = true

View File

@@ -29,6 +29,15 @@ build:
release:
> cargo build --release $(RELEASEFLAGS)
.PHONY: wasm
wasm:
> cargo build --target=wasm32-unknown-unknown --profile wasm --bin wasm --features wasm
> wasm-bindgen --target web --out-dir target/wasm32-unknown-unknown/js target/wasm32-unknown-unknown/wasm/wasm.wasm
.PHONY: run_wasm
run_wasm:
> cat /tmp/test.org | cargo run --profile wasm --bin wasm_test --features wasm_test
.PHONY: clean
clean:
> cargo clean

View File

@@ -2,5 +2,6 @@ FROM rustlang/rust:nightly-alpine3.17
RUN apk add --no-cache musl-dev
RUN cargo install --locked --no-default-features --features ci-autoclean cargo-cache
RUN rustup target add wasm32-unknown-unknown
ENTRYPOINT ["cargo", "build"]

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env bash
#
# Time running a single parse without invoking a compare with emacs.
set -euo pipefail
IFS=$'\n\t'
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
: ${PROFILE:="debug"}
############## Setup #########################
function cleanup {
for f in "${folders[@]}"; do
log "Deleting $f"
rm -rf "$f"
done
}
folders=()
for sig in EXIT INT QUIT HUP TERM; do
trap "set +e; cleanup" "$sig"
done
function die {
local status_code="$1"
shift
(>&2 echo "${@}")
exit "$status_code"
}
function log {
(>&2 echo "${@}")
}
############## Program #########################
function main {
if [ "$#" -gt 0 ]; then
export CARGO_TARGET_DIR="$1"
else
local work_directory=$(mktemp -d -t 'organic.XXXXXX')
folders+=("$work_directory")
export CARGO_TARGET_DIR="$work_directory"
fi
local features=(compare foreign_document_test tracing event_count wasm wasm_test)
ENABLED_FEATURES= for_each_combination "${features[@]}"
}
function for_each_combination {
local additional_flags=()
if [ "$PROFILE" = "dev" ] || [ "$PROFILE" = "debug" ]; then
PROFILE="debug"
else
additional_flags+=(--profile "$PROFILE")
fi
local flag=$1
shift
if [ "$#" -gt 0 ]; then
ENABLED_FEATURES="$ENABLED_FEATURES" for_each_combination "${@}"
elif [ -z "$ENABLED_FEATURES" ]; then
(cd "$DIR/../" && printf "\n\n\n========== no features ==========\n\n\n" && set -x && cargo build "${additional_flags[@]}" --no-default-features)
else
(cd "$DIR/../" && printf "\n\n\n========== %s ==========\n\n\n" "${ENABLED_FEATURES:1}" && set -x && cargo build "${additional_flags[@]}" --no-default-features --features "${ENABLED_FEATURES:1}")
fi
ENABLED_FEATURES="$ENABLED_FEATURES,$flag"
if [ "$#" -gt 0 ]; then
ENABLED_FEATURES="$ENABLED_FEATURES" for_each_combination "${@}"
else
(cd "$DIR/../" && printf "\n\n\n========== %s ==========\n\n\n" "${ENABLED_FEATURES:1}" && set -x && cargo build "${additional_flags[@]}" --no-default-features --features "${ENABLED_FEATURES:1}")
fi
}
main "${@}"

View File

@@ -1,3 +1,4 @@
#![feature(exit_status_error)]
#![feature(round_char_boundary)]
#![feature(exact_size_is_empty)]
use std::io::Read;

30
src/bin_wasm.rs Normal file
View File

@@ -0,0 +1,30 @@
use organic::parser::parse_with_settings;
use organic::settings::GlobalSettings;
use organic::wasm::ParseResult;
use organic::wasm::ToWasm;
use organic::wasm::ToWasmContext;
use wasm_bindgen::prelude::wasm_bindgen;
#[wasm_bindgen]
pub fn parse_org(org_contents: &str) -> wasm_bindgen::JsValue {
let rust_parsed = match parse_with_settings(org_contents, &GlobalSettings::default()) {
Ok(document) => document,
Err(err) => {
return serde_wasm_bindgen::to_value(&ParseResult::Error(format!("{:?}", err)))
.unwrap();
}
};
let to_wasm_context = ToWasmContext::new(org_contents);
let wasm_document = match rust_parsed.to_wasm(to_wasm_context) {
Ok(document) => document,
Err(err) => {
return serde_wasm_bindgen::to_value(&ParseResult::Error(format!("{:?}", err)))
.unwrap();
}
};
serde_wasm_bindgen::to_value(&ParseResult::Success(wasm_document)).unwrap()
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}

62
src/bin_wasm_test.rs Normal file
View File

@@ -0,0 +1,62 @@
#![feature(exact_size_is_empty)]
#![feature(exit_status_error)]
use std::io::Read;
use organic::wasm_test::wasm_run_anonymous_compare;
#[cfg(feature = "tracing")]
use crate::init_tracing::init_telemetry;
#[cfg(feature = "tracing")]
use crate::init_tracing::shutdown_telemetry;
#[cfg(feature = "tracing")]
mod init_tracing;
#[cfg(not(feature = "tracing"))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let rt = tokio::runtime::Runtime::new()?;
rt.block_on(async {
let main_body_result = main_body().await;
main_body_result
})
}
#[cfg(feature = "tracing")]
fn main() -> Result<(), Box<dyn std::error::Error>> {
let rt = tokio::runtime::Runtime::new()?;
rt.block_on(async {
init_telemetry()?;
let main_body_result = main_body().await;
shutdown_telemetry()?;
main_body_result
})
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
async fn main_body() -> Result<(), Box<dyn std::error::Error>> {
let args = std::env::args().skip(1);
if args.is_empty() {
let org_contents = read_stdin_to_string()?;
if wasm_run_anonymous_compare(org_contents).await? {
} else {
Err("Diff results do not match.")?;
}
Ok(())
} else {
todo!()
// for arg in args {
// if run_compare_on_file(arg).await? {
// } else {
// Err("Diff results do not match.")?;
// }
// }
// Ok(())
}
}
fn read_stdin_to_string() -> Result<String, Box<dyn std::error::Error>> {
let mut stdin_contents = String::new();
std::io::stdin()
.lock()
.read_to_string(&mut stdin_contents)?;
Ok(stdin_contents)
}

View File

@@ -2,15 +2,16 @@ use std::path::Path;
use crate::compare::diff::compare_document;
use crate::compare::diff::DiffResult;
use crate::compare::parse::emacs_parse_anonymous_org_document;
use crate::compare::parse::emacs_parse_file_org_document;
use crate::compare::parse::get_emacs_version;
use crate::compare::parse::get_org_mode_version;
use crate::compare::sexp::sexp;
use crate::context::GlobalSettings;
use crate::context::LocalFileAccessInterface;
use crate::parser::parse_file_with_settings;
use crate::parser::parse_with_settings;
use crate::util::emacs_parse_anonymous_org_document;
use crate::util::emacs_parse_file_org_document;
use crate::util::foreground_color;
use crate::util::print_versions;
use crate::util::reset_color;
pub async fn run_anonymous_compare<P: AsRef<str>>(
org_contents: P,
@@ -68,8 +69,8 @@ pub async fn run_anonymous_compare_with_settings<'g, 's, P: AsRef<str>>(
} else if !silent {
println!(
"{color}Entire document passes.{reset}",
color = DiffResult::foreground_color(0, 255, 0),
reset = DiffResult::reset_color(),
color = foreground_color(0, 255, 0),
reset = reset_color(),
);
}
@@ -121,19 +122,10 @@ pub async fn run_compare_on_file_with_settings<'g, 's, P: AsRef<Path>>(
} else if !silent {
println!(
"{color}Entire document passes.{reset}",
color = DiffResult::foreground_color(0, 255, 0),
reset = DiffResult::reset_color(),
color = foreground_color(0, 255, 0),
reset = reset_color(),
);
}
Ok(true)
}
async fn print_versions() -> Result<(), Box<dyn std::error::Error>> {
eprintln!("Using emacs version: {}", get_emacs_version().await?.trim());
eprintln!(
"Using org-mode version: {}",
get_org_mode_version().await?.trim()
);
Ok(())
}

View File

@@ -109,6 +109,8 @@ use crate::types::Verbatim;
use crate::types::VerseBlock;
use crate::types::WarningDelayType;
use crate::types::Year;
use crate::util::foreground_color;
use crate::util::reset_color;
#[derive(Debug)]
pub enum DiffEntry<'b, 's> {
@@ -200,21 +202,21 @@ impl<'b, 's> DiffResult<'b, 's> {
if self.has_bad_children() {
format!(
"{color}BADCHILD{reset}",
color = DiffResult::foreground_color(255, 255, 0),
reset = DiffResult::reset_color(),
color = foreground_color(255, 255, 0),
reset = reset_color(),
)
} else {
format!(
"{color}GOOD{reset}",
color = DiffResult::foreground_color(0, 255, 0),
reset = DiffResult::reset_color(),
color = foreground_color(0, 255, 0),
reset = reset_color(),
)
}
}
DiffStatus::Bad => format!(
"{color}BAD{reset}",
color = DiffResult::foreground_color(255, 0, 0),
reset = DiffResult::reset_color(),
color = foreground_color(255, 0, 0),
reset = reset_color(),
),
}
};
@@ -239,45 +241,6 @@ impl<'b, 's> DiffResult<'b, 's> {
.iter()
.any(|child| child.is_immediately_bad() || child.has_bad_children())
}
pub(crate) fn foreground_color(red: u8, green: u8, blue: u8) -> String {
if DiffResult::should_use_color() {
format!(
"\x1b[38;2;{red};{green};{blue}m",
red = red,
green = green,
blue = blue
)
} else {
String::new()
}
}
#[allow(dead_code)]
pub(crate) fn background_color(red: u8, green: u8, blue: u8) -> String {
if DiffResult::should_use_color() {
format!(
"\x1b[48;2;{red};{green};{blue}m",
red = red,
green = green,
blue = blue
)
} else {
String::new()
}
}
pub(crate) fn reset_color() -> &'static str {
if DiffResult::should_use_color() {
"\x1b[0m"
} else {
""
}
}
fn should_use_color() -> bool {
!std::env::var("NO_COLOR").is_ok_and(|val| !val.is_empty())
}
}
impl<'b, 's> DiffLayer<'b, 's> {
@@ -295,14 +258,14 @@ impl<'b, 's> DiffLayer<'b, 's> {
let status_text = if self.has_bad_children() {
format!(
"{color}BADCHILD{reset}",
color = DiffResult::foreground_color(255, 255, 0),
reset = DiffResult::reset_color(),
color = foreground_color(255, 255, 0),
reset = reset_color(),
)
} else {
format!(
"{color}GOOD{reset}",
color = DiffResult::foreground_color(0, 255, 0),
reset = DiffResult::reset_color(),
color = foreground_color(0, 255, 0),
reset = reset_color(),
)
};
println!(

View File

@@ -4,7 +4,6 @@ mod compare_field;
mod diff;
mod elisp_fact;
mod macros;
mod parse;
mod sexp;
mod util;
pub use compare::run_anonymous_compare;
@@ -13,3 +12,8 @@ pub use compare::run_compare_on_file;
pub use compare::run_compare_on_file_with_settings;
pub use compare::silent_anonymous_compare;
pub use compare::silent_compare_on_file;
pub(crate) use compare_field::EmacsField;
pub(crate) use elisp_fact::ElispFact;
pub use sexp::sexp;
pub use sexp::Token;
pub(crate) use util::get_property_quoted_string;

View File

@@ -8,8 +8,15 @@
extern crate test;
#[cfg(feature = "compare")]
// TODO: I only include compare to use some shared stuff like sexp and DiffResult. Ideally, this would be moved to a shared module.
#[cfg(any(feature = "compare", feature = "wasm_test"))]
pub mod compare;
#[cfg(any(feature = "compare", feature = "wasm_test"))]
pub mod util;
#[cfg(any(feature = "wasm", feature = "wasm_test"))]
pub mod wasm;
#[cfg(feature = "wasm_test")]
pub mod wasm_test;
mod context;
mod error;

View File

@@ -1,29 +1,55 @@
use std::borrow::Cow;
use std::path::Path;
use tokio::process::Command;
use crate::context::HeadlineLevelFilter;
use crate::settings::GlobalSettings;
use crate::settings::HeadlineLevelFilter;
/// Generate elisp to configure org-mode parsing settings
///
/// Currently only org-list-allow-alphabetical is supported.
fn global_settings_elisp(global_settings: &GlobalSettings) -> String {
// This string concatenation is wildly inefficient but its only called in tests 🤷.
let mut ret = "".to_owned();
if global_settings.list_allow_alphabetical {
ret += "(setq org-list-allow-alphabetical t)\n"
}
if global_settings.tab_width != crate::settings::DEFAULT_TAB_WIDTH {
ret += format!("(setq-default tab-width {})", global_settings.tab_width).as_str();
}
if global_settings.odd_levels_only != HeadlineLevelFilter::default() {
ret += match global_settings.odd_levels_only {
HeadlineLevelFilter::Odd => "(setq org-odd-levels-only t)\n",
HeadlineLevelFilter::OddEven => "(setq org-odd-levels-only nil)\n",
};
}
ret
pub async fn print_versions() -> Result<(), Box<dyn std::error::Error>> {
eprintln!("Using emacs version: {}", get_emacs_version().await?.trim());
eprintln!(
"Using org-mode version: {}",
get_org_mode_version().await?.trim()
);
Ok(())
}
pub(crate) async fn get_emacs_version() -> Result<String, Box<dyn std::error::Error>> {
let elisp_script = r#"(progn
(message "%s" (version))
)"#;
let mut cmd = Command::new("emacs");
let cmd = cmd
.arg("-q")
.arg("--no-site-file")
.arg("--no-splash")
.arg("--batch")
.arg("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
out.status.exit_ok()?;
Ok(String::from_utf8(out.stderr)?)
}
pub(crate) async fn get_org_mode_version() -> Result<String, Box<dyn std::error::Error>> {
let elisp_script = r#"(progn
(org-mode)
(message "%s" (org-version nil t nil))
)"#;
let mut cmd = Command::new("emacs");
let cmd = cmd
.arg("-q")
.arg("--no-site-file")
.arg("--no-splash")
.arg("--batch")
.arg("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
out.status.exit_ok()?;
Ok(String::from_utf8(out.stderr)?)
}
pub(crate) async fn emacs_parse_anonymous_org_document<'g, 's, C>(
@@ -144,39 +170,64 @@ where
output
}
pub async fn get_emacs_version() -> Result<String, Box<dyn std::error::Error>> {
let elisp_script = r#"(progn
(message "%s" (version))
)"#;
let mut cmd = Command::new("emacs");
let cmd = cmd
.arg("-q")
.arg("--no-site-file")
.arg("--no-splash")
.arg("--batch")
.arg("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
out.status.exit_ok()?;
Ok(String::from_utf8(out.stderr)?)
/// Generate elisp to configure org-mode parsing settings
///
/// Currently only org-list-allow-alphabetical is supported.
fn global_settings_elisp(global_settings: &GlobalSettings) -> String {
// This string concatenation is wildly inefficient but its only called in tests 🤷.
let mut ret = "".to_owned();
if global_settings.list_allow_alphabetical {
ret += "(setq org-list-allow-alphabetical t)\n"
}
if global_settings.tab_width != crate::settings::DEFAULT_TAB_WIDTH {
ret += format!("(setq-default tab-width {})", global_settings.tab_width).as_str();
}
if global_settings.odd_levels_only != HeadlineLevelFilter::default() {
ret += match global_settings.odd_levels_only {
HeadlineLevelFilter::Odd => "(setq org-odd-levels-only t)\n",
HeadlineLevelFilter::OddEven => "(setq org-odd-levels-only nil)\n",
};
}
ret
}
pub async fn get_org_mode_version() -> Result<String, Box<dyn std::error::Error>> {
let elisp_script = r#"(progn
(org-mode)
(message "%s" (org-version nil t nil))
)"#;
let mut cmd = Command::new("emacs");
let cmd = cmd
.arg("-q")
.arg("--no-site-file")
.arg("--no-splash")
.arg("--batch")
.arg("--eval")
.arg(elisp_script);
let out = cmd.output().await?;
out.status.exit_ok()?;
Ok(String::from_utf8(out.stderr)?)
fn should_use_color() -> bool {
!std::env::var("NO_COLOR").is_ok_and(|val| !val.is_empty())
}
pub(crate) fn foreground_color(red: u8, green: u8, blue: u8) -> Cow<'static, str> {
if should_use_color() {
format!(
"\x1b[38;2;{red};{green};{blue}m",
red = red,
green = green,
blue = blue
)
.into()
} else {
Cow::from("")
}
}
#[allow(dead_code)]
pub(crate) fn background_color(red: u8, green: u8, blue: u8) -> Cow<'static, str> {
if should_use_color() {
format!(
"\x1b[48;2;{red};{green};{blue}m",
red = red,
green = green,
blue = blue
)
.into()
} else {
Cow::from("")
}
}
pub(crate) fn reset_color() -> &'static str {
if should_use_color() {
"\x1b[0m"
} else {
""
}
}

30
src/wasm/angle_link.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::AngleLink;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmAngleLink<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmAngleLink<'s, 'p>,
AngleLink<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmAngleLink {
standard_properties,
children: Vec::new(),
})
}
);

128
src/wasm/ast_node.rs Normal file
View File

@@ -0,0 +1,128 @@
use serde::Serialize;
use super::angle_link::WasmAngleLink;
use super::babel_call::WasmBabelCall;
use super::bold::WasmBold;
use super::center_block::WasmCenterBlock;
use super::citation::WasmCitation;
use super::citation_reference::WasmCitationReference;
use super::clock::WasmClock;
use super::code::WasmCode;
use super::comment::WasmComment;
use super::comment_block::WasmCommentBlock;
use super::diary_sexp::WasmDiarySexp;
use super::document::WasmDocument;
use super::drawer::WasmDrawer;
use super::dynamic_block::WasmDynamicBlock;
use super::entity::WasmEntity;
use super::example_block::WasmExampleBlock;
use super::export_block::WasmExportBlock;
use super::export_snippet::WasmExportSnippet;
use super::fixed_width_area::WasmFixedWidthArea;
use super::footnote_definition::WasmFootnoteDefinition;
use super::footnote_reference::WasmFootnoteReference;
use super::headline::WasmHeadline;
use super::horizontal_rule::WasmHorizontalRule;
use super::inline_babel_call::WasmInlineBabelCall;
use super::inline_source_block::WasmInlineSourceBlock;
use super::italic::WasmItalic;
use super::keyword::WasmKeyword;
use super::latex_environment::WasmLatexEnvironment;
use super::latex_fragment::WasmLatexFragment;
use super::line_break::WasmLineBreak;
use super::node_property::WasmNodeProperty;
use super::org_macro::WasmOrgMacro;
use super::paragraph::WasmParagraph;
use super::plain_link::WasmPlainLink;
use super::plain_list::WasmPlainList;
use super::plain_list_item::WasmPlainListItem;
use super::plain_text::WasmPlainText;
use super::planning::WasmPlanning;
use super::property_drawer::WasmPropertyDrawer;
use super::quote_block::WasmQuoteBlock;
use super::radio_link::WasmRadioLink;
use super::radio_target::WasmRadioTarget;
use super::regular_link::WasmRegularLink;
use super::section::WasmSection;
use super::special_block::WasmSpecialBlock;
use super::src_block::WasmSrcBlock;
use super::statistics_cookie::WasmStatisticsCookie;
use super::strike_through::WasmStrikeThrough;
use super::subscript::WasmSubscript;
use super::superscript::WasmSuperscript;
use super::table::WasmTable;
use super::table_cell::WasmTableCell;
use super::table_row::WasmTableRow;
use super::target::WasmTarget;
use super::timestamp::WasmTimestamp;
use super::underline::WasmUnderline;
use super::verbatim::WasmVerbatim;
use super::verse_block::WasmVerseBlock;
#[derive(Debug, Serialize)]
#[serde(untagged)]
pub enum WasmAstNode<'s, 'p> {
// Document Nodes
Document(WasmDocument<'s, 'p>),
Headline(WasmHeadline<'s, 'p>),
Section(WasmSection<'s, 'p>),
// Elements
Paragraph(WasmParagraph<'s, 'p>),
PlainList(WasmPlainList<'s, 'p>),
PlainListItem(WasmPlainListItem<'s, 'p>),
CenterBlock(WasmCenterBlock<'s, 'p>),
QuoteBlock(WasmQuoteBlock<'s, 'p>),
SpecialBlock(WasmSpecialBlock<'s, 'p>),
DynamicBlock(WasmDynamicBlock<'s, 'p>),
FootnoteDefinition(WasmFootnoteDefinition<'s, 'p>),
Comment(WasmComment<'s, 'p>),
Drawer(WasmDrawer<'s, 'p>),
PropertyDrawer(WasmPropertyDrawer<'s, 'p>),
NodeProperty(WasmNodeProperty<'s, 'p>),
Table(WasmTable<'s, 'p>),
TableRow(WasmTableRow<'s, 'p>),
VerseBlock(WasmVerseBlock<'s, 'p>),
CommentBlock(WasmCommentBlock<'s, 'p>),
ExampleBlock(WasmExampleBlock<'s, 'p>),
ExportBlock(WasmExportBlock<'s, 'p>),
SrcBlock(WasmSrcBlock<'s, 'p>),
Clock(WasmClock<'s, 'p>),
DiarySexp(WasmDiarySexp<'s, 'p>),
Planning(WasmPlanning<'s, 'p>),
FixedWidthArea(WasmFixedWidthArea<'s, 'p>),
HorizontalRule(WasmHorizontalRule<'s, 'p>),
Keyword(WasmKeyword<'s, 'p>),
BabelCall(WasmBabelCall<'s, 'p>),
LatexEnvironment(WasmLatexEnvironment<'s, 'p>),
// Objects
Bold(WasmBold<'s, 'p>),
Italic(WasmItalic<'s, 'p>),
Underline(WasmUnderline<'s, 'p>),
StrikeThrough(WasmStrikeThrough<'s, 'p>),
Code(WasmCode<'s, 'p>),
Verbatim(WasmVerbatim<'s, 'p>),
PlainText(WasmPlainText<'s, 'p>),
RegularLink(WasmRegularLink<'s, 'p>),
RadioLink(WasmRadioLink<'s, 'p>),
RadioTarget(WasmRadioTarget<'s, 'p>),
PlainLink(WasmPlainLink<'s, 'p>),
AngleLink(WasmAngleLink<'s, 'p>),
OrgMacro(WasmOrgMacro<'s, 'p>),
Entity(WasmEntity<'s, 'p>),
LatexFragment(WasmLatexFragment<'s, 'p>),
ExportSnippet(WasmExportSnippet<'s, 'p>),
FootnoteReference(WasmFootnoteReference<'s, 'p>),
Citation(WasmCitation<'s, 'p>),
CitationReference(WasmCitationReference<'s, 'p>),
InlineBabelCall(WasmInlineBabelCall<'s, 'p>),
InlineSourceBlock(WasmInlineSourceBlock<'s, 'p>),
LineBreak(WasmLineBreak<'s, 'p>),
Target(WasmTarget<'s, 'p>),
StatisticsCookie(WasmStatisticsCookie<'s, 'p>),
Subscript(WasmSubscript<'s, 'p>),
Superscript(WasmSuperscript<'s, 'p>),
TableCell(WasmTableCell<'s, 'p>),
Timestamp(WasmTimestamp<'s, 'p>),
}
impl<'s, 'p> WasmAstNode<'s, 'p> {}

30
src/wasm/babel_call.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::BabelCall;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmBabelCall<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmBabelCall<'s, 'p>,
BabelCall<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmBabelCall {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/bold.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Bold;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmBold<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmBold<'s, 'p>,
Bold<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmBold {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/center_block.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::CenterBlock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmCenterBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmCenterBlock<'s, 'p>,
CenterBlock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmCenterBlock {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/citation.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Citation;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmCitation<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmCitation<'s, 'p>,
Citation<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmCitation {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::CitationReference;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmCitationReference<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmCitationReference<'s, 'p>,
CitationReference<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmCitationReference {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/clock.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Clock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmClock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmClock<'s, 'p>,
Clock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmClock {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/code.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Code;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmCode<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmCode<'s, 'p>,
Code<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmCode {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/comment.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Comment;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmComment<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmComment<'s, 'p>,
Comment<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmComment {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/comment_block.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::CommentBlock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmCommentBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmCommentBlock<'s, 'p>,
CommentBlock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmCommentBlock {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/diary_sexp.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::DiarySexp;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmDiarySexp<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmDiarySexp<'s, 'p>,
DiarySexp<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmDiarySexp {
standard_properties,
children: Vec::new(),
})
}
);

81
src/wasm/document.rs Normal file
View File

@@ -0,0 +1,81 @@
use std::path::PathBuf;
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
#[cfg(feature = "wasm_test")]
use crate::compare::ElispFact;
use crate::types::Document;
use crate::wasm::to_wasm::ToWasmStandardProperties;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmDocument<'s, 'p> {
standard_properties: WasmStandardProperties,
additional_properties: Vec<(String, &'s str)>,
pub(crate) children: Vec<WasmAstNode<'s, 'p>>,
category: Option<&'p str>,
pub(crate) path: Option<PathBuf>,
}
to_wasm!(
WasmDocument<'s, 'p>,
Document<'s>,
original,
wasm_context,
standard_properties,
{
let category = original.category.as_ref().map(String::as_str);
let path = original.path.clone();
let additional_properties: Vec<(String, &str)> = original
.get_additional_properties()
.map(|node_property| {
(
format!(":{}", node_property.property_name.to_uppercase()),
node_property.value.unwrap_or(""),
)
})
.collect();
let children = original
.zeroth_section
.iter()
.map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode<'_, '_>>::into)
})
.chain(original.children.iter().map(|child| {
child
.to_wasm(wasm_context.clone())
.map(Into::<WasmAstNode<'_, '_>>::into)
}))
.collect::<Result<Vec<_>, _>>()?;
Ok(WasmDocument {
standard_properties,
additional_properties,
children,
category,
path,
})
}
);
impl<'s, 'p> Into<WasmAstNode<'s, 'p>> for WasmDocument<'s, 'p> {
fn into(self) -> WasmAstNode<'s, 'p> {
WasmAstNode::Document(self)
}
}
#[cfg(feature = "wasm_test")]
impl<'s, 'p> ElispFact<'s> for WasmDocument<'s, 'p> {
fn get_elisp_name<'b>(&'b self) -> std::borrow::Cow<'s, str> {
"org-data".into()
}
}

30
src/wasm/drawer.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Drawer;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmDrawer<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmDrawer<'s, 'p>,
Drawer<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmDrawer {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/dynamic_block.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::DynamicBlock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmDynamicBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmDynamicBlock<'s, 'p>,
DynamicBlock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmDynamicBlock {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/entity.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Entity;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmEntity<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmEntity<'s, 'p>,
Entity<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmEntity {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/example_block.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::ExampleBlock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmExampleBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmExampleBlock<'s, 'p>,
ExampleBlock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmExampleBlock {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/export_block.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::ExportBlock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmExportBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmExportBlock<'s, 'p>,
ExportBlock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmExportBlock {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::ExportSnippet;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmExportSnippet<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmExportSnippet<'s, 'p>,
ExportSnippet<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmExportSnippet {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::FixedWidthArea;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmFixedWidthArea<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmFixedWidthArea<'s, 'p>,
FixedWidthArea<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmFixedWidthArea {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::FootnoteDefinition;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmFootnoteDefinition<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmFootnoteDefinition<'s, 'p>,
FootnoteDefinition<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmFootnoteDefinition {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::FootnoteReference;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmFootnoteReference<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmFootnoteReference<'s, 'p>,
FootnoteReference<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmFootnoteReference {
standard_properties,
children: Vec::new(),
})
}
);

36
src/wasm/headline.rs Normal file
View File

@@ -0,0 +1,36 @@
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Heading;
use crate::wasm::to_wasm::ToWasmStandardProperties;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "headline")]
pub struct WasmHeadline<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmHeadline<'s, 'p>,
Heading<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmHeadline {
standard_properties,
children: Vec::new(),
})
}
);
impl<'s, 'p> Into<WasmAstNode<'s, 'p>> for WasmHeadline<'s, 'p> {
fn into(self) -> WasmAstNode<'s, 'p> {
WasmAstNode::Headline(self)
}
}

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::HorizontalRule;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmHorizontalRule<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmHorizontalRule<'s, 'p>,
HorizontalRule<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmHorizontalRule {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::InlineBabelCall;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmInlineBabelCall<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmInlineBabelCall<'s, 'p>,
InlineBabelCall<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmInlineBabelCall {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::InlineSourceBlock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmInlineSourceBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmInlineSourceBlock<'s, 'p>,
InlineSourceBlock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmInlineSourceBlock {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/italic.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Italic;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmItalic<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmItalic<'s, 'p>,
Italic<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmItalic {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/keyword.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Keyword;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmKeyword<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmKeyword<'s, 'p>,
Keyword<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmKeyword {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::LatexEnvironment;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmLatexEnvironment<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmLatexEnvironment<'s, 'p>,
LatexEnvironment<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmLatexEnvironment {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::LatexFragment;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmLatexFragment<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmLatexFragment<'s, 'p>,
LatexFragment<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmLatexFragment {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/line_break.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::LineBreak;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmLineBreak<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmLineBreak<'s, 'p>,
LineBreak<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmLineBreak {
standard_properties,
children: Vec::new(),
})
}
);

22
src/wasm/macros.rs Normal file
View File

@@ -0,0 +1,22 @@
/// Write the implementation for the intermediate ast node.
///
/// This exists to make changing the type signature easier.
macro_rules! to_wasm {
($ostruct:ty, $istruct:ty, $original:ident, $wasm_context:ident, $standard_properties:ident, $fnbody:tt) => {
impl<'s, 'p> ToWasm<'p> for $istruct {
type Output = $ostruct;
fn to_wasm(
&'p self,
$wasm_context: crate::wasm::to_wasm::ToWasmContext<'_>,
) -> Result<Self::Output, crate::error::CustomError> {
let $original = self;
let $standard_properties =
self.to_wasm_standard_properties($wasm_context.clone())?;
$fnbody
}
}
};
}
pub(crate) use to_wasm;

69
src/wasm/mod.rs Normal file
View File

@@ -0,0 +1,69 @@
mod angle_link;
mod ast_node;
mod babel_call;
mod bold;
mod center_block;
mod citation;
mod citation_reference;
mod clock;
mod code;
mod comment;
mod comment_block;
mod diary_sexp;
mod document;
mod drawer;
mod dynamic_block;
mod entity;
mod example_block;
mod export_block;
mod export_snippet;
mod fixed_width_area;
mod footnote_definition;
mod footnote_reference;
mod headline;
mod horizontal_rule;
mod inline_babel_call;
mod inline_source_block;
mod italic;
mod keyword;
mod latex_environment;
mod latex_fragment;
mod line_break;
mod macros;
mod node_property;
mod org_macro;
mod paragraph;
mod parse_result;
mod plain_link;
mod plain_list;
mod plain_list_item;
mod plain_text;
mod planning;
mod property_drawer;
mod quote_block;
mod radio_link;
mod radio_target;
mod regular_link;
mod section;
mod special_block;
mod src_block;
mod standard_properties;
mod statistics_cookie;
mod strike_through;
mod subscript;
mod superscript;
mod table;
mod table_cell;
mod table_row;
mod target;
mod timestamp;
mod to_wasm;
mod underline;
mod verbatim;
mod verse_block;
pub use ast_node::WasmAstNode;
pub use document::WasmDocument;
pub use parse_result::ParseResult;
pub use to_wasm::ToWasm;
pub use to_wasm::ToWasmContext;

30
src/wasm/node_property.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::NodeProperty;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmNodeProperty<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmNodeProperty<'s, 'p>,
NodeProperty<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmNodeProperty {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/org_macro.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::OrgMacro;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmOrgMacro<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmOrgMacro<'s, 'p>,
OrgMacro<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmOrgMacro {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/paragraph.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Paragraph;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmParagraph<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmParagraph<'s, 'p>,
Paragraph<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmParagraph {
standard_properties,
children: Vec::new(),
})
}
);

13
src/wasm/parse_result.rs Normal file
View File

@@ -0,0 +1,13 @@
use serde::Serialize;
use super::document::WasmDocument;
#[derive(Debug, Serialize)]
#[serde(tag = "status", content = "content")]
pub enum ParseResult<'s, 'p> {
#[serde(rename = "success")]
Success(WasmDocument<'s, 'p>),
#[serde(rename = "error")]
Error(String),
}

30
src/wasm/plain_link.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::PlainLink;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPlainLink<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmPlainLink<'s, 'p>,
PlainLink<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmPlainLink {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/plain_list.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::PlainList;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPlainList<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmPlainList<'s, 'p>,
PlainList<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmPlainList {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::PlainListItem;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPlainListItem<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmPlainListItem<'s, 'p>,
PlainListItem<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmPlainListItem {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/plain_text.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::PlainText;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPlainText<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmPlainText<'s, 'p>,
PlainText<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmPlainText {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/planning.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Planning;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPlanning<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmPlanning<'s, 'p>,
Planning<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmPlanning {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::PropertyDrawer;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmPropertyDrawer<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmPropertyDrawer<'s, 'p>,
PropertyDrawer<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmPropertyDrawer {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/quote_block.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::QuoteBlock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmQuoteBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmQuoteBlock<'s, 'p>,
QuoteBlock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmQuoteBlock {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/radio_link.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::RadioLink;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmRadioLink<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmRadioLink<'s, 'p>,
RadioLink<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmRadioLink {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/radio_target.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::RadioTarget;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmRadioTarget<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmRadioTarget<'s, 'p>,
RadioTarget<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmRadioTarget {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/regular_link.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::RegularLink;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmRegularLink<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmRegularLink<'s, 'p>,
RegularLink<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmRegularLink {
standard_properties,
children: Vec::new(),
})
}
);

36
src/wasm/section.rs Normal file
View File

@@ -0,0 +1,36 @@
use serde::Serialize;
use super::ast_node::WasmAstNode;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Section;
use crate::wasm::to_wasm::ToWasmStandardProperties;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "section")]
pub struct WasmSection<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmSection<'s, 'p>,
Section<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmSection {
standard_properties,
children: Vec::new(),
})
}
);
impl<'s, 'p> Into<WasmAstNode<'s, 'p>> for WasmSection<'s, 'p> {
fn into(self) -> WasmAstNode<'s, 'p> {
WasmAstNode::Section(self)
}
}

30
src/wasm/special_block.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::SpecialBlock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmSpecialBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmSpecialBlock<'s, 'p>,
SpecialBlock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmSpecialBlock {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/src_block.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::SrcBlock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmSrcBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmSrcBlock<'s, 'p>,
SrcBlock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmSrcBlock {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,70 @@
use serde::Serialize;
use super::to_wasm::ToWasmContext;
use super::to_wasm::ToWasmStandardProperties;
use crate::types::PostBlank;
use crate::types::StandardProperties;
#[derive(Debug, Serialize)]
pub(crate) struct WasmStandardProperties {
begin: usize,
end: usize,
contents_begin: Option<usize>,
contents_end: Option<usize>,
post_blank: PostBlank,
}
impl<'s, SP: StandardProperties<'s>> ToWasmStandardProperties for SP {
type Output = WasmStandardProperties;
fn to_wasm_standard_properties(
&self,
wasm_context: ToWasmContext<'_>,
) -> Result<Self::Output, crate::error::CustomError> {
let (begin, end) = get_char_indices(wasm_context.full_document, self.get_source());
let (contents_begin, contents_end) = match self.get_contents() {
Some(contents) => {
let (begin, end) = get_char_indices(wasm_context.full_document, contents);
(Some(begin), Some(end))
}
None => (None, None),
};
let post_blank = self.get_post_blank();
Ok(WasmStandardProperties {
begin,
end,
contents_begin,
contents_end,
post_blank,
})
}
}
fn get_char_indices(original_document: &str, subset: &str) -> (usize, usize) {
let (begin_byte, end_byte) = get_rust_byte_offsets(original_document, subset);
// Add 1 to make this 1-based to match emacs.
let begin_char = original_document[..begin_byte].chars().count() + 1;
// Also 1-based:
let end_char = begin_char + original_document[begin_byte..end_byte].chars().count();
(begin_char, end_char)
}
/// Get the byte offset into source that the string slice exists at.
///
/// These offsets are zero-based.
fn get_rust_byte_offsets(original_document: &str, subset: &str) -> (usize, usize) {
debug_assert!(is_slice_of(original_document, subset));
let offset = subset.as_ptr() as usize - original_document.as_ptr() as usize;
let end = offset + subset.len();
(offset, end)
}
/// Check if the child string slice is a slice of the parent string slice.
fn is_slice_of(parent: &str, child: &str) -> bool {
let parent_start = parent.as_ptr() as usize;
let parent_end = parent_start + parent.len();
let child_start = child.as_ptr() as usize;
let child_end = child_start + child.len();
child_start >= parent_start && child_end <= parent_end
}

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::StatisticsCookie;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmStatisticsCookie<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmStatisticsCookie<'s, 'p>,
StatisticsCookie<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmStatisticsCookie {
standard_properties,
children: Vec::new(),
})
}
);

View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::StrikeThrough;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmStrikeThrough<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmStrikeThrough<'s, 'p>,
StrikeThrough<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmStrikeThrough {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/subscript.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Subscript;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmSubscript<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmSubscript<'s, 'p>,
Subscript<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmSubscript {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/superscript.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Superscript;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmSuperscript<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmSuperscript<'s, 'p>,
Superscript<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmSuperscript {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/table.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Table;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmTable<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmTable<'s, 'p>,
Table<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmTable {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/table_cell.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::TableCell;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmTableCell<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmTableCell<'s, 'p>,
TableCell<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmTableCell {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/table_row.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::TableRow;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmTableRow<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmTableRow<'s, 'p>,
TableRow<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmTableRow {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/target.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Target;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmTarget<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmTarget<'s, 'p>,
Target<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmTarget {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/timestamp.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Timestamp;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmTimestamp<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmTimestamp<'s, 'p>,
Timestamp<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmTimestamp {
standard_properties,
children: Vec::new(),
})
}
);

27
src/wasm/to_wasm.rs Normal file
View File

@@ -0,0 +1,27 @@
use crate::error::CustomError;
pub trait ToWasm<'p> {
type Output;
fn to_wasm(&'p self, full_document: ToWasmContext<'_>) -> Result<Self::Output, CustomError>;
}
pub(crate) trait ToWasmStandardProperties {
type Output;
fn to_wasm_standard_properties(
&self,
wasm_context: ToWasmContext<'_>,
) -> Result<Self::Output, CustomError>;
}
#[derive(Debug, Clone)]
pub struct ToWasmContext<'s> {
pub(crate) full_document: &'s str,
}
impl<'s> ToWasmContext<'s> {
pub fn new(full_document: &'s str) -> ToWasmContext<'s> {
ToWasmContext { full_document }
}
}

30
src/wasm/underline.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Underline;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmUnderline<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmUnderline<'s, 'p>,
Underline<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmUnderline {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/verbatim.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::Verbatim;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmVerbatim<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmVerbatim<'s, 'p>,
Verbatim<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmVerbatim {
standard_properties,
children: Vec::new(),
})
}
);

30
src/wasm/verse_block.rs Normal file
View File

@@ -0,0 +1,30 @@
use serde::Serialize;
use super::macros::to_wasm;
use super::standard_properties::WasmStandardProperties;
use super::to_wasm::ToWasm;
use crate::types::VerseBlock;
use crate::wasm::to_wasm::ToWasmStandardProperties;
use crate::wasm::WasmAstNode;
#[derive(Debug, Serialize)]
#[serde(tag = "ast_node")]
#[serde(rename = "org-data")]
pub struct WasmVerseBlock<'s, 'p> {
standard_properties: WasmStandardProperties,
children: Vec<WasmAstNode<'s, 'p>>,
}
to_wasm!(
WasmVerseBlock<'s, 'p>,
VerseBlock<'s>,
original,
wasm_context,
standard_properties,
{
Ok(WasmVerseBlock {
standard_properties,
children: Vec::new(),
})
}
);

284
src/wasm_test/compare.rs Normal file
View File

@@ -0,0 +1,284 @@
use std::borrow::Cow;
use super::elisp_compare::WasmElispCompare;
use crate::compare::get_property_quoted_string;
use crate::compare::ElispFact;
use crate::compare::EmacsField;
use crate::compare::Token;
use crate::wasm::WasmAstNode;
use crate::wasm::WasmDocument;
use crate::wasm_test::macros::wasm_compare;
pub fn wasm_compare_document<'b, 's, 'p>(
source: &'s str,
emacs: &'b Token<'s>,
wasm: WasmDocument<'s, 'p>,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
wasm.compare_ast_node(source, emacs)
}
#[derive(Debug)]
pub struct WasmDiffResult<'s> {
status: Vec<WasmDiffStatus>,
name: Cow<'s, str>,
children: Vec<WasmDiffResult<'s>>,
}
#[derive(Debug)]
pub(crate) enum WasmDiffStatus {
Good,
Bad(Cow<'static, str>),
}
impl<'s> WasmDiffResult<'s> {
// fn apply(
// &self,
// status: &mut WasmDiffStatus,
// children: &mut Vec<WasmDiffEntry<'s>>,
// ) -> Result<WasmDiffEntry<'s>, Box<dyn std::error::Error>> {
// todo!()
// }
fn extend(
&mut self,
other: WasmDiffResult<'s>,
) -> Result<&mut WasmDiffResult<'s>, Box<dyn std::error::Error>> {
if self.name.is_empty() {
self.name = other.name;
}
self.status.extend(other.status);
self.children.extend(other.children);
Ok(self)
}
pub fn is_bad(&self) -> bool {
todo!()
// self.is_immediately_bad() || self.has_bad_children()
}
pub fn print(&self, original_document: &str) -> Result<(), Box<dyn std::error::Error>> {
// self.print_indented(0, original_document)
println!("{:#?}", self);
todo!()
}
}
impl<'s> Default for WasmDiffResult<'s> {
fn default() -> Self {
WasmDiffResult {
status: Vec::new(),
name: "".into(),
children: Vec::new(),
}
}
}
// impl<'s> WasmDiffEntry<'s> {
// // fn has_bad_children(&self) -> bool {
// // match self {
// // DiffEntry::DiffResult(diff) => &diff.children,
// // DiffEntry::DiffLayer(diff) => &diff.children,
// // }
// // .iter()
// // .any(|child| child.is_immediately_bad() || child.has_bad_children())
// // }
// // fn is_immediately_bad(&self) -> bool {
// // match self {
// // DiffEntry::DiffResult(diff) => matches!(diff.status, DiffStatus::Bad),
// // DiffEntry::DiffLayer(_) => false,
// // }
// // }
// pub fn is_bad(&self) -> bool {
// todo!()
// // self.is_immediately_bad() || self.has_bad_children()
// }
// pub fn print(&self, original_document: &str) -> Result<(), Box<dyn std::error::Error>> {
// self.print_indented(0, original_document)
// }
// fn print_indented(
// &self,
// indentation: usize,
// original_document: &str,
// ) -> Result<(), Box<dyn std::error::Error>> {
// todo!()
// // match self {
// // WasmDiffEntry::WasmDiffResult(diff) => {
// // diff.print_indented(indentation, original_document)
// // }
// // WasmDiffEntry::WasmDiffLayer(diff) => {
// // diff.print_indented(indentation, original_document)
// // }
// // }
// }
// }
fn wasm_compare_list<'b, 's: 'b, 'p, EI, WI, WC>(
source: &'s str,
emacs: EI,
wasm: WI,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>>
where
EI: Iterator<Item = &'b Token<'s>> + ExactSizeIterator,
WI: Iterator<Item = WC> + ExactSizeIterator,
WC: WasmElispCompare<'s, 'p>,
{
let status = Vec::new();
let emacs_length = emacs.len();
let wasm_length = wasm.len();
if emacs_length != wasm_length {
return Ok(WasmDiffResult {
status: vec![WasmDiffStatus::Bad(
format!(
"Child length mismatch (emacs != rust) {:?} != {:?}",
emacs_length, wasm_length
)
.into(),
)],
children: Vec::new(),
name: "".into(),
});
}
let mut child_status = Vec::with_capacity(emacs_length);
for (emacs_child, wasm_child) in emacs.zip(wasm) {
child_status.push(wasm_child.compare_ast_node(source, emacs_child)?);
}
Ok(WasmDiffResult {
status,
children: child_status,
name: "".into(),
})
}
impl<'s, 'p, WAN: WasmElispCompare<'s, 'p>> WasmElispCompare<'s, 'p> for &WAN {
fn compare_ast_node<'b>(
&self,
source: &'s str,
emacs: &'b Token<'s>,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
(*self).compare_ast_node(source, emacs)
}
}
impl<'s, 'p> WasmElispCompare<'s, 'p> for WasmAstNode<'s, 'p> {
fn compare_ast_node<'b>(
&self,
source: &'s str,
emacs: &'b Token<'s>,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
match self {
WasmAstNode::Document(inner) => inner.compare_ast_node(source, emacs),
WasmAstNode::Headline(_) => todo!(),
WasmAstNode::Section(_) => todo!(),
WasmAstNode::Paragraph(_) => todo!(),
WasmAstNode::PlainList(_) => todo!(),
WasmAstNode::PlainListItem(_) => todo!(),
WasmAstNode::CenterBlock(_) => todo!(),
WasmAstNode::QuoteBlock(_) => todo!(),
WasmAstNode::SpecialBlock(_) => todo!(),
WasmAstNode::DynamicBlock(_) => todo!(),
WasmAstNode::FootnoteDefinition(_) => todo!(),
WasmAstNode::Comment(_) => todo!(),
WasmAstNode::Drawer(_) => todo!(),
WasmAstNode::PropertyDrawer(_) => todo!(),
WasmAstNode::NodeProperty(_) => todo!(),
WasmAstNode::Table(_) => todo!(),
WasmAstNode::TableRow(_) => todo!(),
WasmAstNode::VerseBlock(_) => todo!(),
WasmAstNode::CommentBlock(_) => todo!(),
WasmAstNode::ExampleBlock(_) => todo!(),
WasmAstNode::ExportBlock(_) => todo!(),
WasmAstNode::SrcBlock(_) => todo!(),
WasmAstNode::Clock(_) => todo!(),
WasmAstNode::DiarySexp(_) => todo!(),
WasmAstNode::Planning(_) => todo!(),
WasmAstNode::FixedWidthArea(_) => todo!(),
WasmAstNode::HorizontalRule(_) => todo!(),
WasmAstNode::Keyword(_) => todo!(),
WasmAstNode::BabelCall(_) => todo!(),
WasmAstNode::LatexEnvironment(_) => todo!(),
WasmAstNode::Bold(_) => todo!(),
WasmAstNode::Italic(_) => todo!(),
WasmAstNode::Underline(_) => todo!(),
WasmAstNode::StrikeThrough(_) => todo!(),
WasmAstNode::Code(_) => todo!(),
WasmAstNode::Verbatim(_) => todo!(),
WasmAstNode::PlainText(_) => todo!(),
WasmAstNode::RegularLink(_) => todo!(),
WasmAstNode::RadioLink(_) => todo!(),
WasmAstNode::RadioTarget(_) => todo!(),
WasmAstNode::PlainLink(_) => todo!(),
WasmAstNode::AngleLink(_) => todo!(),
WasmAstNode::OrgMacro(_) => todo!(),
WasmAstNode::Entity(_) => todo!(),
WasmAstNode::LatexFragment(_) => todo!(),
WasmAstNode::ExportSnippet(_) => todo!(),
WasmAstNode::FootnoteReference(_) => todo!(),
WasmAstNode::Citation(_) => todo!(),
WasmAstNode::CitationReference(_) => todo!(),
WasmAstNode::InlineBabelCall(_) => todo!(),
WasmAstNode::InlineSourceBlock(_) => todo!(),
WasmAstNode::LineBreak(_) => todo!(),
WasmAstNode::Target(_) => todo!(),
WasmAstNode::StatisticsCookie(_) => todo!(),
WasmAstNode::Subscript(_) => todo!(),
WasmAstNode::Superscript(_) => todo!(),
WasmAstNode::TableCell(_) => todo!(),
WasmAstNode::Timestamp(_) => todo!(),
}
}
}
impl<'s, 'p> WasmElispCompare<'s, 'p> for WasmDocument<'s, 'p> {
fn compare_ast_node<'b>(
&self,
source: &'s str,
emacs: &'b Token<'s>,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
let result = wasm_compare!(
source,
emacs,
self,
(
EmacsField::Required(":path"),
|w| w.path.as_ref().and_then(|p| p.to_str()),
wasm_compare_property_quoted_string
)
);
Ok(result)
}
}
fn wasm_compare_property_quoted_string<
'b,
's,
W,
WV: AsRef<str> + std::fmt::Debug,
WG: Fn(W) -> Option<WV>,
>(
_source: &'s str,
emacs: &'b Token<'s>,
wasm_node: W,
emacs_field: &str,
wasm_value_getter: WG,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>> {
let mut result = WasmDiffResult::default();
let emacs_value = get_property_quoted_string(emacs, emacs_field)?;
let wasm_value = wasm_value_getter(wasm_node);
if wasm_value.as_ref().map(|s| s.as_ref()) != emacs_value.as_deref() {
result.status.push(WasmDiffStatus::Bad(
format!(
"Property mismatch. Property=({property}) Emacs=({emacs:?}) Wasm=({wasm:?}).",
property = emacs_field,
emacs = emacs_value,
wasm = wasm_value,
)
.into(),
))
}
Ok(result)
}

View File

@@ -0,0 +1,10 @@
use super::compare::WasmDiffResult;
use crate::compare::Token;
pub trait WasmElispCompare<'s, 'p> {
fn compare_ast_node<'b>(
&self,
source: &'s str,
emacs: &'b Token<'s>,
) -> Result<WasmDiffResult<'s>, Box<dyn std::error::Error>>;
}

101
src/wasm_test/macros.rs Normal file
View File

@@ -0,0 +1,101 @@
macro_rules! wasm_compare {
($source:expr, $emacs:expr, $wasm:expr, $(($emacs_field:expr, $wasm_value_getter:expr, $compare_fn: expr)),*) => {{
let mut result = WasmDiffResult::default();
let emacs_list = $emacs.as_list()?;
let mut emacs_list_iter = emacs_list.iter();
let emacs_name = emacs_list_iter
.next()
.ok_or("Should have an attributes child.")?
.as_atom()?;
let emacs_attributes_map = emacs_list_iter
.next()
.ok_or("Should have an attributes child.")?
.as_map()?;
let mut emacs_keys: std::collections::BTreeSet<&str> =
emacs_attributes_map.keys().map(|s| *s).collect();
{
// Compare name.
let wasm_name = $wasm.get_elisp_name();
if emacs_name != wasm_name {
result.status.push(WasmDiffStatus::Bad(
format!(
"AST node name mismatch. Emacs=({emacs}) Wasm=({wasm}).",
emacs = emacs_name,
wasm = wasm_name,
)
.into(),
));
}
}
{
// Compare children.
result.extend(wasm_compare_list(
$source,
emacs_list_iter,
$wasm.children.iter(),
)?)?;
}
{
// Check for properties that are missing from the elisp node.
$(
match $emacs_field {
EmacsField::Required(name) if emacs_keys.contains(name) => {
emacs_keys.remove(name);
}
EmacsField::Optional(name) if emacs_keys.contains(name) => {
emacs_keys.remove(name);
}
EmacsField::Required(name) => {
result.status.push(WasmDiffStatus::Bad(
format!(
"Emacs node lacked required field ({name}).",
name = name,
)
.into(),
));
}
EmacsField::Optional(_name) => {}
}
)*
}
{
// Check for elisp properties that were not compared.
if !emacs_keys.is_empty() {
let unexpected_keys: Vec<&str> = emacs_keys.into_iter().collect();
let unexpected_keys = unexpected_keys.join(", ");
result.status.push(WasmDiffStatus::Bad(
format!(
"Emacs node had extra field(s): ({field_names}).",
field_names = unexpected_keys,
)
.into(),
));
}
}
{
// Compare properties.
$(
let emacs_name = match $emacs_field {
EmacsField::Required(name) => {
name
},
EmacsField::Optional(name) => {
name
},
};
let result = $compare_fn($source, $emacs, $wasm, emacs_name, $wasm_value_getter)?;
// TODO: record this result.
)*
}
result
}};
}
pub(crate) use wasm_compare;

7
src/wasm_test/mod.rs Normal file
View File

@@ -0,0 +1,7 @@
mod compare;
mod elisp_compare;
mod macros;
mod runner;
pub use runner::wasm_run_anonymous_compare;
pub use runner::wasm_run_anonymous_compare_with_settings;

61
src/wasm_test/runner.rs Normal file
View File

@@ -0,0 +1,61 @@
use super::compare::wasm_compare_document;
use crate::compare::sexp;
use crate::context::GlobalSettings;
use crate::parser::parse_with_settings;
use crate::util::emacs_parse_anonymous_org_document;
use crate::util::foreground_color;
use crate::util::print_versions;
use crate::util::reset_color;
use crate::wasm::ToWasm;
use crate::wasm::ToWasmContext;
pub async fn wasm_run_anonymous_compare<P: AsRef<str>>(
org_contents: P,
) -> Result<bool, Box<dyn std::error::Error>> {
wasm_run_anonymous_compare_with_settings(org_contents, &GlobalSettings::default(), false).await
}
pub async fn wasm_run_anonymous_compare_with_settings<'g, 's, P: AsRef<str>>(
org_contents: P,
global_settings: &GlobalSettings<'g, 's>,
silent: bool,
) -> Result<bool, Box<dyn std::error::Error>> {
// TODO: This is a work-around to pretend that dos line endings do not exist. It would be better to handle the difference in line endings.
let org_contents = org_contents.as_ref().replace("\r\n", "\n");
let org_contents = org_contents.as_str();
if !silent {
print_versions().await?;
}
let rust_parsed = parse_with_settings(org_contents, global_settings)?;
let to_wasm_context = ToWasmContext::new(org_contents);
let wasm_parsed = rust_parsed
.to_wasm(to_wasm_context)
.map_err(|_e| "Failed to convert to wasm.")?;
let org_sexp = emacs_parse_anonymous_org_document(org_contents, global_settings).await?;
let (_remaining, parsed_sexp) = sexp(org_sexp.as_str()).map_err(|e| e.to_string())?;
if !silent {
println!("{}\n\n\n", org_contents);
println!("{}", org_sexp);
println!("{:#?}", rust_parsed);
println!("{}", serde_json::to_string(&wasm_parsed)?);
}
// We do the diffing after printing out both parsed forms in case the diffing panics
let diff_result = wasm_compare_document(org_contents, &parsed_sexp, wasm_parsed)?;
if !silent {
diff_result.print(org_contents)?;
}
if diff_result.is_bad() {
return Ok(false);
} else if !silent {
println!(
"{color}Entire document passes.{reset}",
color = foreground_color(0, 255, 0),
reset = reset_color(),
);
}
Ok(true)
}