goccmack / gocc

Parser / Scanner Generator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

API stability and exported methods

mewmew opened this issue · comments

commented

I'd like to start a discussion regarding the exported API of Gocc. Which packages should be made available to end users (if any)? Within these packages, which exported identifiers should be made available, and which are only intended to be used by gocc internally.

The main reason for raising this question is that the answer dictates how we may develop gocc in the future. If the only interface we promise to keep stable is the command line interface, than we may change the internal implementation of Gocc as need arise and restructure its internal components.

I would personally wish to do a rather extensive cleanup of the internal packages used by Gocc, and was wondering if there are any known use cases where one may want to import a package from the gocc repository directly, rather than relying on the generated lexer and parser packages?

Personally, I've never found that to be the case, that is, I've never encountered a use case where an end-user of Gocc may wish to import github.com/goccmack/gocc/<pkgname> directly.

Depending on the outcome if this discussion, I would suggest that all packages internal to Gocc are clearly marked as such; preferably using the internal directory package structure introduce by the Go tool chain.

This is the approach takes by two of the projects I'm involved with which relies on Gocc, namely

https://github.com/graphism/dot
https://github.com/llir/llvm

Both of these projects hide internal details of the implementation using internal directories. More specifically, the packages which are automatically generated by Gocc are considered internal; e.g. https://github.com/graphism/dot/tree/master/internal

  • graphism/dot/internal/astx
  • graphism/dot/internal/errors
  • graphism/dot/internal/lexer
  • graphism/dot/internal/parser
  • graphism/dot/internal/token
  • graphism/dot/internal/util

The dot package in this example then takes the approach of providing dedicated packages intended for end users, such as package ast and package dot covering the AST of DOT files and functions for parsing DOT files, respectively.

The benefit of this approach, is that it enables Gocc to continue evolving without breaking any API promises to end-users.

My intention is to initiate this discussion, and try to figure out if there are any use-cases of the Gocc packages that I have not thought of.

I personally see Gocc as a tool, and its API promise to the users is only relevant in regards to the command line interface.

Should you all agree, I'd be happy to prepare a PR which moves internal components into an internal directory, before starting to prepare some more extensive cleanup PRs and refactoring efforts.

Hope to hear from you : )

CC: @goccmack, @awalterschulze

For anyone using gocc to generate code from BNF the only guaranteed API is the generated code. The only user of any of the packages you listed would be someone developing gocc itself. So I am happy with your proposal to move all the listed packages to an "internal" package.

commented

Lovely, I'll prepare a PR.

It took me a while to come around, because I haven't been a big fan of internal, even though I like the idea of limiting the exposed API. Which is contradicting.
So lets do internal :)

commented

It took me a while to come around, because I haven't been a big fan of internal, even though I like the idea of limiting the exposed API. Which is contradicting.

I had the same initial feeling. Also had this feeling when the three index slice syntax was introduced to the language. Now I quite like it.

So lets do internal :)

Great!

Three index slice syntax?
I think I missed something.

commented

From https://golang.org/ref/spec#Slice_expressions

Full slice expressions

For an array, pointer to array, or slice a (but not a string), the primary expression

a[low : high : max]

constructs a slice of the same type, and with the same length and elements as the simple slice expression a[low : high]. Additionally, it controls the resulting slice's capacity by setting it to max - low. Only the first index may be omitted; it defaults to 0.

wow very interesting. I think that will take me a while to get used to.

commented

wow very interesting. I think that will take me a while to get used to.

The three index slice syntax? It is very seldom used, but has at least one purpose.

Imagine a Read(b []byte) method which fills a buffer b. Further imagine that the implementation fills the entire length of b, but wishes to only give clients of the API access to the first part of this buffer (say the first line in a file, but the 4 KB is read by a buffered reader or so). By setting the capacity to the end of the first part of this buffer, the API may then restrict the client from accessing later parts of the buffer. That is to say, you can reslice to shrink the capacity of a slice, never grow it. At least this is my understanding of it, may be missing something ^^

Without any ability to set capacity, the Read method would have to create a new buffer with length of the first part (the first line in this case), copy the data from the old buffer to this new buffer and return the new, shorter buffer instead.