So this week I recycled a talk I'd given in the past, about how even using extremely simple parsers allows a lot of useful static-analysis to be done, for specific niche use-cases.
This included examples of scanning comments above classes to ensure they referred to the appropriate object, ensuring that specific function calls always included a specific (optional) parameter, etc.
Nothing too complex, but I figured I'd give a new example this time, and I remembered I'd recently written a bunch of functions for an interpreter which I'd ordered quite deliberately.
Assume you're writing a BASIC interpreter, you need to implement a bunch of
built-in maths functions such as SIN
, COS
, TAN
, then some string-related
functions LEFT$
, RIGHT$
, MID$
, etc.
When it comes to ordering there are a couple of approaches:
- Stick them all in one package:
builtins/builtins.go
- Create a package and group them:
builtins/maths.go
builtins/string.go
- .. etc
Personal preference probably dictates the choice you make, but either way I think it would be rational and obvious that you'd put the functions in alphabetical order:
func ABS( args []primitive.Object) (primitive.Object, error) {
..}
func COS( args []primitive.Object) (primitive.Object, error) {
..}
func SIN( args []primitive.Object) (primitive.Object, error) {
..}
func TAN( args []primitive.Object) (primitive.Object, error) {
..}
I did that myself, and I wrote a perl-script to just parse the file using a simple regexp "^func\s+([^(]+)\(
" but then I figured this was a good time to write a real static-analysis tool.
The golang environment is full of trivial little linters for various purposes, and the standard "go vet ..
" driver makes it easy to invoke them. Realizing that I was going to get driven in the same way it was obvious I'd write something called "alphaVet".
So anyway, half written for a talk, half-written because of the name:
- Golang linter that reports failures if functions aren't in alphabetical order