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

@ -144,7 +144,7 @@ generateEnumeration = \buf, types, enumType, name, tags, tagBytes ->
Str.concat Str.concat
""" """
} }
impl core::fmt::Debug for \(escapedName) { impl core::fmt::Debug for \(escapedName) {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self { match self {
@ -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,10 +207,132 @@ 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
@ -222,26 +344,26 @@ generateZeroElementSingleTagStruct = \buf, name, tagName ->
impl \(name) { impl \(name) {
/// A tag named \(tagName), which has no payload. /// A tag named \(tagName), which has no payload.
pub const \(tagName): Self = Self(); pub const \(tagName): Self = Self();
/// Other `into_` methods return a payload, but since \(tagName) tag /// Other `into_` methods return a payload, but since \(tagName) tag
/// has no payload, this does nothing and is only here for completeness. /// has no payload, this does nothing and is only here for completeness.
pub fn into_\(tagName)(self) { pub fn into_\(tagName)(self) {
() ()
} }
/// Other `as_` methods return a payload, but since \(tagName) tag /// Other `as_` methods return a payload, but since \(tagName) tag
/// has no payload, this does nothing and is only here for completeness. /// has no payload, this does nothing and is only here for completeness.
pub fn as_\(tagName)(&self) { pub fn as_\(tagName)(&self) {
() ()
} }
} }
impl core::fmt::Dbg for \(name) { impl core::fmt::Dbg for \(name) {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("\(name)::\(tagName)") f.write_str("\(name)::\(tagName)")
} }
} }
""" """
@ -478,7 +600,7 @@ archName = \arch ->
fileHeader = fileHeader =
""" """
// ⚠️ GENERATED CODE ⚠️ - this entire file was generated by the `roc glue` CLI command // ⚠️ GENERATED CODE ⚠️ - this entire file was generated by the `roc glue` CLI command
#![allow(unused_unsafe)] #![allow(unused_unsafe)]
#![allow(dead_code)] #![allow(dead_code)]
#![allow(unused_mut)] #![allow(unused_mut)]
@ -494,8 +616,8 @@ fileHeader =
#![allow(clippy::redundant_static_lifetimes)] #![allow(clippy::redundant_static_lifetimes)]
#![allow(clippy::needless_borrow)] #![allow(clippy::needless_borrow)]
#![allow(clippy::clone_on_copy)] #![allow(clippy::clone_on_copy)]
""" """

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);