Skip to content
This repository has been archived by the owner on Apr 18, 2020. It is now read-only.

Unify Generator API's #44

Open
DavidDudson opened this issue Jan 9, 2018 · 2 comments
Open

Unify Generator API's #44

DavidDudson opened this issue Jan 9, 2018 · 2 comments
Labels
Milestone

Comments

@DavidDudson
Copy link
Member

DavidDudson commented Jan 9, 2018

The whole split abstract class for different generators is nice in theory, but in reality, it is just a pain.

I have a proof of concept idea which is nearly complete.

For this to be performant, my latest changes to scalameta contrib will need to be pulled in, but this is not an issue at present.

Current

  1. Discover generators
  2. Match on generator type
  3. Apply based on Input Tree Type

Proposed

  1. Discover Generators
  2. Match on Input tree type.
  3. Apply ALL generators
  4. Abort or skip if generator incompatibility is detected

How it works

  1. My recent changes to scalameta contrib short circuit structural equality when the object is identical.
  2. I've added a method to scalagen like withStats that can short-circuit
  • I'm undecided on whether we want this to be the default as it requires both Extract and Replace instances present, which is a large binary incompatibility.
  1. It runs all generators on the input tree, in parallel.
  2. It then checks if more then one of the incompatible generators modified the tree. (aka is not identical to the source)
  3. If it did not abort, it will apply the transformations.

Incompatibilties

E = Extension
CE = CompanionExtension
M = Manipulation
T = Transmutation
P = Param

_ E CE M T P
E _ X X
CE _
M X _ X
T X X _
P _

As you can see, You cannot extend and manipulate the same Tree. You can, however, replicate this behavior by choosing the order as a generator author. By calling directly into the relevant method.

Examples

// Abort - tried to manipulate class twice
class Foo extends Generator("Foo") {
  def manipulate(c: Defn.Class): Defn.Class = ???
  def extend(c: Defn.Class): List[Stat] = ???
}
// Success - different tree types are fine
class Foo extends Generator("Foo") {
  def manipulate(c: Defn.Class): Defn.Class = ???
  def extend(c: Defn.Trait): List[Stat] = ???
}
// Success - no conflict as the Companion and class are different objects
class Foo extends Generator("Foo") {
  def extendCompanion(c: Defn.Class): List[Stat] = ???
  def extend(c: Defn.Class): List[Stat] = ???
}
@DavidDudson
Copy link
Member Author

DavidDudson commented Jan 9, 2018

@olafurpg Do you like this better than the current API?

@DavidDudson
Copy link
Member Author

Blocked by #24

@DavidDudson DavidDudson added this to the Version 0.1 milestone Jan 9, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

1 participant