Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 57 additions & 4 deletions crates/csharp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ impl CSharp {
direction,
usings: HashSet::<String>::new(),
interop_usings: HashSet::<String>::new(),
custom_exception_types: HashSet::new(),
}
}

Expand Down Expand Up @@ -253,6 +254,8 @@ impl WorldGenerator for CSharp {
}
}

gen.add_custom_exception_types(resolve);

// for anonymous types
gen.define_interface_types(id);

Expand Down Expand Up @@ -916,6 +919,7 @@ struct InterfaceGenerator<'a> {
direction: Direction,
usings: HashSet<String>,
interop_usings: HashSet<String>,
custom_exception_types: HashSet<TypeId>,
}

impl InterfaceGenerator<'_> {
Expand Down Expand Up @@ -1377,6 +1381,46 @@ impl InterfaceGenerator<'_> {
}
}

fn use_custom_exception(&mut self, ty: Type) -> Option<Type> {
match ty {
Type::Id(id) => {
let inner_ty = &self.resolve.types[id];
match &inner_ty.kind {
TypeDefKind::Enum(_) | TypeDefKind::Record(_) | TypeDefKind::Variant(_) => {
self.custom_exception_types.insert(id.clone());
Some(ty)
}
_ => None,
}
}
_ => None,
}
}

fn add_custom_exception_types(&mut self, resolve: &Resolve) {
let access = self.gen.access_modifier();

for custom_type in self.custom_exception_types.iter() {
let ty = &resolve.types[*custom_type];
let name = ty.name.as_ref().unwrap().to_upper_camel_case();
match ty.kind {
TypeDefKind::Enum(_) | TypeDefKind::Record(_) | TypeDefKind::Variant(_) => {
uwrite!(
self.src,
"
{access} class {name}Exception : WitException {{
{access} {name} {name}Value {{get {{return ({name})this.Value; }} }}

{access} {name}Exception({name} v, uint level) : base(v, level){{}}
}}
"
);
}
_ => {}
}
}
}

fn type_name_with_qualifier(&mut self, ty: &Type, qualifier: bool) -> String {
match ty {
Type::Bool => "bool".to_owned(),
Expand Down Expand Up @@ -2952,10 +2996,9 @@ impl Bindgen for FunctionBindgen<'_, '_> {
1 => {
let mut payload_is_void = false;
let mut previous = operands[0].clone();
let mut vars = Vec::with_capacity(self.results.len());
let mut vars: Vec::<(String, Option<String>)> = Vec::<(String, Option<String>)>::with_capacity(self.results.len());
if let Direction::Import = self.gen.direction {
for ty in &self.results {
vars.push(previous.clone());
let tmp = self.locals.tmp("tmp");
uwrite!(
self.src,
Expand All @@ -2964,21 +3007,31 @@ impl Bindgen for FunctionBindgen<'_, '_> {
var {tmp} = {previous}.AsOk;
"
);
previous = tmp;

let TypeDefKind::Result(result) = &self.gen.resolve.types[*ty].kind else {
unreachable!();
};
let exception_name = result.err
.and_then(|ty| self.gen.use_custom_exception(ty))
.map(|ty| self.gen.type_name_with_qualifier(&ty, true));
vars.push((previous.clone(), exception_name));
payload_is_void = result.ok.is_none();
previous = tmp;
}
}
uwriteln!(self.src, "return {};", if payload_is_void { "" } else { &previous });
for (level, var) in vars.iter().enumerate().rev() {
self.gen.gen.needs_wit_exception = true;
let (var_name, exception_name) = var;
let exception_name = match exception_name {
Some(name) => &format!("{}Exception",name),
None => "WitException",
};
uwrite!(
self.src,
"\
}} else {{
throw new WitException({var}.AsErr!, {level});
throw new {exception_name}({var_name}.AsErr!, {level});
}}
"
);
Expand Down
47 changes: 13 additions & 34 deletions tests/runtime/results/wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,54 +13,33 @@ public static float EnumError(float a)
{
try {
return ResultsWorld.wit.imports.test.results.TestInterop.EnumError(a);
} catch (WitException e) {
switch ((ResultsWorld.wit.imports.test.results.ITest.E) e.Value) {
case ResultsWorld.wit.imports.test.results.ITest.E.A:
throw new WitException(ITest.E.A, 0);
case ResultsWorld.wit.imports.test.results.ITest.E.B:
throw new WitException(ITest.E.B, 0);
case ResultsWorld.wit.imports.test.results.ITest.E.C:
throw new WitException(ITest.E.C, 0);
default:
throw new Exception("unreachable");
}
} catch (ResultsWorld.wit.imports.test.results.ITest.EException e) {
throw new WitException(e.EValue, 0);
}
}

public static float RecordError(float a)
{
try {
return ResultsWorld.wit.imports.test.results.TestInterop.RecordError(a);
} catch (WitException e) {
var value = (ResultsWorld.wit.imports.test.results.ITest.E2) e.Value;
throw new WitException(new ITest.E2(value.line, value.column), 0);
} catch (ResultsWorld.wit.imports.test.results.ITest.E2Exception e) {
throw new WitException(new ITest.E2(e.E2Value.line, e.E2Value.column), 0);
}
}

public static float VariantError(float a)
{
try {
return ResultsWorld.wit.imports.test.results.TestInterop.VariantError(a);
} catch (WitException e) {
var value = (ResultsWorld.wit.imports.test.results.ITest.E3) e.Value;
switch (value.Tag) {
case ResultsWorld.wit.imports.test.results.ITest.E3.Tags.E1:
switch (value.AsE1) {
case ResultsWorld.wit.imports.test.results.ITest.E.A:
throw new WitException(ITest.E3.E1(ITest.E.A), 0);
case ResultsWorld.wit.imports.test.results.ITest.E.B:
throw new WitException(ITest.E3.E1(ITest.E.B), 0);
case ResultsWorld.wit.imports.test.results.ITest.E.C:
throw new WitException(ITest.E3.E1(ITest.E.C), 0);
default:
throw new Exception("unreachable");
}
case ResultsWorld.wit.imports.test.results.ITest.E3.Tags.E2: {
throw new WitException(ITest.E3.E2(new ITest.E2(value.AsE2.line, value.AsE2.column)), 0);
}
default:
throw new Exception("unreachable");
}
} catch (ResultsWorld.wit.imports.test.results.ITest.E3Exception e)
when (e.E3Value.Tag == ResultsWorld.wit.imports.test.results.ITest.E3.Tags.E1) {
throw new WitException(ITest.E3.E1((ITest.E)Enum.Parse(typeof(ITest.E), e.E3Value.AsE1.ToString())), 0);
} catch (ResultsWorld.wit.imports.test.results.ITest.E3Exception e)
when (e.E3Value.Tag == ResultsWorld.wit.imports.test.results.ITest.E3.Tags.E2) {
throw new WitException(ITest.E3.E2(new ITest.E2(e.E3Value.AsE2.line, e.E3Value.AsE2.column)), 0);
}
catch {
throw new Exception("unreachable");
}
}

Expand Down