add multi element single tag structs

This commit is contained in:
Brendan Hansknecht 2022-12-15 12:06:13 -08:00
parent 8b68dfd02f
commit 605e4e82b8
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
2 changed files with 137 additions and 11 deletions

View file

@ -199,7 +199,7 @@ generateSingleTagStruct = \buf, types, name, tagName, payloadFields ->
else else
generateMultiElementSingleTagStruct b types name tagName payloadFields asStructFields generateMultiElementSingleTagStruct b types name tagName payloadFields asStructFields
generateMultiElementSingleTagStruct = \buf, types, name, _tagName, _payloadFields, asStructFields -> generateMultiElementSingleTagStruct = \buf, types, name, tagName, payloadFields, asStructFields ->
buf buf
|> Str.concat "{\n" |> Str.concat "{\n"
|> \b -> List.walk asStructFields b (generateStructFields types Private) |> \b -> List.walk asStructFields b (generateStructFields types Private)
@ -207,11 +207,133 @@ generateMultiElementSingleTagStruct = \buf, types, name, _tagName, _payloadField
|> Str.concat |> Str.concat
""" """
impl \(name) { impl \(name) {
"""
|> \b ->
fieldTypes =
payloadFields
|> List.map \id ->
typeName types id
args =
fieldTypes
|> List.mapWithIndex \fieldTypeName, index ->
indexStr = Num.toStr index
"f\(indexStr): \(fieldTypeName)"
fields =
payloadFields
|> List.mapWithIndex \_, index ->
indexStr = Num.toStr index
"f\(indexStr),"
fieldAccesses =
fields
|> List.map \field ->
"self.\(field)"
{
b,
args,
fields,
fieldTypes,
fieldAccesses,
}
|> \{ b, args, fields, fieldTypes, fieldAccesses } ->
argsStr = Str.joinWith args ", "
fieldsStr = Str.joinWith fields "\n\(indent)\(indent)\(indent)"
{
b: Str.concat
b
"""
\(indent)/// A tag named ``\(tagName)``, with the given payload.
\(indent)pub fn \(tagName)(\(argsStr)) -> Self {
\(indent) Self {
\(indent) \(fieldsStr)
\(indent) }
\(indent)}
""",
fieldTypes,
fieldAccesses,
}
|> \{ b, fieldTypes, fieldAccesses } ->
retType = asRustTuple fieldTypes
retExpr = asRustTuple fieldAccesses
{
b: Str.concat
b
"""
\(indent)/// Since `\(name)` only has one tag (namely, `\(tagName)`),
\(indent)/// convert it to `\(tagName)`'s payload.
\(indent)pub fn into_\(tagName)(self) -> \(retType) {
\(indent) \(retExpr)
\(indent)}
""",
fieldTypes,
fieldAccesses,
}
|> \{ b, fieldTypes, fieldAccesses } ->
retType =
fieldTypes
|> List.map \ft -> "&\(ft)"
|> asRustTuple
retExpr =
fieldAccesses
|> List.map \fa -> "&\(fa)"
|> asRustTuple
Str.concat
b
"""
\(indent)/// Since `\(name)` only has one tag (namely, `\(tagName)`),
\(indent)/// convert it to `\(tagName)`'s payload.
\(indent)pub fn as_\(tagName)(self) -> \(retType) {
\(indent) \(retExpr)
\(indent)}
"""
|> Str.concat
"""
}
impl core::fmt::Dbg for \(name) {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("\(name)::\(tagName)")
"""
|> \b ->
payloadFields
|> List.mapWithIndex \_, index ->
indexStr = Num.toStr index
"\(indent)\(indent)\(indent)\(indent).field(&self.f\(indexStr))\n"
|> List.walk b Str.concat
|> Str.concat
"""
.finish()
}
} }
""" """
asRustTuple = \list ->
# If there is 1 element in the list we just return it
# Otherwise, we make a proper tuple string.
joined = Str.joinWith list ", "
if List.len list == 1 then
joined
else
"(\(joined))"
generateZeroElementSingleTagStruct = \buf, name, tagName -> generateZeroElementSingleTagStruct = \buf, name, tagName ->
# A single tag with no payload is a zero-sized unit type, so # A single tag with no payload is a zero-sized unit type, so
# represent it as a zero-sized struct (e.g. "struct Foo()"). # represent it as a zero-sized struct (e.g. "struct Foo()").

View file

@ -50,6 +50,10 @@ pub fn generate(input_path: &Path, output_path: &Path, spec_path: &Path) -> io::
types.iter().map(|x| x.into()).collect(); types.iter().map(|x| x.into()).collect();
let mut files = roc_std::RocResult::err(roc_std::RocStr::empty()); let mut files = roc_std::RocResult::err(roc_std::RocStr::empty());
unsafe { make_glue(&mut files, &roc_types) }; unsafe { make_glue(&mut files, &roc_types) };
// Roc will free data passed into it. So forget that data.
std::mem::forget(roc_types);
let files: Result<roc_std::RocList<roc_type::File>, roc_std::RocStr> = files.into(); let files: Result<roc_std::RocList<roc_type::File>, roc_std::RocStr> = files.into();
let files = files.unwrap_or_else(|err| { let files = files.unwrap_or_else(|err| {
eprintln!("Glue generation failed: {}", err); eprintln!("Glue generation failed: {}", err);