Code Monkey home page Code Monkey logo

macro-visit's Introduction

Macro Visit

A macro-based generic visitor generator

Continuous Integration Maven Central License Join the chat at https://gitter.im/sangria-graphql/sangria

SBT Configuration:

libraryDependencies += "org.sangria-graphql" %% "macro-visit" % "<latest version>"

Introduction

Writing visitor code can be quite tedious, especially if some nodes need to be transformed (in immutable way) along the way. This becomes even harder if performance is a concern and data structures are deeply recursive, so non tail-recursive approach is not an option. macro-visit provides very simple way to create type-safe visitor code for arbitrary sealed case class hierarchies. Generated visitor provides following features:

  • Non-recursive traversal, which means all state is managed in the heap and you will not run into stack overflow errors with deep recursive data structures.
  • Optimised for performance and memory footprint. Generated code for class hierarchy traversal is compiled into tight while loop.
  • Allows to transform traversed object in immutable way. It generates code that uses case class's copy method to get updated instance of object in most efficient way (if object has several changes, it would be copied only once)
  • Allows to break traversal at any given node and skip nodes
  • Supports List, Vector, Seq and Option traversal

Generated visitors can be very useful for traversing and transforming AST (Abstract Syntax Tree).

Assuming that the base type is called Ast, following visitors are supported:

  • Visit(enter, leave), where enter and leave are Ast => VisitorCommand functions - it recursively visits all instances of Ast type
  • VisitAnyField(fn) - it visits all fields with special type S (which is different from Ast) along the way
  • VisitAnyFieldByName(fieldName, fn) - it visits all fields with provided name and special type S (which is different from Ast) along the way

Following visitor commands are supported:

  • Skip
  • Continue
  • Break
  • Transform(newValue, controlCommand)
  • Delete
  • DeleteAndBreak

Example

Here is how basic usage looks like:

import sangria.visitor._

val res = visit[Ast](root,
  Visit[Field](f => if (f.name == "hex") VisitorCommand.Delete else VisitorCommand.Continue),
  Visit[IntValue](v => VisitorCommand.Transform(IntValue(v.value + 1))))

Macro will look for all subtypes of Ast and then will generate traversal code for it with provided visitors. Visit takes 2 functions as an argument enter and leave which both have Ast โ‡’ VisitorCommand type.

Given following AST definitions:

sealed trait Ast

case class Vertex(name: String, edges: List[Edge], fields: Vector[Field] = Vector.empty) extends Ast
case class Edge(weight: Int, toVertex: Vertex) extends Ast
case class Field(name: String, value: Option[Value]) extends Ast

sealed trait Value extends Ast

case class StringValue(value: String) extends Value
case class IntValue(value: Int) extends Value

and sample data:

val root =
  Vertex("start", List(
    Edge(1, Vertex("colors", List(
      Edge(2, Vertex("RED", Nil, Vector(
        Field("intensity", Some(IntValue(123))),
        Field("hex", Some(StringValue("#FF0000")))
      ))),
      Edge(100, Vertex("GREEN", Nil, Vector(
        Field("hex", Some(StringValue("#00FF00")))
      )))
    ))),
    Edge(42, Vertex("books", List(
      Edge(1, Vertex("The Hobbit", Nil, Vector(
        Field("pages", Some(IntValue(320)))
      )))
    )))
  ))

The result of the transformation will look like this:

Vertex("start", List(
  Edge(1, Vertex("colors", List(
    Edge(2,Vertex("RED", Nil, Vector(
      Field("intensity", Some(IntValue(124)))))),
    Edge(100, Vertex("GREEN", Nil, Vector.empty))), Vector.empty)),
  Edge(42, Vertex("books", List(
    Edge(1, Vertex("The Hobbit", Nil, Vector(
      Field("pages", Some(IntValue(321))))))),
    Vector.empty))),
  Vector.empty)

License

macro-visit is licensed under Apache License, Version 2.0.

macro-visit's People

Contributors

ingemaradahl avatar jchyb avatar nickhudkins avatar olegilyenko avatar scala-steward avatar sh0hei avatar travisbrown avatar yanns avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

macro-visit's Issues

Better names for TransformSpecialNamed and TransformSpecial?

These are not yet documented.
As far as I can determine; they are used to modify a field of a case class.
Each specifies the type of the target field and TransformSpecialNamed names the field when the type matches more than one field.

Might I suggest that they be named something like TransformField and TransformFieldByName?

Strange modified date in 0.1.3 artifact

I am using org.sangria-graphql:sangria_2.13:3.0.0 dependency in a Maven project which uses org.apache.maven.plugins:maven-dependency-plugin:3.2.0:unpack-dependencies during the package phase. Unfortunately, the package phase keeps failing with the following error when the maven-dependency-plugin tries to expand the macro-visit_2.13-0.1.3.jar (which is a transitive dependency of org.sangria-graphql:sangria_2.13:3.0.0) into the target/classes directory:

org.apache.maven.plugin.PluginExecutionException: Execution null of goal org.apache.maven.plugins:maven-dependency-plugin:3.2.0:unpack-dependencies failed: Negative time

To investigate, I downloaded the macro-visit_2.13-0.1.3.jar from https://mvnrepository.com/artifact/org.sangria-graphql/macro-visit_2.13/0.1.3 and unzipped it on my local machine and found some strange modified dates which are likely the root cause for this issue.

image

Not quite sure how that happened. Maybe a glitch during the build? Other sangria dependencies seem to be just fine. Maybe a simple rebuild and release will fix the issue.

For now, I have manually added a dependency on macro-visit_2.13:0.1.2 which does not expose this problem and gets my build to pass.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.