Skip to content

Commit 6dbc4ad

Browse files
committed
Assign Rust default variant with attribute, validate presence (closes #43)
1 parent 8bd1e4d commit 6dbc4ad

File tree

7 files changed

+194
-1
lines changed

7 files changed

+194
-1
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use crate::prelude::internal::*;
2+
3+
impl RSConvertContext {
4+
pub fn config(&self) -> &RsConfigLang {
5+
&self.config
6+
}
7+
8+
pub fn assign_config(&mut self, config: RsConfigLang) -> &mut Self {
9+
self.config = config;
10+
self
11+
}
12+
}

lang/rs/tree/src/context/convert/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ pub use ids::*;
1313
mod naming;
1414
pub use naming::*;
1515

16+
mod config;
17+
pub use config::*;
18+
1619
#[derive(Default)]
1720
pub struct RSConvertContext {
1821
resolve: RSConvertResolve,

lang/rs/tree/src/enum/convert.rs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ impl RSConvert<RSEnum> for GTUnion {
2323

2424
trim_variant_names(&name, &mut variants, &mut variant_names);
2525

26+
if context.config().derive.contains(&"Default".into()) {
27+
let default_attrs = variants
28+
.iter()
29+
.flat_map(|variant| variant.attributes.iter().find(|attr| attr.0 == "default"));
30+
let count = default_attrs.clone().count();
31+
if count == 0 {
32+
return Err(RSConverterError::MissingDefaultVariant(self.span.clone()).into());
33+
} else if count > 1 {
34+
return Err(RSConverterError::MultipleDefaultVariants(self.span.clone()).into());
35+
}
36+
}
37+
2638
let r#enum = RSEnum {
2739
id,
2840
doc,
@@ -55,6 +67,10 @@ fn convert_variant(
5567

5668
context.enter_parent(RSContextParent::EnumVariant(variant_name.clone()));
5769

70+
if GTAttribute::find_flag(descriptor.attributes(), "default") {
71+
attributes.push(RSAttribute("default".into()));
72+
}
73+
5874
let descriptor = match descriptor {
5975
GTDescriptor::Literal(literal) => {
6076
let str = render_literal(literal);
@@ -970,4 +986,130 @@ mod tests {
970986
"#
971987
);
972988
}
989+
990+
#[test]
991+
fn test_attr_default() {
992+
let mut context = Gtrs::convert_context_with_parent("Status");
993+
let mut config = RsConfigLang::default();
994+
config.derive.push("Default".into());
995+
context.assign_config(config);
996+
let union = Gt::union(descriptor_nodes![
997+
Gt::primitive_string(),
998+
node_with!(
999+
Gt::primitive_number(),
1000+
attributes = vec![attribute_node!(default)]
1001+
),
1002+
]);
1003+
assert_debug_snapshot!(
1004+
convert_node_with(union, &mut context),
1005+
@r#"
1006+
RSEnum {
1007+
id: GTDefinitionId(
1008+
GTModuleId(
1009+
"module",
1010+
),
1011+
"Status",
1012+
),
1013+
doc: None,
1014+
attributes: [
1015+
RSAttribute(
1016+
"derive(Debug, Clone, PartialEq, Serialize, Deserialize)",
1017+
),
1018+
RSAttribute(
1019+
"serde(untagged)",
1020+
),
1021+
],
1022+
name: RSIdentifier(
1023+
"Status",
1024+
),
1025+
variants: [
1026+
RSEnumVariant {
1027+
doc: None,
1028+
attributes: [],
1029+
name: RSIdentifier(
1030+
"String",
1031+
),
1032+
descriptor: Some(
1033+
Descriptor(
1034+
Primitive(
1035+
String,
1036+
),
1037+
),
1038+
),
1039+
},
1040+
RSEnumVariant {
1041+
doc: None,
1042+
attributes: [
1043+
RSAttribute(
1044+
"default",
1045+
),
1046+
],
1047+
name: RSIdentifier(
1048+
"Number",
1049+
),
1050+
descriptor: Some(
1051+
Descriptor(
1052+
Primitive(
1053+
Float64,
1054+
),
1055+
),
1056+
),
1057+
},
1058+
],
1059+
}
1060+
"#
1061+
);
1062+
}
1063+
1064+
#[test]
1065+
fn test_attr_default_missing_err() {
1066+
let mut context = Gtrs::convert_context_with_parent("Status");
1067+
let mut config = RsConfigLang::default();
1068+
config.derive.push("Default".into());
1069+
context.assign_config(config);
1070+
let union = Gt::union(descriptor_nodes![
1071+
Gt::primitive_string(),
1072+
Gt::primitive_number()
1073+
]);
1074+
assert_debug_snapshot!(
1075+
convert_node_err_with(union, &mut context),
1076+
@"
1077+
MissingDefaultVariant(
1078+
GTSpan(
1079+
0,
1080+
0,
1081+
),
1082+
)
1083+
"
1084+
);
1085+
}
1086+
1087+
#[test]
1088+
fn test_attr_default_multiple_err() {
1089+
let mut context = Gtrs::convert_context_with_parent("Status");
1090+
let mut config = RsConfigLang::default();
1091+
config.derive.push("Default".into());
1092+
context.assign_config(config);
1093+
let union = Gt::union(descriptor_nodes![
1094+
node_with!(
1095+
Gt::primitive_string(),
1096+
attributes = vec![attribute_node!(default)]
1097+
),
1098+
node_with!(
1099+
Gt::primitive_number(),
1100+
attributes = vec![attribute_node!(default)]
1101+
)
1102+
]);
1103+
assert_debug_snapshot!(
1104+
convert_node_err_with(union, &mut context),
1105+
@"
1106+
MultipleDefaultVariants(
1107+
GTSpan(
1108+
0,
1109+
0,
1110+
),
1111+
)
1112+
"
1113+
);
1114+
}
9731115
}

lang/rs/tree/src/error/convert.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,10 @@ pub enum RSConverterError {
1010
#[error("Tried to convert unresolved reference")]
1111
#[diagnostic(code(GTRSC102))]
1212
UnresolvedReference(#[label("this reference")] GTSpan),
13+
#[error("Missing default variant for enum with derived Default")]
14+
#[diagnostic(code(GTRSC103))]
15+
MissingDefaultVariant(#[label("enum")] GTSpan),
16+
#[error("Multiple default variants for enum with derived Default")]
17+
#[diagnostic(code(GTRSC104))]
18+
MultipleDefaultVariants(#[label("enum")] GTSpan),
1319
}

lang/rs/tree/src/test.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ pub fn convert_node_with<GtNode: RSConvert<Node>, Node>(
1111
gt_node.convert(context).unwrap()
1212
}
1313

14+
pub fn convert_node_err_with<GtNode: RSConvert<Node>, Node>(
15+
gt_node: GtNode,
16+
context: &mut RSConvertContext,
17+
) -> miette::Report
18+
where
19+
Node: std::fmt::Debug,
20+
{
21+
let result = gt_node.convert(context);
22+
result.unwrap_err()
23+
}
24+
1425
pub struct Gtrs {}
1526

1627
impl Gtrs {

parser/src/test/mod.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,14 @@ impl Gt {
450450
}
451451
}
452452

453+
pub fn attribute_flag(name: &str) -> GTAttribute {
454+
GTAttribute {
455+
span: (0, 2).into(),
456+
name: Self::attribute_name(name),
457+
descriptor: None,
458+
}
459+
}
460+
453461
pub fn attribute_name(value: &str) -> GTAttributeName {
454462
GTAttributeName {
455463
span: (0, 0).into(),
@@ -491,15 +499,20 @@ macro_rules! node_with {
491499
node
492500
}};
493501
}
494-
495502
#[macro_export]
496503
macro_rules! attribute_node {
504+
// key = value
497505
($key:ident = $value:expr) => {
498506
Gt::attribute(
499507
stringify!($key),
500508
Gt::attribute_assignment(Gt::literal_string($value)),
501509
)
502510
};
511+
512+
// flag-style: attribute_node!(default)
513+
($key:ident) => {
514+
Gt::attribute_flag(stringify!($key))
515+
};
503516
}
504517

505518
#[macro_export]

parser/src/tree/attribute/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,10 @@ impl GTAttribute {
7070
}
7171
None
7272
}
73+
74+
pub fn find_flag(attributes: &Vec<GTAttribute>, name: &str) -> bool {
75+
attributes
76+
.iter()
77+
.any(|attr| attr.is_it(name) && attr.descriptor.is_none())
78+
}
7379
}

0 commit comments

Comments
 (0)