Skip to content

Commit

Permalink
Transpile test blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
antoniusnaumann committed Jan 7, 2024
1 parent 40f60dd commit 88547f6
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 4 deletions.
5 changes: 3 additions & 2 deletions galvan-resolver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::collections::HashMap;

use thiserror::Error;

use galvan_ast::{FnDecl, Ident, MainDecl, SegmentedAsts, ToplevelItem, TypeDecl, TypeIdent};
use galvan_ast::{
FnDecl, Ident, MainDecl, SegmentedAsts, TestDecl, ToplevelItem, TypeDecl, TypeIdent,
};

#[derive(Debug, Default)]
pub struct LookupContext<'a> {
Expand All @@ -19,7 +21,6 @@ pub struct LookupContext<'a> {
pub main: Option<&'a ToplevelItem<MainDecl>>,
}

// TODO: derive thiserror and add proper error handling #[derive(Error)]
// TODO: Include spans in errors
#[derive(Debug, Error)]
pub enum LookupError {
Expand Down
54 changes: 53 additions & 1 deletion galvan-transpiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use convert_case::{Case, Casing};
use derive_more::{Deref, Display, From};
use galvan_ast::*;
use galvan_files::{FileError, Source};
use itertools::Itertools;
use std::borrow::Cow;
use std::collections::HashMap;
use std::iter;
use std::ops::Deref;
use thiserror::Error;

pub(crate) use galvan_resolver::LookupContext;
Expand Down Expand Up @@ -116,6 +119,8 @@ fn transpile_segmented(
.join("\n\n");
let toplevel_functions = toplevel_functions.trim();

let tests = transpile_tests(&segmented, ctx);

let modules = type_files
.keys()
.map(|id| sanitize_name(id))
Expand All @@ -136,7 +141,7 @@ fn transpile_segmented(
"extern crate galvan; pub(crate) use ::galvan::std::*;\n pub(crate) mod {} {{\n{}\nuse crate::*;\n{}\n}}",
galvan_module!(),
SUPPRESS_WARNINGS,
[modules, toplevel_functions, &main].join("\n\n")
[modules, toplevel_functions, &main, &tests].join("\n\n")
)
.into(),
};
Expand All @@ -156,6 +161,53 @@ fn transpile_segmented(
Ok(type_files.chain(iter::once(lib)).collect())
}

fn transpile_tests(segmented_asts: &SegmentedAsts, ctx: &Context) -> String {
fn test_name<'a>(desc: &Option<StringLiteral>) -> Cow<'a, str> {
desc.as_ref().map_or("test".into(), |desc| {
let snake = desc.as_str().trim_matches('\"').to_case(Case::Snake);
if snake.ends_with(|c: char| c.is_ascii_digit()) {
format!("{}_", snake).into()
} else {
snake.into()
}
})
}

let mut by_name: HashMap<Cow<'_, str>, Vec<&TestDecl>> = HashMap::new();
for test in &segmented_asts.tests {
by_name
.entry(test_name(&test.item.name))
.or_default()
.push(&test.item);
}

let resolved_tests = by_name
.iter()
.flat_map(|(name, tests)| {
if tests.len() == 1 {
vec![(name.clone(), tests[0])]
} else {
tests
.iter()
.enumerate()
.map(|(i, &test)| (Cow::from(format!("{}_{}", name, i)), test))
.collect_vec()
}
})
.collect_vec();

let test_mod = "#[cfg(test)]\nmod tests {\nuse crate::*;\n".to_owned()
+ resolved_tests
.iter()
.map(|t| t.transpile(ctx))
.collect::<Vec<_>>()
.join("\n\n")
.as_str()
+ "\n}";

test_mod
}

fn transpile_member_functions(ty: &TypeIdent, fns: &[&FnDecl], ctx: &Context) -> String {
if fns.is_empty() {
return "".into();
Expand Down
3 changes: 2 additions & 1 deletion galvan-transpiler/src/transpile_item/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
mod assignment;
mod closure;
mod fn_decl;
mod function_call;
mod ident;
mod operator;
mod statement;
mod r#struct;
mod task;
mod test_decl;
mod toplevel;
mod r#type;
mod visibility;
mod closure;
13 changes: 13 additions & 0 deletions galvan-transpiler/src/transpile_item/test_decl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use crate::context::Context;
use crate::macros::transpile;
use crate::Transpile;
use galvan_ast::TestDecl;
use std::borrow::Cow;

impl Transpile for &(Cow<'_, str>, &TestDecl) {
fn transpile(&self, ctx: &Context) -> String {
let (name, test_decl) = self;
let name = name.as_ref();
transpile!(ctx, "#[test]\nfn {}() {{\n{}\n}}", name, test_decl.body)
}
}

0 comments on commit 88547f6

Please sign in to comment.