Skip to content

Support query symbol information - #85

Merged
liufengyun merged 36 commits into
mainfrom
doc-query
Jul 29, 2026
Merged

Support query symbol information#85
liufengyun merged 36 commits into
mainfrom
doc-query

Conversation

@liufengyun

@liufengyun liufengyun commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Fix #84 : Support query symbol information

Summary

Support query symbol information from command line:

jo compile --query jo.List.map

It outputs

[
  {
    "name": "jo.List.map",
    "kind": "def",
    "signature": "def map[S](f: T => S receives none): List[S] receives none",
    "source": { "file": "lib/List.jo", "line": 162 },
    "visibility": "public",
    "flags": ["loaded", "fun", "method"],
    "annotations": [],
    "doc": "Apply `f` to each element and return the resulting list."
  }
]

It is also possible to filter by file name:

jo compile --query file:main.jo src/*.jo

Only symbols defined in the specified will be included.

Checklist

  • Added / updated tests under tests/pos/ or tests/warn/
  • Docs updated if the change affects user-visible behavior
  • All commits are signed off (why?)
How to sign off commits

Use git commit -s to add the Signed-off-by line automatically:

To add a sign-off to the last commit retroactively:

git commit --amend -s --no-edit

To add sign-off to the last 3 commits:

git rebase --signoff HEAD~3

Security impact

No

Compatibility impact

No

  • Source compatibility: existing code continue to compile
  • SAST compatibility
    • forward compatibility: new libraries can be used by old compiler
    • backward comopatibility: old libraries can be used by new compiler
  • Standard Library compatibility:
    • forward compatibility: new code can work with old stdlib
    • backward compatibility: old code work with the new stdlib
  • Runtime Library compatibility:
    • forward compatibility: new code can work with old runtime
    • backward compatibility: old code work with the new runtime
  • Build tool
    • Build spec compatibility: old projects continue to build
    • Joy package compatibility: old .joy can be consumed by new build tool

Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
@liufengyun
liufengyun requested a review from necto July 27, 2026 15:28
@necto

necto commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

That's a good idea to include the source line

"source": { "file": "lib/List.jo", "line": 162 },

This made me thing that "endLine" could probably also be useful. I imagine, an LLM would want to read the actual definition of some symbol, in that case it could issue a "read" command with the begin and end lines to read only a slice of a file.

@necto necto left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Does --query work only with --format json?
If so, then you essentially give only two options:

  • "--query --format json"
  • "--format html" and no --query (or is it permitted and ignored?)

Thus you could simplify the API to accept either --query and then output json or no --query and output HTML and require --out, and you don't need the --format parameter.

Additionally, I am not sure --query is needed. If you output all available symbols in JSON format to stdout, and especially in JSONL (i.e., just a stream of json objects, rather than a JSON array), then the consumer can use a plethora of standard tools to filter/query/transform the json on-the-fly. For example they could use jq to select the symbol of interest and discard the rest.

Having your own query means you have to implement and explain the query language, and if it is even slightly non-trivial it means headache for the users to learn it and use correctly.

Comment thread docs/usage/commands/compile.md Outdated
Comment thread docs/usage/commands/compile.md Outdated
Comment thread docs/usage/reference/compiler-options.md Outdated
Comment thread stack-lang/doc/Compiler.scala Outdated
@liufengyun

Copy link
Copy Markdown
Contributor Author

Does --query work only with --format json? If so, then you essentially give only two options:

  • "--query --format json"
  • "--format html" and no --query (or is it permitted and ignored?)

Thus you could simplify the API to accept either --query and then output json or no --query and output HTML and require --out, and you don't need the --format parameter.

This is a good point, given that --doc and --query do not share code, we can decouple them.

The only case where --query is optional when source files are provided can be supported with a special selector such as all or *.

Currently, it kind of works as you mentioned: if --query is given, --format json is implied.

Additionally, I am not sure --query is needed. If you output all available symbols in JSON format to stdout, and especially in JSONL (i.e., just a stream of json objects, rather than a JSON array), then the consumer can use a plethora of standard tools to filter/query/transform the json on-the-fly. For example they could use jq to select the symbol of interest and discard the rest.

Having your own query means you have to implement and explain the query language, and if it is even slightly non-trivial it means headache for the users to learn it and use correctly.

The reason why --query is needed is that the name universe is huge: it by default contains all names in standard library, but may also contain names from 3rd party libraries. Without --query, it is just inconvenient for simple use cases --- users and LLMs should not need to resort to another tool for common use cases.

In addition, without --query, it's not clear how to support a simple use case like the following:

jo compie --query jo.List.map

@necto

necto commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Currently, it kind of works as you mentioned: if --query is given, --format json is implied.

Sure, but it invites confusion. As a language designer you should know that a better designed language makes something inexpressible rather than simply forbidden at compile or at runtime. CLI is a form of a language, so making unwanted things inexpressible also plays in its favor.

The reason why --query is needed is that the name universe is huge: it by default contains all names in standard library, but may also contain names from 3rd party libraries. Without --query, it is just inconvenient for simple use cases --- users and LLMs should not need to resort to another tool for common use cases.

Indeed it is large by default, but there is always --no-stdlib. If the most common case turns out to be looking for non-stdlib symbols, we could make stdlib opt-in rather than opt-out.

In addition, without --query, it's not clear how to support a simple use case like the following:

jo compie --query jo.List.map

Here is how I would do that in shell (note that I cannot avoid --query in the current implementation because jo errors):

jo compile --doc --query jo.List | jq '.. | objects | select(.name == "jo.List.map")'

Or, what is more likely, I (or LLM) would invoke jo compile --doc in a python script, and use its json parsing to parse and select the objects I'm interested in.

As an aside, --query jo.List gives me documentation of jo.List (class, section, pattern, and def), --query jo.List.map does not find anything:

$ ./bin/jo compile --doc --format json --query jo.List.map
[Error] No documentation entries match symbol selector jo.List.map
1 error(s), 0 warning(s)

BTW should jo/docs/usage/commands/doc.md also mention this new mode?

@liufengyun

Copy link
Copy Markdown
Contributor Author

Currently, it kind of works as you mentioned: if --query is given, --format json is implied.

Sure, but it invites confusion. As a language designer you should know that a better designed language makes something inexpressible rather than simply forbidden at compile or at runtime. CLI is a form of a language, so making unwanted things inexpressible also plays in its favor.

Yes, we can go even further here to decouple the --query from --doc.

The reason why --query is needed is that the name universe is huge: it by default contains all names in standard library, but may also contain names from 3rd party libraries. Without --query, it is just inconvenient for simple use cases --- users and LLMs should not need to resort to another tool for common use cases.

Indeed it is large by default, but there is always --no-stdlib. If the most common case turns out to be looking for non-stdlib symbols, we could make stdlib opt-in rather than opt-out.

I think --no-stdlib is only useful for compiling the standard library.

For normal compilation, standard library is indispensable.

In addition, without --query, it's not clear how to support a simple use case like the following:

jo compie --query jo.List.map

Here is how I would do that in shell (note that I cannot avoid --query in the current implementation because jo errors):

jo compile --doc --query jo.List | jq '.. | objects | select(.name == "jo.List.map")'

This is painful, I never remember the syntax of jq. Think the whole-program (source, stdlibs, 3rd-party libs) as a database of symbols, targeted query is a natural and inherent need which the interface design need to address, IMHO. Otherwise, it's an awkward interface to be used.

Or, what is more likely, I (or LLM) would invoke jo compile --doc in a python script, and use its json parsing to parse and select the objects I'm interested in.

As an aside, --query jo.List gives me documentation of jo.List (class, section, pattern, and def), --query jo.List.map does not find anything:

$ ./bin/jo compile --doc --format json --query jo.List.map
[Error] No documentation entries match symbol selector jo.List.map
1 error(s), 0 warning(s)

This is a bug, I'll investigate.

BTW should jo/docs/usage/commands/doc.md also mention this new mode?

jo doc is the tool interface, not compiler interface. The compiler interface begins with jo compile.

@necto

necto commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

My use case: retriever all the symbols defined in a file and their doc string (#84 ). Does this implementation support it?
I couldn't find the syntax to do that (--query expects an argument and I don't what I can pass to it to get everything from a file).

@necto

necto commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

I never remember the syntax of jq.

Luckily we have LLMs for that now.

Think the whole-program (source, stdlibs, 3rd-party libs) as a database of symbols, targeted query is a natural and inherent need which the interface design need to address, IMHO. Otherwise, it's an awkward interface to be used.

You can implement a separate jo filter or something command that would filter and select necessary entries from the full doc produced by jo doc --json.

I think adding a query language before anyone asks for it is premature, but I do not insist, as long as it does not get in the way.

@necto

necto commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

I think --no-stdlib is only useful for compiling the standard library.

For normal compilation, standard library is indispensable.

I am speaking only about documentation extraction. --no-stdlib would allow me not to worry about the huge list of definitions in stdlib when I am querying a single code file.

@liufengyun

Copy link
Copy Markdown
Contributor Author

My use case: retriever all the symbols defined in a file and their doc string (#84 ). Does this implementation support it? I couldn't find the syntax to do that (--query expects an argument and I don't what I can pass to it to get everything from a file).

If the namespace of the file is know, it can be done by querying the namespace symbol. Otherwise, query with the file name file:xxx.jo, it will output symbols in the file.

@liufengyun

Copy link
Copy Markdown
Contributor Author

I think --no-stdlib is only useful for compiling the standard library.
For normal compilation, standard library is indispensable.

I am speaking only about documentation extraction. --no-stdlib would allow me not to worry about the huge list of definitions in stdlib when I am querying a single code file.

--no-stdlib is only intended for compiling the standard library, it does not have other uses. It is impossible to compile other files without standard library.

@liufengyun

Copy link
Copy Markdown
Contributor Author

Think the whole-program (source, stdlibs, 3rd-party libs) as a database of symbols, targeted query is a natural and inherent need which the interface design need to address, IMHO. Otherwise, it's an awkward interface to be used.

You can implement a separate jo filter or something command that would filter and select necessary entries from the full doc produced by jo doc --json.

I think adding a query language before anyone asks for it is premature, but I do not insist, as long as it does not get in the way.

I think "query language" is not an accurate characterization: it's just an input format. If a user or LLM wants to know the interface of String, it simply queries jo.String. The query is always there, it's inherent with all the use cases I am aware of.

I'm not sure how to tell whether something is "premature" or not. But as principled design we never take a requirement at its surface value and for information-retrival interface, narrowing/querying is essential IMHO.

@necto

necto commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

If the namespace of the file is know, it can be done by querying the namespace symbol. Otherwise, query with the file name file:xxx.jo, it will output symbols in the file.

Here is how I tried to do it:

 ~/proj/jo $ ./bin/jo compile --doc --query "file:Byte.jo"
[Error] No documentation entries match file selector `file:Byte.jo`

1 error(s), 0 warning(s)
 ~/proj/jo $ ./bin/jo compile --doc --query "file:Byte.jo" lib/Byte.jo 
---------- Error at lib/Byte.jo:10:7 ---------------
| class Byte
|       ^^^^
|       Redefinition of Byte
|
| The name `Byte` is already defined at lib/Byte.jo:10:7
| class Byte
|       ^^^^

1 error(s), 0 warning(s)

@necto

necto commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

--no-stdlib is only intended for compiling the standard library, it does not have other uses. It is impossible to compile other files without standard library.

Then you can add an equivalent for docs. e.g. --no-stdlib-doc

@liufengyun

Copy link
Copy Markdown
Contributor Author

--no-stdlib is only intended for compiling the standard library, it does not have other uses. It is impossible to compile other files without standard library.

Then you can add an equivalent for docs. e.g. --no-stdlib-doc

That won't work, because without standard library, it is impossible generate docs.

Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
@liufengyun liufengyun changed the title Support doc query Support query symbol information Jul 29, 2026
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
@liufengyun

Copy link
Copy Markdown
Contributor Author

@necto Thank you again for your feedback. Now I have fixed the bugs you mentioned about file:Bytes.jo and jo.List.map, as well as addressed other feedback.

Could you please take a look and let me now whether it satisfies your use case?

@necto necto left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you please take a look and let me now whether it satisfies your use case?

It works well now. thank you.

I was surprised that you dropped the lines from the output (i.e., line:... endLine:...). But I did not intend to use that feature presently.

@liufengyun

liufengyun commented Jul 29, 2026 via email

Copy link
Copy Markdown
Contributor Author

Signed-off-by: Fengyun Liu <fengyun.liu.cs@gmail.com>
@liufengyun
liufengyun merged commit 6196b52 into main Jul 29, 2026
3 checks passed
@liufengyun
liufengyun deleted the doc-query branch July 29, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable structured documentation collection based on doc-comments

2 participants