aboutsummaryrefslogtreecommitdiffstats
path: root/sylt_macro
diff options
context:
space:
mode:
Diffstat (limited to 'sylt_macro')
-rw-r--r--sylt_macro/Cargo.lock45
-rw-r--r--sylt_macro/Cargo.toml5
-rw-r--r--sylt_macro/src/lib.rs104
3 files changed, 145 insertions, 9 deletions
diff --git a/sylt_macro/Cargo.lock b/sylt_macro/Cargo.lock
new file mode 100644
index 0000000..137e02a
--- /dev/null
+++ b/sylt_macro/Cargo.lock
@@ -0,0 +1,45 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "sylt_macro"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.62"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
diff --git a/sylt_macro/Cargo.toml b/sylt_macro/Cargo.toml
index 9ac045e..6d3c75f 100644
--- a/sylt_macro/Cargo.toml
+++ b/sylt_macro/Cargo.toml
@@ -10,5 +10,6 @@ proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-syn = { version = "1.0", features=["full"] }
-quote = "1.0"
+syn = { version = "1", features=["full"] }
+proc-macro2 = "1"
+quote = "1"
diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs
index 3b8b37c..95b79c6 100644
--- a/sylt_macro/src/lib.rs
+++ b/sylt_macro/src/lib.rs
@@ -1,5 +1,6 @@
-use proc_macro::TokenStream;
-use quote::quote;
+use std::path::Path;
+
+use quote::{format_ident, quote};
use syn::{Expr, Pat, Token, parse::{Parse, ParseStream, Result}, parse_macro_input};
struct ExternBlock {
@@ -43,7 +44,7 @@ impl Parse for ExternFunction {
}
#[proc_macro]
-pub fn extern_function(tokens: TokenStream) -> TokenStream {
+pub fn extern_function(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
let parsed: ExternFunction = parse_macro_input!(tokens);
let function = parsed.function;
@@ -89,7 +90,7 @@ pub fn extern_function(tokens: TokenStream) -> TokenStream {
}
}
};
- TokenStream::from(tokens)
+ proc_macro::TokenStream::from(tokens)
}
struct LinkRename {
@@ -137,9 +138,8 @@ impl Parse for Links {
}
}
-
#[proc_macro]
-pub fn link(tokens: TokenStream) -> TokenStream {
+pub fn link(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
let links: Links = parse_macro_input!(tokens);
let links: Vec<_> = links.links.iter().map(|link| {
@@ -157,5 +157,95 @@ pub fn link(tokens: TokenStream) -> TokenStream {
let tokens = quote! {
vec![ #(#links),* ]
};
- TokenStream::from(tokens)
+ proc_macro::TokenStream::from(tokens)
+}
+
+struct TestSettings {
+ errors: Option<String>,
+ print: bool,
+}
+
+impl Default for TestSettings {
+ fn default() -> Self {
+ Self {
+ errors: None,
+ print: true,
+ }
+ }
+}
+
+fn parse_test_settings(contents: String) -> TestSettings {
+ let mut settings = TestSettings::default();
+
+ for line in contents.split("\n") {
+ if line.starts_with("// errors: ") {
+ settings.errors = Some(line.strip_prefix("// errors: ").unwrap().to_string());
+ } else if line.starts_with("// flags: ") {
+ for flag in line.split(" ").skip(2) {
+ match flag {
+ "no_print" => {
+ settings.print = false;
+ }
+ _ => {
+ panic!("Unknown test flag '{}'", flag);
+ }
+ }
+ }
+ }
+ }
+
+ settings
+}
+
+fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream {
+ let mut tests = quote! {};
+
+ for entry in std::fs::read_dir(directory).unwrap() {
+ let path = entry.unwrap().path();
+ let file_name = path.file_name().unwrap().to_str().unwrap();
+
+ if file_name.starts_with("_") {
+ continue;
+ }
+
+ if path.is_dir() {
+ tests.extend(find_test_paths(&path));
+ } else {
+ assert!(!path.to_str().unwrap().contains(","), "You should be ashamed.");
+
+ let path_string = path.to_str().unwrap();
+ let test_name = format_ident!("file_{}", file_name.replace(".sy", ""));
+
+ let settings = parse_test_settings(std::fs::read_to_string(path.clone()).unwrap());
+ let print = settings.print;
+ let tokens = if let Some(wanted_errs) = settings.errors {
+ let wanted_errs: proc_macro2::TokenStream = wanted_errs.parse().unwrap();
+ quote! {
+ test_file!(#test_name, #path_string, #print, #wanted_errs);
+ }
+ } else {
+ quote! {
+ test_file!(#test_name, #path_string, #print);
+ }
+ };
+
+ tests.extend(tokens);
+ }
+ }
+
+ let directory = directory.file_name().unwrap().to_str().unwrap().replace("/", "");
+ let directory = format_ident!("{}", directory);
+ quote! {
+ mod #directory {
+ #tests
+ }
+ }
+}
+
+#[proc_macro]
+pub fn find_tests(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
+ assert!(tokens.is_empty());
+
+ let tokens = find_test_paths(Path::new("progs/"));
+ proc_macro::TokenStream::from(tokens)
}