Some improvements to the type system

This commit is contained in:
Fabian Stamm
2025-05-27 17:30:13 +02:00
parent 45ebb2c0d7
commit 0e73f7b5b3
6 changed files with 649 additions and 358 deletions

View File

@ -3,7 +3,9 @@ use log::warn;
use std::collections::{HashMap, HashSet};
use crate::compile::{Compile, CompileContext, FileGenerator};
use crate::ir::{EnumDefinition, ServiceDefinition, Step, Type, TypeDefinition};
use crate::ir::{
BaseType, EnumDefinition, ServiceDefinition, Step, Type, TypeDefinition, TypeModifier,
};
use crate::shared::Keywords;
use crate::IR;
@ -14,37 +16,43 @@ pub struct RustCompiler {
static RUST_KEYWORDS: [&'static str; 6] = ["type", "return", "static", "pub", "enum", "self"];
impl RustCompiler {
fn type_to_rust(typ: &Type) -> String {
fn type_to_rust(typ: &BaseType) -> String {
match typ {
Type::String => "String".to_string(),
Type::Int => "i64".to_string(),
Type::Float => "f64".to_string(),
Type::Bool => "bool".to_string(),
Type::Bytes => "Vec<u8>".to_string(),
Type::Void => "()".to_string(),
Type::Custom(name) => name.clone(),
BaseType::String => "String".to_string(),
BaseType::Int => "i64".to_string(),
BaseType::Float => "f64".to_string(),
BaseType::Bool => "bool".to_string(),
BaseType::Bytes => "Vec<u8>".to_string(),
BaseType::Void => "()".to_string(),
BaseType::Custom(name) => name.clone(),
}
}
fn type_to_rust_ext(typ: &Type, optional: bool, array: bool) -> String {
let mut result = Self::type_to_rust(typ);
if optional {
result = format!("Option<{}>", result);
}
fn type_to_rust_ext(typ: &Type) -> String {
let mut result = Self::type_to_rust(&typ.0);
let (optional, array, map) = typ.1.get_flags();
if array {
result = format!("Vec<{}>", result);
}
if let Some(map) = &map {
result = format!("HashMap<{}, {}>", Self::type_to_rust(&map), result);
}
if optional {
result = format!("Option<{}>", result);
}
result
}
fn add_dependencies(
&mut self,
file: &mut FileGenerator,
depends: &HashSet<Type>,
depends: &HashSet<BaseType>,
) -> Result<()> {
for dep in depends {
match dep {
Type::Custom(name) => {
BaseType::Custom(name) => {
file.a0(&format!("use crate::{};", name));
}
_ => {}
@ -148,16 +156,16 @@ impl RustCompiler {
format!(
"{}: {}",
Self::fix_keyword_name(&arg.name),
Self::type_to_rust_ext(&arg.typ, arg.optional, arg.array)
Self::type_to_rust_ext(&arg.typ)
)
})
.collect::<Vec<String>>()
.join(", ");
let ret = method.output.as_ref().map_or_else(
|| "()".to_owned(),
|r| Self::type_to_rust_ext(&r.typ, false, r.array),
);
let ret = method
.output
.as_ref()
.map_or_else(|| "()".to_owned(), |r| Self::type_to_rust_ext(&r.typ));
f.a1("#[allow(non_snake_case)]");
f.a(
@ -238,7 +246,7 @@ impl RustCompiler {
format!(
".map_err(|_| \"Parameter for field '{}' should be of type '{}'!\")?{}",
arg.name,
arg.typ.to_string(),
arg.typ.0.to_string(),
if i < method.inputs.len() - 1 { "," } else { "" }
),
);
@ -266,7 +274,7 @@ impl RustCompiler {
format!(
".map_err(|_| \"Parameter for field {} should be of type '{}'!\")?{}",
arg.name,
arg.typ.to_string(),
arg.typ.0.to_string(),
if i < method.inputs.len() - 1 { "," } else { "" }
),
);
@ -332,13 +340,13 @@ impl RustCompiler {
format!(
"{}: {}",
Self::fix_keyword_name(&arg.name),
Self::type_to_rust_ext(&arg.typ, arg.optional, arg.array)
Self::type_to_rust_ext(&arg.typ)
)
})
.collect::<Vec<String>>()
.join(", ");
let ret = method.output.as_ref().map_or("()".to_string(), |output| {
Self::type_to_rust_ext(&output.typ, false, output.array)
Self::type_to_rust_ext(&output.typ)
});
f.a1("#[allow(non_snake_case)]");
@ -369,7 +377,7 @@ impl RustCompiler {
f.a2("let l_res = self.client.send_request(l_req).await;");
f.a2("match l_res {");
f.a3("Err(e) => Err(e),");
if output.typ == Type::Void {
if output.typ.0 == BaseType::Void {
f.a3("Ok(_) => Ok(())");
} else {
f.a3("Ok(o) => serde_json::from_value(o).map_err(|e| Box::from(e))");
@ -440,7 +448,11 @@ impl Compile for RustCompiler {
) -> anyhow::Result<()> {
let mut f = FileGenerator::new();
if definition.fields.iter().any(|e| e.map.is_some()) {
if definition
.fields
.iter()
.any(|e| e.typ.1.get_flags().2.is_some())
{
f.a0("use std::collections::hash_map::HashMap;")
}
f.a0("use serde::{Deserialize, Serialize};");
@ -451,7 +463,6 @@ impl Compile for RustCompiler {
f.a0(format!("pub struct {} {{", definition.name));
for field in definition.fields.iter() {
f.a(1, "#[allow(non_snake_case)]");
let func = format!("pub {}:", Self::fix_keyword_name(&field.name));
if Keywords::is_keyword(&field.name) {
warn!(
@ -462,49 +473,11 @@ impl Compile for RustCompiler {
f.a(1, format!("#[serde(rename = \"{}\")]", field.name));
}
let mut opts = String::new();
let mut opte = String::new();
if field.optional {
opts = "Option<".to_string();
opte = ">".to_string();
}
if field.array {
f.a(
1,
format!(
"{} {}Vec<{}>{},",
func,
opts,
Self::type_to_rust(&field.typ),
opte
),
);
} else if let Some(map) = &field.map {
f.a(
1,
format!(
"{} {}HashMap<{}, {}>{},",
func,
opts,
Self::type_to_rust(map),
Self::type_to_rust(&field.typ),
opte
),
);
} else {
f.a(
1,
format!(
"{} {}{}{},",
func,
opts,
Self::type_to_rust(&field.typ),
opte
),
);
}
f.a1(format!(
"pub {}: {}",
Self::fix_keyword_name(&field.name),
Self::type_to_rust_ext(&field.typ)
));
}
f.a0("}");