Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infrastructure for enso --docs option & signature generator #10291

Merged
merged 38 commits into from
Jan 21, 2025

Conversation

JaroslavTulach
Copy link
Member

@JaroslavTulach JaroslavTulach commented Jun 15, 2024

Pull Request Description

Implements --docs flag to generate documentation of a library into its docs/api directory. The --docs flag can take an optional argument - the format of the documentation. The default value is md that invokes (not yet finished) DocsEmitMarkdown generator. Finishing that generator is a work for the future.

However there is another DocsEmitSignatures generator that can be invoked via --docs=api. It ignores all documentation and just emits info about visible elements and their signatures. Sample output for can be found below.

Arguments have their name, followed by : and their fully qualified type when specified. Arguments may be prefixed by ~ indicating they are suspended. Arguments may contain trailing = indicating there is a default value for such an argument.

Important Notes

Use following command:

sbt:enso> runEngineDistribution --docs=api --in-project ./built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/

to generate signature snapshot for Standard.Base.

My plan is to use this infrastructure to signature check the public elements of Meta when #12031 is to be integrated.

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • All code follows the
    Scala,
    Java,
  • Unit tests written

@JaroslavTulach
Copy link
Member Author

I believe this PR provides good enough infrastructure for generating the documentation for a library. Use:

sbt:enso> runEngineDistribution --docs --in-project ./built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/lib/Standard/Base/0.0.0-dev/

Please pick the PR up and cultivate the content of .md files! CCing @jdunkerley, @Akirathan

@enso-bot
Copy link

enso-bot bot commented Jun 16, 2024

Jaroslav Tulach reports a new STANDUP for yesterday (2024-06-15):

Progress: - infrastructure to generate documentation: #10291

@JaroslavTulach JaroslavTulach marked this pull request as draft July 12, 2024 04:39
@JaroslavTulach JaroslavTulach self-assigned this Jan 15, 2025
@enso-bot enso-bot bot mentioned this pull request Jan 16, 2025
@JaroslavTulach JaroslavTulach changed the title WIP: Generate documentation of a library Infrastructure for enso --docs option & signature generator Jan 16, 2025
@JaroslavTulach JaroslavTulach added the CI: No changelog needed Do not require a changelog entry for this PR. label Jan 16, 2025
@JaroslavTulach JaroslavTulach marked this pull request as ready for review January 16, 2025 19:49
@JaroslavTulach
Copy link
Member Author

## Enso Signatures 1.0
## module Standard.Base.Meta
- type Type
    - constructors self -> (Standard.Base.Data.Vector.Vector Standard.Base.Meta.Constructor)
    - methods self -> Standard.Base.Data.Vector.Vector
    - qualified_name self -> Standard.Base.Data.Text.Text
    - name self -> Standard.Base.Data.Text.Text
    - find qualified_name:Standard.Base.Data.Text.Text -> Standard.Base.Any.Any
- type Atom
    - value self -> Standard.Base.Any.Any
    - fields self -> (Standard.Base.Data.Vector.Vector Standard.Base.Any.Any)
    - constructor self -> Standard.Base.Meta.Constructor
- type Constructor
    - value self -> Standard.Base.Function.Function
    - fields self -> (Standard.Base.Data.Vector.Vector Standard.Base.Data.Text.Text)
    - name self -> Standard.Base.Data.Text.Text
    - new self fields:(Standard.Base.Data.Vector.Vector|Standard.Base.Data.Array.Array) -> Standard.Base.Any.Any
    - declaring_type self -> Standard.Base.Meta.Type
- type Primitive
    - value self -> Standard.Base.Any.Any
- type Unresolved_Symbol
    - rename self new_name:Standard.Base.Data.Text.Text -> Standard.Base.Meta.Unresolved_Symbol
    - name self -> Standard.Base.Data.Text.Text
    - instrument self -> Standard.Base.Meta.Instrumentor
- type Error
    - value self -> Standard.Base.Any.Any
- type Polyglot
    - value self -> Standard.Base.Any.Any
    - get_language self -> Standard.Base.Meta.Language
Standard.Base.Any.Any.is_same_object_as self value:Standard.Base.Any.Any -> Standard.Base.Data.Boolean.Boolean
Standard.Base.Any.Any.is_a self typ:Standard.Base.Any.Any -> Standard.Base.Data.Boolean.Boolean
Standard.Base.Error.Error.is_a self typ:Standard.Base.Any.Any -> Standard.Base.Data.Boolean.Boolean
atom_with_hole factory:Standard.Base.Any.Any -> Standard.Base.Any.Any
meta ~value:Standard.Base.Any.Any -> (Standard.Base.Meta.Atom|Standard.Base.Meta.Constructor|Standard.Base.Meta.Primitive|Standard.Base.Meta.Polyglot|Standard.Base.Meta.Unresolved_Symbol|Standard.Base.Meta.Error)
is_same_object value_1:Standard.Base.Any.Any value_2:Standard.Base.Any.Any -> Standard.Base.Data.Boolean.Boolean
is_a value:Standard.Base.Any.Any typ:Standard.Base.Any.Any -> Standard.Base.Data.Boolean.Boolean
type_of value:Standard.Base.Any.Any -> Standard.Base.Any.Any
get_annotation target:Standard.Base.Any.Any method:Standard.Base.Any.Any parameter_name:Standard.Base.Any.Any -> Standard.Base.Any.Any
- type Language
    - Java
    - Unknown
