-
Notifications
You must be signed in to change notification settings - Fork 7
Experiment - eliminate creation of nested tuples #78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sergei-shabanau
wants to merge
2
commits into
master
Choose a base branch
from
75-ast-zip-optimization
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
src/test/scala/org/spartanz/parserz/prototype/P2Module.scala
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| package org.spartanz.parserz.prototype | ||
|
|
||
| import org.spartanz.parserz.ParsersModule | ||
|
|
||
| trait P2Module extends ParsersModule { | ||
| import Grammar._ | ||
|
|
||
| type S | ||
| type E | ||
| type G[A] = Grammar[S, S, E, A] | ||
|
|
||
| object Tools { | ||
| import Hacks._ | ||
|
|
||
| sealed trait Equiv[A, Repr] | ||
| case class Equiv3[Z, A, B, C](f: (A, B, C) => Z, g: Z => (A, B, C)) extends Equiv[((A, B), C), Z] | ||
| case class Equiv4[Z, A, B, C, D](f: (A, B, C, D) => Z, g: Z => (A, B, C, D)) extends Equiv[(((A, B), C), D), Z] | ||
|
|
||
| object Equiv { | ||
| // def caseClass1[Z, A](f: A => Z, g: Z => Option[A]): Equiv[A, Z] = ??? | ||
| // def caseClass2[Z, A, B](f: (A, B) => Z, g: Z => Option[(A, B)]): Equiv[(A, B), Z] = ??? | ||
| def caseClass3[Z, A, B, C](f: (A, B, C) => Z, g: Z => (A, B, C)): Equiv[((A, B), C), Z] = Equiv3(f, g) | ||
| def caseClass4[Z, A, B, C, D](f: (A, B, C, D) => Z, g: Z => (A, B, C, D)): Equiv[(((A, B), C), D), Z] = Equiv4(f, g) | ||
| } | ||
|
|
||
| // using Equiv with prior optimization of Zip operations | ||
| def toZ[A, AA, Z](g: G[A])(implicit equiv: Equiv[AA, Z], ev: AA <:< A): G[Z] = { | ||
| val g1: Option[GADT.ZipUnsafe[S, S, E]] = equiv match { | ||
| case Equiv3(_, _) => zippy(3)(g).map(l => GADT.ZipUnsafe(l.toArray)) | ||
| case Equiv4(_, _) => zippy(4)(g).map(l => GADT.ZipUnsafe(l.toArray)) | ||
| } | ||
| // g1.fold { | ||
| // toZDirect(g)(equiv, ev) | ||
| // ??? | ||
| // } { g2 => | ||
| // place where we cast types back at runtime | ||
| equiv match { | ||
| case equiv: Equiv3[Z, ta, tb, tc] => GADT.Map[S, S, E, Array[Any], Z](g1.get, | ||
| arr => { | ||
| val Array(a: ta, b: tb, c: tc) = arr | ||
| Right(equiv.f(a, b, c)) | ||
| }, | ||
| z => { | ||
| val (a: ta, b: tb, c: tc) = equiv.g(z) | ||
| Right(Array(a, b, c)) | ||
| } | ||
| ) | ||
| case equiv: Equiv4[Z, ta, tb, tc, td] => GADT.Map[S, S, E, Array[Any], Z](g1.get, | ||
| arr => { | ||
| val Array(a: ta, b: tb, c: tc, d: td) = arr | ||
| Right(equiv.f(a, b, c, d)) | ||
| }, | ||
| z => { | ||
| val (a: ta, b: tb, c: tc, d: td) = equiv.g(z) | ||
| Right(Array(a, b, c, d)) | ||
| } | ||
| ) | ||
| } | ||
| // } | ||
| } | ||
|
|
||
| // using Equiv without any optimization of execution plan | ||
| def toZDirect[A, AA, Z](g: G[A])(implicit equiv: Equiv[AA, Z], ev: AA <:< A): G[Z] = | ||
| equiv match { | ||
| case equiv: Equiv3[Z, ta, tb, tc] => GADT.Map[S, S, E, A, Z](g, | ||
| { case ((a: ta, b: tb), c: tc) => Right(equiv.f(a, b, c)) }, | ||
| z => { | ||
| val (a: ta, b: tb, c: tc) = equiv.g(z) | ||
| Right(((a, b), c)) | ||
| } | ||
| ) | ||
| case equiv: Equiv4[Z, ta, tb, tc, td] => GADT.Map[S, S, E, A, Z](g, | ||
| { case (((a: ta, b: tb), c: tc), d: td) => Right(equiv.f(a, b, c, d)) }, | ||
| z => { | ||
| val (a: ta, b: tb, c: tc, d: td) = equiv.g(z) | ||
| Right((((a, b), c), d)) | ||
| } | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| // place where we loose types | ||
| object Hacks { | ||
| def zippy[A](size: Int)(g: G[A]): Option[List[G[Any]]] = { | ||
|
|
||
| @scala.annotation.tailrec | ||
| def step[AA](i: Int)(acc: List[G[Any]])(g: G[AA]): List[G[Any]] = | ||
| g match { | ||
| // case GADT.ZipL(left, right, b) => | ||
| // case GADT.ZipR(left, right, a) => | ||
| case GADT.Zip(l, r) if i > 0 => | ||
| step(i - 1)(r.asInstanceOf[G[Any]] :: acc)(l) | ||
| case g if i > 0 => | ||
| g.asInstanceOf[G[Any]] :: acc | ||
| case _ => | ||
| acc | ||
| } | ||
|
|
||
| val list = step(size)(Nil)(g) | ||
| if (list.length == size) Some(list) else None | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| package org.spartanz.parserz.prototype | ||
|
|
||
| object T2 { | ||
|
|
||
| object Module extends P2Module { | ||
| override type Input = List[Char] | ||
| override type S = String | ||
| override type E = String | ||
| } | ||
|
|
||
| import Module.Grammar._ | ||
| import Module._ | ||
| import Tools._ | ||
|
|
||
| val one: G[Int] = "one" @@ consumePure(i => i.tail -> i.head.toString.toInt, { case (i, a) => i ::: a.toString.toList }) | ||
| val two: G[Boolean] = "two" @@ consumePure(i => i.tail -> (i.head == 'T'), { case (i, a) => i ::: (if (a) List('T') else List('F')) }) | ||
| val thr: G[String] = "thr" @@ succeed("blah") | ||
|
|
||
| case class Thing(idx: Int, exists: Boolean, name: String) | ||
|
|
||
| implicit val thingEquiv: Equiv[((Int, Boolean), String), Thing] = | ||
| Equiv.caseClass3(Thing.apply, Thing.unapply(_).get) | ||
|
|
||
| val g1: G[((Int, Boolean), String)] = one ~ two ~ thr | ||
|
|
||
| val g2: G[Thing] = toZDirect(g1) | ||
| val g3: G[Thing] = toZ(g1) | ||
|
|
||
|
|
||
| def main(args: Array[String]): Unit = { | ||
| println(parser(g1)("", List('1', 'T'))) | ||
| println() | ||
| println(parser(g2)("", List('1', 'T'))) | ||
| println() | ||
| println(parser(g3)("", List('1', 'T'))) | ||
| println() | ||
|
|
||
| println() | ||
| println(printer(g1)("", (Nil, ((2, true), "printed")))) | ||
| println() | ||
| println(printer(g2)("", (Nil, Thing(2, true, "printed")))) | ||
| println() | ||
| println(printer(g3)("", (Nil, Thing(2, true, "printed")))) | ||
| println() | ||
|
|
||
| println() | ||
| println(bnf("g1" @@ g1).mkString("\n")) | ||
| println() | ||
| println(bnf("g2" @@ g2).mkString("\n")) | ||
| println() | ||
| println(bnf("g3" @@ g3).mkString("\n")) | ||
| println() | ||
|
Comment on lines
+31
to
+52
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Running yields same results for all cases |
||
| } | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added
ZipUnsafeinto existing algebra for demo.Correct implementation is to have
Grammar.GADTcompiled into another low level algebra, which in turn will be used to produce parser/printer functions.