From 8622292fde891d7efdb325533e36e49ffd90cd5a Mon Sep 17 00:00:00 2001 From: Antonius Naumann Date: Fri, 5 Jan 2024 01:35:23 +0100 Subject: [PATCH] Add helper traits to handle deref & borrow and auto-derive common traits --- example-code/functions/function_call.galvan | 2 +- example-code/functions/member_function.galvan | 1 + .../functions/mut_param_function.galvan | 1 + .../functions/ref_param_function.galvan | 1 + example-code/types/empty_struct_type.galvan | 2 +- example-code/types/empty_tuple_type.galvan | 2 +- example-code/types/empty_type.galvan | 2 +- example-code/types/optional_dict.galvan | 2 +- example-code/types/ref_type.galvan | 2 +- example-code/types/simple_struct_type.galvan | 2 +- example-code/types/simple_tuple_type.galvan | 2 +- galvan-ast/src/item/type.rs | 1 + galvan-transpiler/src/lib.rs | 2 +- .../src/transpile_item/assignment.rs | 18 ++--- .../src/transpile_item/function_call.rs | 3 + .../src/transpile_item/statement.rs | 14 +++- .../src/transpile_item/struct.rs | 8 ++- galvan-transpiler/tests/test_transpilation.rs | 2 + src/lib.rs | 2 + src/std.rs | 69 +++++++++++++++++++ 20 files changed, 113 insertions(+), 25 deletions(-) create mode 100644 src/std.rs diff --git a/example-code/functions/function_call.galvan b/example-code/functions/function_call.galvan index 6a73d31..bc86a17 100644 --- a/example-code/functions/function_call.galvan +++ b/example-code/functions/function_call.galvan @@ -31,7 +31,7 @@ multi(vec![ // TODO: Only insert & around expressions for non-copy types " pub fn multiply(a: i64, b: i64) -> i64 { } -pub fn double(a: i64) -> i64 { multiply(&(a), &(2)) } +pub fn double(a: i64) -> i64 { multiply(&(&a).__borrow(), &(2)) } " */ diff --git a/example-code/functions/member_function.galvan b/example-code/functions/member_function.galvan index 2da764a..be465e8 100644 --- a/example-code/functions/member_function.galvan +++ b/example-code/functions/member_function.galvan @@ -16,6 +16,7 @@ multi(vec![ /*# TRANSPILE " +#[derive(Clone, Debug, PartialEq)] pub(crate) struct Dog; impl Dog { pub(crate) fn woof(&self) { } diff --git a/example-code/functions/mut_param_function.galvan b/example-code/functions/mut_param_function.galvan index 7f1591f..dc6c8a5 100644 --- a/example-code/functions/mut_param_function.galvan +++ b/example-code/functions/mut_param_function.galvan @@ -16,6 +16,7 @@ multi(vec![ /*# TRANSPILE " +#[derive(Clone, Debug, PartialEq)] pub(crate) struct Dog; pub(crate) fn bark(dog: &mut Dog) { } " diff --git a/example-code/functions/ref_param_function.galvan b/example-code/functions/ref_param_function.galvan index 960fc03..63ed359 100644 --- a/example-code/functions/ref_param_function.galvan +++ b/example-code/functions/ref_param_function.galvan @@ -16,6 +16,7 @@ multi(vec![ /*# TRANSPILE " +#[derive(Clone, Debug, PartialEq)] pub(crate) struct Dog; pub(crate) fn bark(dog: std::sync::Arc>) { } " diff --git a/example-code/types/empty_struct_type.galvan b/example-code/types/empty_struct_type.galvan index 2c36439..36168d0 100644 --- a/example-code/types/empty_struct_type.galvan +++ b/example-code/types/empty_struct_type.galvan @@ -3,7 +3,7 @@ single(struct_type(inherited(), "EmptyStruct", vec![])) */ /*# TRANSPILE -"pub(crate) struct EmptyStruct { }" +"#[derive(Clone, Debug, PartialEq)] pub(crate) struct EmptyStruct { }" */ type EmptyStruct {} \ No newline at end of file diff --git a/example-code/types/empty_tuple_type.galvan b/example-code/types/empty_tuple_type.galvan index 4d2762d..58e439e 100644 --- a/example-code/types/empty_tuple_type.galvan +++ b/example-code/types/empty_tuple_type.galvan @@ -3,7 +3,7 @@ single(tuple_type(inherited(), "EmptyTuple", vec![])) */ /*# TRANSPILE -"pub(crate) struct EmptyTuple();" +"#[derive(Clone, Debug, PartialEq)] pub(crate) struct EmptyTuple();" */ type EmptyTuple() \ No newline at end of file diff --git a/example-code/types/empty_type.galvan b/example-code/types/empty_type.galvan index 39657de..82ea503 100644 --- a/example-code/types/empty_type.galvan +++ b/example-code/types/empty_type.galvan @@ -3,7 +3,7 @@ single(empty_type(inherited(), "EmptyMarker")) */ /*# TRANSPILE -"pub(crate) struct EmptyMarker;" +"#[derive(Clone, Debug, PartialEq)] pub(crate) struct EmptyMarker;" */ type EmptyMarker \ No newline at end of file diff --git a/example-code/types/optional_dict.galvan b/example-code/types/optional_dict.galvan index b353d11..c0f99dc 100644 --- a/example-code/types/optional_dict.galvan +++ b/example-code/types/optional_dict.galvan @@ -9,7 +9,7 @@ single( */ /*# TRANSPILE -"pub(crate) struct Foo { +"#[derive(Clone, Debug, PartialEq)] pub(crate) struct Foo { pub(crate) bar: Option> }" */ diff --git a/example-code/types/ref_type.galvan b/example-code/types/ref_type.galvan index 8abbc74..9c7bbb0 100644 --- a/example-code/types/ref_type.galvan +++ b/example-code/types/ref_type.galvan @@ -3,7 +3,7 @@ single(struct_type(inherited(), "WithRef", vec![ref_struct_member("ref_member", */ /*# TRANSPILE -"pub(crate) struct WithRef { +"#[derive(Clone, Debug, PartialEq)] pub(crate) struct WithRef { pub(crate) ref_member: std::sync::Arc> }" */ diff --git a/example-code/types/simple_struct_type.galvan b/example-code/types/simple_struct_type.galvan index 85955d8..e95e3fb 100644 --- a/example-code/types/simple_struct_type.galvan +++ b/example-code/types/simple_struct_type.galvan @@ -3,7 +3,7 @@ single(struct_type(public(), "SimpleStruct", vec![struct_member("member", plain( */ /*# TRANSPILE -"pub struct SimpleStruct { +"#[derive(Clone, Debug, PartialEq)] pub struct SimpleStruct { pub(crate) member: String }" */ diff --git a/example-code/types/simple_tuple_type.galvan b/example-code/types/simple_tuple_type.galvan index babbc65..19e9e7a 100644 --- a/example-code/types/simple_tuple_type.galvan +++ b/example-code/types/simple_tuple_type.galvan @@ -3,7 +3,7 @@ single(tuple_type(public(), "SimpleTuple", vec![tuple_member(plain("Int")), tupl */ /*# TRANSPILE -"pub struct SimpleTuple(i64, i64);" +"#[derive(Clone, Debug, PartialEq)] pub struct SimpleTuple(i64, i64);" */ pub type SimpleTuple(Int, Int) \ No newline at end of file diff --git a/galvan-ast/src/item/type.rs b/galvan-ast/src/item/type.rs index 1e46a86..15da3be 100644 --- a/galvan-ast/src/item/type.rs +++ b/galvan-ast/src/item/type.rs @@ -45,6 +45,7 @@ pub struct StructTypeDecl { pub ident: TypeIdent, pub members: Vec, } + #[derive(Debug, PartialEq, Eq, FromPest)] #[pest_ast(rule(Rule::struct_field))] pub struct StructTypeMember { diff --git a/galvan-transpiler/src/lib.rs b/galvan-transpiler/src/lib.rs index 7ccc426..a74344e 100644 --- a/galvan-transpiler/src/lib.rs +++ b/galvan-transpiler/src/lib.rs @@ -133,7 +133,7 @@ fn transpile_segmented( let lib = TranspileOutput { file_name: galvan_module!("rs").into(), content: format!( - "pub(crate) mod {} {{\n{}\nuse crate::*;\n{}\n}}", + "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") diff --git a/galvan-transpiler/src/transpile_item/assignment.rs b/galvan-transpiler/src/transpile_item/assignment.rs index 6d320f3..1af697e 100644 --- a/galvan-transpiler/src/transpile_item/assignment.rs +++ b/galvan-transpiler/src/transpile_item/assignment.rs @@ -8,10 +8,6 @@ impl_transpile_variants!(AssignmentTarget; Ident, MemberFieldAccess); impl Transpile for Assignment { fn transpile(&self, ctx: &Context) -> String { // TODO: Use scope to determine if variable is &mut or owned, dereference is only needed for &mut - let deref = match self.target { - AssignmentTarget::Ident(_) => "*", - AssignmentTarget::MemberFieldAccess(_) => "", - }; let Self { target, operator, @@ -19,25 +15,25 @@ impl Transpile for Assignment { } = self; match operator { AssignmentOperator::Assign => { - transpile!(ctx, "{deref}{} = {}", target, exp) + transpile!(ctx, "*({}.__mut()) = {}", target, exp) } AssignmentOperator::AddAssign => { - transpile!(ctx, "{deref}{} += {}", target, exp) + transpile!(ctx, "*({}.__mut()) += {}", target, exp) } AssignmentOperator::SubAssign => { - transpile!(ctx, "{deref}{} -= {}", target, exp) + transpile!(ctx, "*({}.__mut()) -= {}", target, exp) } AssignmentOperator::MulAssign => { - transpile!(ctx, "{deref}{} *= {}", target, exp) + transpile!(ctx, "*({}.__mut()) *= {}", target, exp) } AssignmentOperator::DivAssign => { - transpile!(ctx, "{deref}{} /= {}", target, exp) + transpile!(ctx, "*({}.__mut()) /= {}", target, exp) } AssignmentOperator::RemAssign => { - transpile!(ctx, "{deref}{} %= {}", target, exp) + transpile!(ctx, "*({}.__mut()) %= {}", target, exp) } AssignmentOperator::PowAssign => { - transpile!(ctx, "{deref}{} = {}.pow({})", target, target, exp) + transpile!(ctx, "*({}.__mut()) = {}.pow({})", target, target, exp) } } } diff --git a/galvan-transpiler/src/transpile_item/function_call.rs b/galvan-transpiler/src/transpile_item/function_call.rs index d07e2d5..7a3dc6a 100644 --- a/galvan-transpiler/src/transpile_item/function_call.rs +++ b/galvan-transpiler/src/transpile_item/function_call.rs @@ -34,6 +34,9 @@ impl Transpile for FunctionCallArg { (Mod::Let, _) => { todo!("TRANSPILER ERROR: Let modifier is not allowed for function call arguments") } + (Mod::Inherited, expr @ Exp::Ident(_)) => { + transpile!(ctx, "&(&{}).__borrow()", expression) + } (Mod::Inherited, expression) => { transpile!(ctx, "&({})", expression) } diff --git a/galvan-transpiler/src/transpile_item/statement.rs b/galvan-transpiler/src/transpile_item/statement.rs index 48467ab..7fcc14c 100644 --- a/galvan-transpiler/src/transpile_item/statement.rs +++ b/galvan-transpiler/src/transpile_item/statement.rs @@ -36,17 +36,27 @@ impl Transpile for Declaration { // TODO: Clone inner type from ref types to non-ref types self.expression .as_ref() - .map(|expr| transpile_assignment_expression(ctx, keyword, expr)) + .map(|expr| transpile_assignment_expression(ctx, expr)) + .map(|expr| { + if self.decl_modifier == DeclModifier::Ref { + format!("(&({expr})).__to_ref()") + } else { + expr + } + }) .map(|expr| format!("{keyword} {identifier}{ty} = {expr}")) .unwrap_or_else(|| format!("{keyword} {identifier}{ty}")) } } -fn transpile_assignment_expression(ctx: &Context, keyword: &str, expr: &Expression) -> String { +fn transpile_assignment_expression(ctx: &Context, expr: &Expression) -> String { match expr { Expression::Ident(ident) => { transpile!(ctx, "{}.to_owned()", ident) } + Expression::MemberFieldAccess(access) => { + transpile!(ctx, "{}.to_owned()", access) + } expr => expr.transpile(ctx), } } diff --git a/galvan-transpiler/src/transpile_item/struct.rs b/galvan-transpiler/src/transpile_item/struct.rs index 9c3b819..adc153d 100644 --- a/galvan-transpiler/src/transpile_item/struct.rs +++ b/galvan-transpiler/src/transpile_item/struct.rs @@ -3,11 +3,13 @@ use crate::macros::{impl_transpile, impl_transpile_match, transpile}; use crate::{StructTypeMember, Transpile, TupleTypeMember, TypeDecl}; use galvan_ast::DeclModifier; +static DERIVE: &str = "#[derive(Clone, Debug, PartialEq)]"; + impl_transpile_match! { TypeDecl, - Tuple(def) => ("{} struct {}({});", def.visibility, def.ident, def.members), - Struct(def) => ("{} struct {} {{\n{}\n}}", def.visibility, def.ident, def.members), + Tuple(def) => ("{DERIVE} {} struct {}({});", def.visibility, def.ident, def.members), + Struct(def) => ("{DERIVE} {} struct {} {{\n{}\n}}", def.visibility, def.ident, def.members), Alias(def) => ("{} type {} = {};", def.visibility, def.ident, def.r#type), - Empty(def) => ("{} struct {};", def.visibility, def.ident), + Empty(def) => ("{DERIVE} {} struct {};", def.visibility, def.ident), } impl_transpile!(TupleTypeMember, "{}", r#type); diff --git a/galvan-transpiler/tests/test_transpilation.rs b/galvan-transpiler/tests/test_transpilation.rs index c0a5aab..801374c 100644 --- a/galvan-transpiler/tests/test_transpilation.rs +++ b/galvan-transpiler/tests/test_transpilation.rs @@ -33,12 +33,14 @@ mod test_utils { .join("\n\n") .lines() .filter(|line| { + let line = line.trim(); !line.starts_with("pub use") && !line.starts_with("use") && !line.starts_with("mod") && !line.starts_with("pub(crate) mod") && !line.starts_with("pub mod") && !line.starts_with("#![") + && !line.starts_with("extern crate galvan") }) .dropping_back(1) .collect::>() diff --git a/src/lib.rs b/src/lib.rs index faa9760..edc3bc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +pub mod std; + pub use galvan_transpiler::galvan_module; #[cfg(feature = "build")] diff --git a/src/std.rs b/src/std.rs new file mode 100644 index 0000000..e3e0672 --- /dev/null +++ b/src/std.rs @@ -0,0 +1,69 @@ +use std::borrow::{Borrow, BorrowMut}; +use std::ops::Deref; +use std::sync::{Arc, Mutex, MutexGuard}; + +pub trait __ToRef { + type Inner; + fn __to_ref(&self) -> Arc>; +} + +impl __ToRef for &T { + type Inner = T::Owned; + + #[inline(always)] + fn __to_ref(&self) -> Arc> { + Arc::new(Mutex::new(self.deref().to_owned())) + } +} + +impl __ToRef for Arc> { + type Inner = T; + + #[inline(always)] + fn __to_ref(&self) -> Arc> { + Arc::clone(self) + } +} + +pub trait __Borrow<'a> { + type Inner; + fn __borrow(&'a self) -> Self::Inner; +} + +impl<'a, T: Borrow> __Borrow<'a> for &'a T { + type Inner = &'a T; + #[inline(always)] + fn __borrow(&'a self) -> Self::Inner { + (**self).borrow() + } +} + +impl<'a, T: 'a> __Borrow<'a> for Arc> { + type Inner = MutexGuard<'a, T>; + #[inline(always)] + fn __borrow(&'a self) -> Self::Inner { + self.lock().unwrap() + } +} + +impl<'a, T: 'a> __Borrow<'a> for MutexGuard<'a, T> { + type Inner = &'a T; + #[inline(always)] + fn __borrow(&'a self) -> Self::Inner { + (*self).deref() + } +} + +pub trait __Mut<'a> { + type Inner; + + fn __mut(&'a mut self) -> Self::Inner; +} + +impl<'a, T: BorrowMut + 'a> __Mut<'a> for T { + type Inner = &'a mut T; + + fn __mut(&'a mut self) -> Self::Inner { + self.borrow_mut() + } +}