is_atom_constructor ~value:Standard.Base.Any.Any -> Standard.Base.Data.Boolean.Boolean
is_atom value:Standard.Base.Any.Any -> Standard.Base.Data.Boolean.Boolean
is_error value:Standard.Base.Any.Any -> Standard.Base.Data.Boolean.Boolean
is_type value:Standard.Base.Any.Any -> Standard.Base.Data.Boolean.Boolean
is_polyglot value:Standard.Base.Any.Any -> Standard.Base.Data.Boolean.Boolean
get_source_location skip_frames:Standard.Base.Any.Any -> Standard.Base.Any.Any
get_simple_type_name value:Standard.Base.Any.Any -> Standard.Base.Any.Any
get_qualified_type_name value:Standard.Base.Any.Any -> Standard.Base.Any.Any
- type Instrumentor
    - uuid id:Standard.Base.Data.Text.Text -> Standard.Base.Any.Any
    - on_enter self fn:Standard.Base.Any.Any -> Standard.Base.Any.Any
    - on_return self fn:Standard.Base.Any.Any expression:(Standard.Base.Data.Text.Text|Standard.Base.Nothing.Nothing)= -> Standard.Base.Any.Any
    - on_call self fn:Standard.Base.Any.Any -> Standard.Base.Any.Any
    - activate self -> Standard.Base.Any.Any

Copy link
Collaborator

@hubertp hubertp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly fine. Few nits to consider

value.invokeMember(
COMPILE,
shouldCompileDependencies,
docsArg.getOrElse(false)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this correct? It seems that the underlying value of docsArg is a String?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was:

  • false - don't generate
  • true - generate and use default "style"
  • any String - generate and use the "style" specified by the string

engine/runner/src/main/java/org/enso/runner/Main.java Outdated Show resolved Hide resolved
engine/runner/src/main/java/org/enso/runner/Main.java Outdated Show resolved Hide resolved
import org.enso.pkg.QualifiedName;

final class DocsUtils {
private static final String ANY = "Standard.Base.Any.Any";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this available as a constant already somewhere? I'd like to avoid duplicates like that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are few occurrences and even some definitions:

ANY

The most suitable one would probably be BuiltinTypes.FQN_ANY, but it is not public and the dependency on package org.enso.compiler.pass.analyse.types doesn't seem correct either.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I figured BuiltinTypes.FQN_ANY should be the source of truth. Shame that we can't include it as a dependency.

JaroslavTulach and others added 2 commits January 20, 2025 10:53
Co-authored-by: Hubert Plociniczak <[email protected]>
Co-authored-by: Hubert Plociniczak <[email protected]>
Copy link
Member

@Akirathan Akirathan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I would also prefer new methods in Compiler rather than adding a parameter, but it is fine.


private DocsUtils() {}

static String toSignature(Method.Explicit m) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to have a lot in common with TypeInferenceSignatures pass.

I wonder if you could rewrite it to use the results of that pass instead? You could rely on the pass to check the arguments and return types, and also we have there already a way to render the type signature in textual form which we could re-use.

Maybe we could avoid duplication of some of the logic. I guess the problem is TypeInferenceSignatures does not currently handle names of arguments nor if they have default value. But I think this can be easily fixed by extending

--- a/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypeRepresentation.java	(revision 1c0ce51bd71281f66428c19057b255bb69e5aa0c)
+++ b/engine/runtime-compiler/src/main/java/org/enso/compiler/pass/analyse/types/TypeRepresentation.java	(date 1737379428154)
@@ -72,7 +72,7 @@
     }
   }
 
-  record ArrowType(TypeRepresentation argType, TypeRepresentation resultType)
+  record ArrowType(String argName, TypeRepresentation argType, boolean hasDefaultValue, TypeRepresentation resultType)
       implements TypeRepresentation {
     @Override
     public String toString() {

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to share the code, but all fails since start:

if (hasAnyDefaults) {
// TODO inferring types that have default arguments
yield null;
}

default arguments are prefixed with ~ in the --docs=api format. E.g. we have to process them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TypeRepresentation classes are really solving similar issues. I recognize hacks I had to do myself. However the suspended arguments support is missing and I need to move forward with #12031 - e.g. I guess I leave the unification for the future.

Copy link
Member

@radeusgd radeusgd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look great.

I'd suggest trying to re-use the TypeInferenceSignatures pass (or extract common logic from it) here. As otherwise are are getting two places that essentially do the same thing (extract the signatures of methods from IR). But that will require some slight changes to TypeInferenceSignatures although I think they should be relatively small.

@JaroslavTulach JaroslavTulach merged commit 570f141 into develop Jan 21, 2025
48 of 49 checks passed
@JaroslavTulach JaroslavTulach deleted the wip/jtulach/Docs branch January 21, 2025 05:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
-compiler -parser CI: No changelog needed Do not require a changelog entry for this PR. w-docs Website: Documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants