Skip to content

Commit

Permalink
Add support for lambda syntax that allows to specify parameter name. …
Browse files Browse the repository at this point in the history
…Fix doc generation for lambdas. (#1546)

Signed-off-by: Nazar Kacharaba <[email protected]>
  • Loading branch information
NazarKacharaba authored Aug 24, 2023
1 parent 1c36362 commit 92e6a51
Show file tree
Hide file tree
Showing 29 changed files with 1,678 additions and 32 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Gluecodium project Release Notes

## Unreleased
### Features:
* Added new lambda syntax that allows to specify parameter name.
### Bug fixes:
* Fixed documentation generation for lambdas.

## 13.6.4
### Features:
* Java: Documentation for generated property's getters contains tag @return from the first part
Expand Down
3 changes: 2 additions & 1 deletion docs/lime_idl.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ struct Options {
* Can be a free-standing element at file level or can be placed in: class, interface, struct.
* Description: declares a lambda type (a functional reference). Unlike the functions, specifying a
return type for a lambda is required. For declaring lambdas with no return type, `Void` type should
be used (like in the example above).
be used (like in the example above). When clarity is needed, it is possible to use lambda syntax with named
parameters, for example: `lambda TimestampCallback = (currentDate: Date) -> Void`

### Child element declarations

Expand Down
13 changes: 11 additions & 2 deletions docs/lime_markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,24 @@ The comment after the `@constructor` tag will be used for the documentation of t
used for the documentation of the struct itself. The parameter documentation of the constructor will use the same
documentation as for the fields of the struct. A default value will make it possible to omit a field from a constructor.

Structured comments for lambdas allow specifying comments for lambda parameters, even though they do not have explicit
names. Implicit positional names should be used for parameters instead: `p0`, `p1`, and so on. Example:
Structured comments for lambdas allow specifying comments for lambda parameters.
For unnamed parameters that have only types specified, positional names can be used to document parameters: `p0`, `p1`,
and so on. For example:
```
// Communicate the date and the message.
// @param[p0] the current date.
// @param[p1] the new message.
// @return whether the operation succeeded.
lambda TimestampCallback = (Date, String) -> Boolean
```
For named parameters use the same syntax as for functions. For example:
```
// Communicate the date and the message.
// @param[currentDate] the current date.
// @param[newMessage] the new message.
// @return whether the operation succeeded.
lambda TimestampCallback = (currentDate: Date, newMessage: String) -> Boolean
```

Formatting in documentation comments
------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ internal object DartAsyncHelpers {
val helpers: Map<String, LimeFunction>
)

private const val FIRST_PARAMETER_NAME = "p0"
private const val RESULT_LAMBDA = "__resultLambda"
private const val ERROR_LAMBDA = "__errorLambda"
private const val ASYNC_FUNCTION = "__async"
Expand Down Expand Up @@ -70,25 +71,38 @@ internal object DartAsyncHelpers {
return AsyncHelpersGroup(limeContainer.fullName, lambdas, helpers)
}

private fun createResultLambda(limeFunction: LimeFunction, functionName: String) =
LimeLambda(
limeFunction.path.parent.child(limeFunction.name + RESULT_LAMBDA, limeFunction.path.disambiguator),
private fun createResultLambda(limeFunction: LimeFunction, functionName: String): LimeLambda {
val path = limeFunction.path.parent.child(limeFunction.name + RESULT_LAMBDA, limeFunction.path.disambiguator)
return LimeLambda(
path,
attributes = LimeAttributes.Builder().addAttribute(DART, NAME, functionName + RESULT_LAMBDA).build(),
parameters = when {
limeFunction.returnType.isVoid -> emptyList()
else -> listOf(LimeLambdaParameter(limeFunction.returnType.typeRef))
else -> listOf(
LimeLambdaParameter(
limeFunction.returnType.typeRef, path.child(FIRST_PARAMETER_NAME)
)
)
}
)
}

private fun createErrorLambda(
limeFunction: LimeFunction,
limeException: LimeException,
functionName: String
) = LimeLambda(
limeFunction.path.parent.child(limeFunction.name + ERROR_LAMBDA, limeFunction.path.disambiguator),
attributes = LimeAttributes.Builder().addAttribute(DART, NAME, functionName + ERROR_LAMBDA).build(),
parameters = listOf(LimeLambdaParameter(limeException.errorType))
)
): LimeLambda {
val path = limeFunction.path.parent.child(limeFunction.name + ERROR_LAMBDA, limeFunction.path.disambiguator)
return LimeLambda(
path,
attributes = LimeAttributes.Builder().addAttribute(DART, NAME, functionName + ERROR_LAMBDA).build(),
parameters = listOf(
LimeLambdaParameter(
limeException.errorType, path.child(FIRST_PARAMETER_NAME)
)
)
)
}

private fun createAsyncHelper(
limeFunction: LimeFunction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import com.here.gluecodium.model.lime.LimeEnumerator
import com.here.gluecodium.model.lime.LimeExternalDescriptor.Companion.IMPORT_PATH_NAME
import com.here.gluecodium.model.lime.LimeFunction
import com.here.gluecodium.model.lime.LimeGenericType
import com.here.gluecodium.model.lime.LimeLambda
import com.here.gluecodium.model.lime.LimeList
import com.here.gluecodium.model.lime.LimeMap
import com.here.gluecodium.model.lime.LimeNamedElement
Expand Down Expand Up @@ -229,17 +230,32 @@ internal class DartNameResolver(
private fun resolveComment(limeComment: LimeComment): String {
var commentText = limeComment.getFor("Dart")
if (commentText.isBlank()) return ""
val limeElement = limeReferenceMap[limeComment.path.toString()] as? LimeNamedElement

val exactElement = limeReferenceMap[limeComment.path.toString()] as? LimeNamedElement
if (exactElement is LimeType || exactElement is LimeFunction) {
// For functions and types, separate first sentence with double line break.
if (isNeededToSeparateFirstLine(limeElement, limeComment)) {
commentText = commentText.replaceFirst(END_OF_SENTENCE, ".\n\n")
}

val commentedElement = exactElement ?: getParentElement(limeComment.path)
val commentedElement = limeElement ?: getParentElement(limeComment.path)
return commentsProcessor.process(commentedElement.fullName, commentText, limeToDartNames, limeLogger)
}

private fun isNeededToSeparateFirstLine(limeElement: LimeNamedElement?, limeComment: LimeComment): Boolean {
val isParameterComment = limeElement is LimeLambda &&
limeElement.parameters.any { it.comment === limeComment }

if (isParameterComment) {
return false
}

// For functions and types, separate first sentence with double line break.
return when (limeElement) {
is LimeType -> true
is LimeFunction -> true
else -> false
}
}

private fun getPlatformName(element: LimeNamedElement) =
when {
element.attributes.have(DART, DEFAULT) -> "\$init"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
! License-Filename: LICENSE
!
!}}
{{>cpp/CppDocComment}}{{>cpp/CppAttributes}}
{{>cpp/CppLambdaDoc}}{{>cpp/CppAttributes}}
using {{resolveName}} = {{>cpp/CppLambdaType}};
38 changes: 38 additions & 0 deletions gluecodium/src/main/resources/templates/cpp/CppLambdaDoc.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{{!!
!
! Copyright (C) 2016-2023 HERE Europe B.V.
!
! Licensed under the Apache License, Version 2.0 (the "License");
! you may not use this file except in compliance with the License.
! You may obtain a copy of the License at
!
! http://www.apache.org/licenses/LICENSE-2.0
!
! Unless required by applicable law or agreed to in writing, software
! distributed under the License is distributed on an "AS IS" BASIS,
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
! See the License for the specific language governing permissions and
! limitations under the License.
!
! SPDX-License-Identifier: Apache-2.0
! License-Filename: LICENSE
!
!}}
{{#ifPredicate "hasAnyComment"}}
/**
{{#unless comment.isEmpty}}{{!!
}}{{#resolveName comment}}{{prefix this " * "}}{{/resolveName}}{{!!
}}{{#parameters}}{{#set self=this}}{{#resolveName comment}}{{#unless this.isEmpty}}
* \param[in] {{self.parameterName}} {{prefix this " * " skipFirstLine=true}}{{!!
}}{{/unless}}{{/resolveName}}{{/set}}{{/parameters}}{{!!
}}{{#unless returnType.isVoid}}
{{#resolveName returnType.comment}}{{#unless this.isEmpty}}
* \return {{#ifPredicate returnType.typeRef "needsNotNullComment"}}@NotNull {{/ifPredicate}}{{!!
}}{{prefix this " * " skipFirstLine=true}}{{!!
}}{{/unless}}{{/resolveName}}{{/unless}}{{/unless}}{{#if comment.isExcluded}}
* \private
{{/if}}{{#if attributes.deprecated}}
* \deprecated {{#resolveName attributes.deprecated.message}}{{!!
}}{{prefix this " * " skipFirstLine=true}}{{/resolveName}}{{/if}}
*/
{{/ifPredicate}}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@
!
!}}
::std::function<{{resolveName returnType.typeRef "C++"}}({{#parameters}}{{!!
}}const {{resolveName typeRef "C++"}}{{#ifPredicate typeRef "needsRefSuffix"}}&{{/ifPredicate}}{{#if iter.hasNext}}, {{/if}}{{/parameters}})>
}}const {{resolveName typeRef "C++"}}{{#ifPredicate typeRef "needsRefSuffix"}}&{{/ifPredicate}}{{!!
}}{{#if this.isNamedParameter}} {{this.parameterName}}{{/if}}{{!!
}}{{#if iter.hasNext}}, {{/if}}{{/parameters}})>
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
! License-Filename: LICENSE
!
!}}
{{>dart/DartDocumentation}}{{>dart/DartAttributes}}
{{>dart/DartLambdaDocs}}{{>dart/DartAttributes}}
typedef {{resolveName}} = {{>dart/DartLambdaType}};

// {{resolveName}} "private" section, not exported.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{{!!
!
! Copyright (C) 2016-2023 HERE Europe B.V.
!
! Licensed under the Apache License, Version 2.0 (the "License");
! you may not use this file except in compliance with the License.
! You may obtain a copy of the License at
!
! http://www.apache.org/licenses/LICENSE-2.0
!
! Unless required by applicable law or agreed to in writing, software
! distributed under the License is distributed on an "AS IS" BASIS,
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
! See the License for the specific language governing permissions and
! limitations under the License.
!
! SPDX-License-Identifier: Apache-2.0
! License-Filename: LICENSE
!
!}}
{{#resolveName comment}}{{#unless this.isEmpty}}{{prefix this "/// "}}
{{/unless}}{{/resolveName}}{{!!
}}{{#ifPredicate "needsNoDoc"}}
/// @nodoc
{{/ifPredicate}}{{!!
}}{{#parameters}}{{#set self=this}}{{#resolveName comment}}{{#unless this.isEmpty}}
///
/// [{{self.parameterName}}] {{prefix this "/// " skipFirstLine=true}}
{{/unless}}{{/resolveName}}{{/set}}{{/parameters}}
{{#if attributes.deprecated}}
@Deprecated("{{#resolveName attributes.deprecated.message}}{{escape this}}{{/resolveName}}")
{{/if}}
{{#unless returnType.isVoid}}{{!!
}}{{#resolveName returnType.comment}}{{#unless this.isEmpty}}
///
/// Returns {{prefix this "/// " skipFirstLine=true}}
{{/unless}}{{/resolveName}}{{!!
}}{{/unless}}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@
! License-Filename: LICENSE
!
!}}
{{resolveName returnType.typeRef}} Function({{#parameters}}{{resolveName typeRef}}{{#if iter.hasNext}}, {{/if}}{{/parameters}})
{{resolveName returnType.typeRef}} Function({{#parameters}}{{resolveName typeRef}}{{!!
}}{{#if this.isNamedParameter}} {{this.parameterName}}{{/if}}{{#if iter.hasNext}}, {{/if}}{{/parameters}})
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{{!!
!
! Copyright (C) 2016-2023 HERE Europe B.V.
!
! Licensed under the Apache License, Version 2.0 (the "License");
! you may not use this file except in compliance with the License.
! You may obtain a copy of the License at
!
! http://www.apache.org/licenses/LICENSE-2.0
!
! Unless required by applicable law or agreed to in writing, software
! distributed under the License is distributed on an "AS IS" BASIS,
! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
! See the License for the specific language governing permissions and
! limitations under the License.
!
! SPDX-License-Identifier: Apache-2.0
! License-Filename: LICENSE
!
!}}
{{#ifPredicate "hasAnyComment"}}
{{#resolveName comment}}{{#unless this.isEmpty}}{{prefix this "/// "}}{{/unless}}{{/resolveName}}{{!!
}}{{#parameters}}{{#set self=this}}{{#resolveName comment}}{{#unless this.isEmpty}}
/// - Parameter {{self.parameterName}}: {{prefix this "/// " skipFirstLine=true}}{{!!
}}{{/unless}}{{/resolveName}}{{/set}}{{/parameters}}{{!!
}}{{#unless returnType.isVoid}}{{!!
}}{{#resolveName returnType.comment}}{{#unless this.isEmpty}}
/// - Returns: {{prefix this "/// " skipFirstLine=true}}{{!!
}}{{/unless}}{{/resolveName}}{{!!
}}{{/unless}}{{#if comment.isExcluded}}
/// :nodoc:{{/if}}{{#attributes.deprecated}}
@available(*, deprecated{{#if message}}, message: "{{#resolveName message}}{{escape this}}{{/resolveName}}"{{/if}}){{/attributes.deprecated}}
{{/ifPredicate}}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
! License-Filename: LICENSE
!
!}}
{{>swift/SwiftComment}}{{>swift/SwiftAttributes}}
{{>swift/SwiftLambdaComment}}{{>swift/SwiftAttributes}}
{{#unless isInterface}}{{resolveName "visibility"}} {{/unless}}typealias {{resolveName}} = {{!!
}}({{#parameters}}{{#unless typeRef.isNullable}}{{#instanceOf typeRef.type.actualType "LimeLambda"}}@escaping {{/instanceOf}}{{/unless}}{{!!
}}{{resolveName typeRef}}{{#if iter.hasNext}}, {{/if}}{{/parameters}}) -> {{resolveName returnType}}
}}{{#if this.isNamedParameter}}_ {{this.parameterName}}: {{/if}}{{resolveName typeRef}}{{#if iter.hasNext}}, {{/if}}{{/parameters}}) -> {{resolveName returnType}}
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ class LimeOptimizedListsValidatorTest(private val limeElement: LimeNamedElement,
arrayOf(LimeLambda(EMPTY_PATH), true),
arrayOf(LimeLambda(EMPTY_PATH, returnType = LimeReturnType(typeRef)), true),
arrayOf(LimeLambda(EMPTY_PATH, returnType = LimeReturnType(optimizedListTypeRef)), false),
arrayOf(LimeLambda(EMPTY_PATH, parameters = listOf(LimeLambdaParameter(typeRef))), true),
arrayOf(LimeLambda(EMPTY_PATH, parameters = listOf(LimeLambdaParameter(optimizedListTypeRef))), false),
arrayOf(LimeLambda(EMPTY_PATH, parameters = listOf(LimeLambdaParameter(typeRef, EMPTY_PATH))), true),
arrayOf(LimeLambda(EMPTY_PATH, parameters = listOf(LimeLambdaParameter(optimizedListTypeRef, EMPTY_PATH))), false),
arrayOf(LimeFunction(EMPTY_PATH), true),
arrayOf(LimeFunction(EMPTY_PATH, parameters = listOf(LimeParameter(EMPTY_PATH, typeRef = typeRef))), true),
arrayOf(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (C) 2016-2019 HERE Europe B.V.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
# License-Filename: LICENSE

package smoke

class LambdaComments {

// The first line of the doc.
// @param[p0] The first input parameter
lambda WithNoNamedParameters = (String) -> String

// The first line of the doc.
lambda WithNoDocsForParameters = (String) -> String

// The first line of the doc.
// @param[inputParameter] The first input parameter. The second sentence of the first input parameter.
// @return The string.
lambda WithNamedParameters = (inputParameter: String) -> String

// The first line of the doc.
// @param[p0] The first input parameter.
// @return The string.
lambda MixedDocNameParameters = (inputParameter: String, secondInputParameter: String) -> String

lambda NoCommentsNoNamedParams = (String, String) -> String

lambda NoCommentsWithNamedParams = (first: String, second: String) -> String
}
Loading

0 comments on commit 92e6a51

Please sign in to comment.