kenbot / goggles

Pleasant, yet principled Scala optics DSL
MIT License
195 stars 7 forks source link

Fixes #2: ^ points to right spot in compile errors #46

Closed kenbot closed 5 years ago

kenbot commented 5 years ago

This fixes #2.

This was way harder than I thought it would be, and required gigantic, violent refactoring which has left the codebase in a much better state for further maintenance and extension.

New things:

Cake pattern Because the macros need to use types dependent on a fixed whitebox.Context object (eg c.Type, c.Tree), we couldn't really have the interpreter separated into difference modules, since if you pass the Context into a constructor, the compiler will not be able to unify it with other constructors the same object has been passed into. So the interpreter was in one big complicated ball of mud file.

The cake pattern solves this, because the compiler is able to unify a shared Context val if mixed in with traits, using self-types. The interpreter part of the codebase is now split into several files that only do one thing, and should be much better to maintain.

MacroState and MacroResult MacroResult is now the type returned by the macros. It contains either a successfully assembled source tree or error information, including line numbers and a list of optic info. It is easy to put more stuff in here if we want the macros to return more things in the future.

MacroState is now the type of the state that the Parse monad munges around before it finally produces a MacroResult. This is also now a new extension point where new state can easily be added to the interpreter as required. MacroState always contains the offset of the LensExpr being currently interpreted, which is used to set the correct location of the ^ in the error messages.

Fragments The StringContext gives the macro a list of string fragments and arguments, all of the them source trees. These now get unified into a single list of Fragments to feed into the lexer. Fragment is a new ADT that can either be a Verbatim or an Argument, each taking a relative offset.

Line numbers There is now an At[A] wrapper class that wraps another class, adding an offset integer. The lexer wraps each Token in an At, and the parser produces an AST where each LensExpr is wrapped in At. If necessary, in the future this could evolve into a more broad-based decorator concept.

There is now an ErrorAt class, which wraps errors with an offset count; it differs from At in that it always contains a GogglesError[T], and is parameterised by T.