Skip to content

Commit 1717979

Browse files
committed
Finally get working macros in place for a render hook method
1 parent 5796d2e commit 1717979

File tree

5 files changed

+161
-43
lines changed

5 files changed

+161
-43
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package japgolly.scalajs.react.hooks
2+
3+
import japgolly.microlibs.compiletime.MacroUtils
4+
import japgolly.scalajs.react.{Children, CtorType}
5+
import japgolly.scalajs.react.component.ScalaFn.Component
6+
import japgolly.scalajs.react.hooks.Api._
7+
import japgolly.scalajs.react.internal.Box
8+
import japgolly.scalajs.react.vdom.VdomNode
9+
import scala.reflect.macros.blackbox.Context
10+
11+
object HookMacros {
12+
13+
trait ApiSecondaryWithRenderMacros[P, C <: Children, Ctx, CtxFn[_], Step <: SubsequentStep[Ctx, CtxFn]] {
14+
self: PrimaryWithRender[P, C, Ctx, Step] with Secondary[Ctx, CtxFn, Step] =>
15+
16+
final def render(f: CtxFn[VdomNode])(implicit step: Step, s: CtorType.Summoner[Box[P], C]): Component[P, s.CT] =
17+
// Without macros: render(step.squash(f)(_))
18+
macro HookMacros.render[P, C, Ctx, CtxFn, Step]
19+
}
20+
}
21+
22+
@annotation.nowarn("cat=unused") // TODO: remove
23+
class HookMacros(val c: Context) extends MacroUtils {
24+
import c.universe._
25+
26+
def render[P, C <: Children, Ctx, CtxFn[_], Step <: SubsequentStep[Ctx, CtxFn]]
27+
(f: c.Tree)(step: c.Tree, s: c.Tree): c.Tree = {
28+
29+
var debug = false // showCode(c.macroApplication).contains("counter.value")
30+
31+
def println(args: Any*): Unit =
32+
if (debug) System.out.println(args.mkString)
33+
34+
println("="*120)
35+
println()
36+
37+
val self = c.prefix
38+
39+
val result = q"""
40+
{
41+
val f = $step.squash($f)
42+
$self.render(f)($s)
43+
}
44+
"""
45+
46+
if (debug)
47+
println("RESULT:\n" + showCode(result))
48+
49+
println()
50+
println("="*120)
51+
52+
result
53+
}
54+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package japgolly.scalajs.react.hooks
2+
3+
import japgolly.microlibs.compiletime.MacroEnv._
4+
import japgolly.scalajs.react.{Children, CtorType}
5+
import japgolly.scalajs.react.component.ScalaFn.Component
6+
import japgolly.scalajs.react.hooks.Api._
7+
import japgolly.scalajs.react.internal.Box
8+
import japgolly.scalajs.react.vdom.VdomNode
9+
import scala.quoted.*
10+
import scala.scalajs.js
11+
12+
object HookMacros {
13+
14+
trait ApiSecondaryWithRenderMacros[P, C <: Children, Ctx, CtxFn[_], _Step <: SubsequentStep[Ctx, CtxFn]] {
15+
self: PrimaryWithRender[P, C, Ctx, _Step] with Secondary[Ctx, CtxFn, _Step] =>
16+
17+
inline final def render(inline f: CtxFn[VdomNode])(implicit inline step: Step, inline s: CtorType.Summoner[Box[P], C]): Component[P, s.CT] =
18+
// Without macros: render(step.squash(f)(_))
19+
renderWorkaround[P, C, Ctx, CtxFn, Step, s.CT](this, f, step, s)
20+
}
21+
22+
// ===================================================================================================================
23+
24+
// https://github.com/lampepfl/dotty/issues/15357
25+
inline def renderWorkaround[
26+
P, C <: Children, Ctx, CtxFn[_], Step <: SubsequentStep[Ctx, CtxFn], CT[-p, +u] <: CtorType[p, u]
27+
](inline self: PrimaryWithRender[P, C, Ctx, Step] with Secondary[Ctx, CtxFn, Step],
28+
inline f : CtxFn[VdomNode],
29+
inline step : Step,
30+
inline s : CtorType.Summoner.Aux[Box[P], C, CT],
31+
): Component[P, CT] =
32+
${ renderMacro[P, C, Ctx, CtxFn, Step, CT]('self, 'f, 'step, 's) }
33+
34+
def renderMacro[P, C <: Children, Ctx, CtxFn[_], Step <: SubsequentStep[Ctx, CtxFn], CT[-p, +u] <: CtorType[p, u]]
35+
(self: Expr[PrimaryWithRender[P, C, Ctx, Step] with Secondary[Ctx, CtxFn, Step]],
36+
f : Expr[CtxFn[VdomNode]],
37+
step : Expr[Step],
38+
s : Expr[CtorType.Summoner.Aux[Box[P], C, CT]],
39+
)(using Quotes, Type[P], Type[C], Type[CT], Type[Ctx], Type[CtxFn], Type[Step]): Expr[Component[P, CT]] = {
40+
41+
import quotes.reflect.*
42+
43+
var debug = false // showCode(c.macroApplication).contains("counter.value")
44+
45+
def println(args: Any*): Unit =
46+
if (debug) System.out.println(args.mkString)
47+
48+
println("="*120)
49+
println()
50+
51+
val result: Expr[Component[P, CT]] =
52+
'{ $self.render($step.squash($f)(_))($s) }
53+
54+
if (debug)
55+
println("RESULT:\n" + result.show)
56+
57+
println()
58+
println("="*120)
59+
60+
result
61+
}
62+
63+
}

library/coreGeneric/src/main/scala/japgolly/scalajs/react/hooks/Api.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -690,9 +690,12 @@ object Api {
690690
def renderWithReuseBy[A](reusableInputs: Ctx => A)(f: A => VdomNode)(implicit s: CtorType.Summoner[Box[P], C], r: Reusability[A]): Component[P, s.CT]
691691
}
692692

693-
trait SecondaryWithRender[P, C <: Children, Ctx, CtxFn[_], _Step <: SubsequentStep[Ctx, CtxFn]] extends PrimaryWithRender[P, C, Ctx, _Step] with Secondary[Ctx, CtxFn, _Step] {
694-
final def render(f: CtxFn[VdomNode])(implicit step: Step, s: CtorType.Summoner[Box[P], C]): Component[P, s.CT] =
695-
render(step.squash(f)(_))
693+
trait SecondaryWithRender[P, C <: Children, Ctx, CtxFn[_], _Step <: SubsequentStep[Ctx, CtxFn]] extends PrimaryWithRender[P, C, Ctx, _Step] with Secondary[Ctx, CtxFn, _Step] with HookMacros.ApiSecondaryWithRenderMacros[P, C, Ctx, CtxFn, _Step] {
694+
695+
// This has been moved into HookMacros.ApiSecondaryWithRenderMacros
696+
//
697+
// final def render(f: CtxFn[VdomNode])(implicit step: Step, s: CtorType.Summoner[Box[P], C]): Component[P, s.CT] =
698+
// render(step.squash(f)(_))
696699

697700
final def renderReusable[A](f: CtxFn[Reusable[A]])(implicit step: Step, s: CtorType.Summoner[Box[P], C], v: A => VdomNode): Component[P, s.CT] =
698701
renderReusable(step.squash(f)(_))

library/testEmissions/jvm/src/test/resources/sjr/UseState-out2.js

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
function $c_Lsjr_test_emissions_UseState$() {
22
this.Lsjr_test_emissions_UseState$__f_Component = null;
33
$n_Lsjr_test_emissions_UseState$ = this;
4-
$j_sjr_package$.$m_Lsjr_package$();
5-
var this$4 = $j_sjr_hooks_HookComponentBuilder$.$m_Lsjr_hooks_HookComponentBuilder$().apply__Lsjr_hooks_HookComponentBuilder$ComponentP$First();
6-
var initialState = new $j_AnonFunction0.$c_sjsr_AnonFunction0(() => 123);
7-
var step = new $j_sjr_hooks_HookComponentBuilder$ComponentP$FirstStep.$c_Lsjr_hooks_HookComponentBuilder$ComponentP$FirstStep();
8-
var this$18 = $j_sjr_hooks_Api$SecondaryWithRender.$as_Lsjr_hooks_Api$SecondaryWithRender($j_sjr_hooks_Api$Primary.$f_Lsjr_hooks_Api$Primary__useState__F0__Lsjr_hooks_Api$AbstractStep__O(this$4, initialState, step));
9-
var f = new $j_AnonFunction2.$c_sjsr_AnonFunction2((x$1$2, s$2) => {
4+
var this$1 = $j_sjr_hooks_HookComponentBuilder$ComponentP$SubsequentStep$.$m_Lsjr_hooks_HookComponentBuilder$ComponentP$SubsequentStep$();
5+
var f = $j_scala_Function1.$as_F1(new $j_sjr_hooks_ComponentP_SubsequentSteps$$anon$1.$c_Lsjr_hooks_ComponentP_SubsequentSteps$$anon$1(this$1).squash__F1().apply__O__O(new $j_AnonFunction2.$c_sjsr_AnonFunction2((x$1$2, s$2) => {
106
$j_java_lang_Object.$as_jl_Void(x$1$2);
117
var s = $j_sjr_hooks_Hooks$UseStateF.$as_Lsjr_hooks_Hooks$UseStateF(s$2);
128
var $$x2 = $j_sjr_vdom_HtmlTagOf$.$m_Lsjr_vdom_HtmlTagOf$();
@@ -27,11 +23,12 @@ function $c_Lsjr_test_emissions_UseState$() {
2723
}))).Lsjr_callback_CallbackTo__f_japgolly$scalajs$react$callback$CallbackTo$$trampoline);
2824
})(s)), $j_sjr_vdom_Attr$EventCallback$.$m_Lsjr_vdom_Attr$EventCallback$().Lsjr_vdom_Attr$EventCallback$__f_defaultSync)];
2925
return $$x2.apply$extension__T__sci_Seq__Lsjr_vdom_TagOf("button", new $j_WrappedVarArgs.$c_sjsr_WrappedVarArgs(array));
30-
});
31-
var this$17 = $j_sjr_hooks_HookComponentBuilder$ComponentP$SubsequentStep$.$m_Lsjr_hooks_HookComponentBuilder$ComponentP$SubsequentStep$();
32-
var step$1 = new $j_sjr_hooks_ComponentP_SubsequentSteps$$anon$1.$c_Lsjr_hooks_ComponentP_SubsequentSteps$$anon$1(this$17);
33-
var s$3 = $j_sjr_CtorType$Summoner$.$m_Lsjr_CtorType$Summoner$().summonN__Lsjr_internal_Singleton__Lsjr_CtorType$Summoner($j_sjr_internal_Singleton$.$m_Lsjr_internal_Singleton$().Lsjr_internal_Singleton$__f_BoxUnit);
34-
this.Lsjr_test_emissions_UseState$__f_Component = $j_sjr_hooks_Api$SecondaryWithRender.$f_Lsjr_hooks_Api$SecondaryWithRender__render__O__Lsjr_hooks_Api$SubsequentStep__Lsjr_CtorType$Summoner__Lsjr_component_JsBaseComponentTemplate$ComponentWithRoot(this$18, f, step$1, s$3);
26+
})));
27+
$j_sjr_package$.$m_Lsjr_package$();
28+
var this$17 = $j_sjr_hooks_HookComponentBuilder$.$m_Lsjr_hooks_HookComponentBuilder$().apply__Lsjr_hooks_HookComponentBuilder$ComponentP$First();
29+
var initialState = new $j_AnonFunction0.$c_sjsr_AnonFunction0(() => 123);
30+
var step = new $j_sjr_hooks_HookComponentBuilder$ComponentP$FirstStep.$c_Lsjr_hooks_HookComponentBuilder$ComponentP$FirstStep();
31+
this.Lsjr_test_emissions_UseState$__f_Component = $j_sjr_hooks_HookComponentBuilder$ComponentP$Subsequent.$as_Lsjr_hooks_HookComponentBuilder$ComponentP$Subsequent($j_sjr_hooks_Api$Primary.$f_Lsjr_hooks_Api$Primary__useState__F0__Lsjr_hooks_Api$AbstractStep__O(this$17, initialState, step)).render__F1__Lsjr_CtorType$Summoner__Lsjr_component_JsBaseComponentTemplate$ComponentWithRoot(f, $j_sjr_CtorType$Summoner$.$m_Lsjr_CtorType$Summoner$().summonN__Lsjr_internal_Singleton__Lsjr_CtorType$Summoner($j_sjr_internal_Singleton$.$m_Lsjr_internal_Singleton$().Lsjr_internal_Singleton$__f_BoxUnit));
3532
}
3633

3734
export { $c_Lsjr_test_emissions_UseState$ };

library/testEmissions/jvm/src/test/resources/sjr/UseState-out3.js

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,37 @@ function $c_Lsjr_test_emissions_UseState$() {
55
var this$4 = $j_sjr_hooks_HookComponentBuilder$.$m_Lsjr_hooks_HookComponentBuilder$().apply__Lsjr_hooks_HookComponentBuilder$ComponentP$First();
66
var initialState = new $j_AnonFunction0.$c_sjsr_AnonFunction0(() => 123);
77
var step = new $j_sjr_hooks_HookComponentBuilder$ComponentP$FirstStep.$c_Lsjr_hooks_HookComponentBuilder$ComponentP$FirstStep();
8-
var this$16 = $j_sjr_hooks_Api$SecondaryWithRender.$as_Lsjr_hooks_Api$SecondaryWithRender($j_sjr_hooks_Api$Primary.$f_Lsjr_hooks_Api$Primary__useState__F0__Lsjr_hooks_Api$AbstractStep__O(this$4, initialState, step));
9-
var f = new $j_AnonFunction2.$c_sjsr_AnonFunction2((_$1, s) => {
10-
$j_java_lang_Object.$as_jl_Void(_$1);
11-
var s$1 = $j_sjr_hooks_Hooks$UseStateF.$as_Lsjr_hooks_Hooks$UseStateF(s);
12-
var this$14 = $j_sjr_vdom_HtmlTagOf$.$m_Lsjr_vdom_HtmlTagOf$();
13-
$j_sjr_vdom_html_$.$m_Lsjr_vdom_html_$();
14-
$j_sjr_vdom_Exports$.$m_Lsjr_vdom_Exports$();
15-
var self = "button";
16-
var $$x2 = $j_java_lang_Character$.$m_sr_ScalaRunTime$();
17-
$j_sjr_vdom_html_$.$m_Lsjr_vdom_html_$();
18-
$j_sjr_vdom_VdomNode$.$m_Lsjr_vdom_VdomNode$();
19-
var $$x1 = new $j_sjr_vdom_VdomNode$$anon$1.$c_Lsjr_vdom_VdomNode$$anon$1("Count is ");
20-
$j_sjr_vdom_html_$.$m_Lsjr_vdom_html_$();
21-
var v = $j_java_lang_Object.$uI(s$1.Lsjr_hooks_Hooks$$anon$2__f_raw[0]);
22-
$j_sjr_vdom_VdomNode$.$m_Lsjr_vdom_VdomNode$();
23-
var xs = $$x2.wrapRefArray__AO__sci_ArraySeq(new ($j_sjr_vdom_TagMod.$d_Lsjr_vdom_TagMod.getArrayOf().constr)([$$x1, new $j_sjr_vdom_VdomNode$$anon$1.$c_Lsjr_vdom_VdomNode$$anon$1(v), $j_sjr_vdom_html_$.$m_Lsjr_vdom_html_$().Lsjr_vdom_html_$__f_$up.Lsjr_vdom_HtmlAttrAndStyles$__f_onClick.$minus$minus$greater__F0__F1__Lsjr_vdom_TagMod(new $j_AnonFunction0.$c_sjsr_AnonFunction0((s$2 => () => {
24-
$j_sjr_Reusable$.$m_Lsjr_Reusable$();
25-
var r = $j_sjr_hooks_Hooks$UseStateF.$f_Lsjr_hooks_Hooks$UseStateF__modState__Lsjr_Reusable(s$2);
26-
var ev$1 = $j_scala_Function1.$as_F1(r.value__O()).apply__O__O(new $j_scala_Function1.$c_sjsr_AnonFunction1(_$2 => {
27-
var _$2$1 = $j_java_lang_Object.$uI(_$2);
8+
var ApiSecondaryWithRenderMacros_this = $j_sjr_hooks_HookComponentBuilder$ComponentP$Subsequent.$as_Lsjr_hooks_HookComponentBuilder$ComponentP$Subsequent($j_sjr_hooks_Api$Primary.$f_Lsjr_hooks_Api$Primary__useState__F0__Lsjr_hooks_Api$AbstractStep__O(this$4, initialState, step));
9+
this.Lsjr_test_emissions_UseState$__f_Component = ApiSecondaryWithRenderMacros_this.render__F1__Lsjr_CtorType$Summoner__Lsjr_component_JsBaseComponentTemplate$ComponentWithRoot(new $j_scala_Function1.$c_sjsr_AnonFunction1(_$4 => {
10+
var _$4$1 = $j_sjr_hooks_HookCtx$P1.$as_Lsjr_hooks_HookCtx$P1(_$4);
2811

29-
return 1 + _$2$1 | 0;
30-
}));
31-
return new $j_sjr_callback_CallbackTo.$c_Lsjr_callback_CallbackTo(ev$1 === null ? null : $j_sjr_callback_CallbackTo.$as_Lsjr_callback_CallbackTo(ev$1).Lsjr_callback_CallbackTo__f_trampoline);
32-
})(s$1)), $j_sjr_vdom_Attr$EventCallback$.$m_Lsjr_vdom_Attr$EventCallback$().Lsjr_vdom_Attr$EventCallback$__f_defaultSync)]));
33-
return $j_sjr_vdom_TagLite.$f_Lsjr_vdom_TagLite__apply__T__sci_Seq__Lsjr_vdom_TagOf(this$14, self, xs);
34-
});
35-
var step$1 = new $j_sjr_hooks_ComponentP_SubsequentSteps$$anon$1.$c_Lsjr_hooks_ComponentP_SubsequentSteps$$anon$1();
36-
var s$3 = $j_sjr_CtorType$Summoner$.$m_Lsjr_CtorType$Summoner$().summonN__Lsjr_internal_Singleton__Lsjr_CtorType$Summoner($j_sjr_internal_Singleton$.$m_Lsjr_internal_Singleton$().Lsjr_internal_Singleton$__f_BoxUnit);
37-
this.Lsjr_test_emissions_UseState$__f_Component = $j_sjr_hooks_Api$SecondaryWithRender.$f_Lsjr_hooks_Api$SecondaryWithRender__render__O__Lsjr_hooks_Api$SubsequentStep__Lsjr_CtorType$Summoner__Lsjr_component_JsBaseComponentTemplate$ComponentWithRoot(this$16, f, step$1, s$3);
12+
return $j_sjr_vdom_VdomNode.$as_Lsjr_vdom_VdomNode($j_scala_Function1.$as_F1(new $j_sjr_hooks_ComponentP_SubsequentSteps$$anon$1.$c_Lsjr_hooks_ComponentP_SubsequentSteps$$anon$1().squash__F1().apply__O__O(new $j_AnonFunction2.$c_sjsr_AnonFunction2((_$1, s) => {
13+
$j_java_lang_Object.$as_jl_Void(_$1);
14+
var s$1 = $j_sjr_hooks_Hooks$UseStateF.$as_Lsjr_hooks_Hooks$UseStateF(s);
15+
var this$16 = $j_sjr_vdom_HtmlTagOf$.$m_Lsjr_vdom_HtmlTagOf$();
16+
$j_sjr_vdom_html_$.$m_Lsjr_vdom_html_$();
17+
$j_sjr_vdom_Exports$.$m_Lsjr_vdom_Exports$();
18+
var self = "button";
19+
var $$x2 = $j_java_lang_Character$.$m_sr_ScalaRunTime$();
20+
$j_sjr_vdom_html_$.$m_Lsjr_vdom_html_$();
21+
$j_sjr_vdom_VdomNode$.$m_Lsjr_vdom_VdomNode$();
22+
var $$x1 = new $j_sjr_vdom_VdomNode$$anon$1.$c_Lsjr_vdom_VdomNode$$anon$1("Count is ");
23+
$j_sjr_vdom_html_$.$m_Lsjr_vdom_html_$();
24+
var v = $j_java_lang_Object.$uI(s$1.Lsjr_hooks_Hooks$$anon$2__f_raw[0]);
25+
$j_sjr_vdom_VdomNode$.$m_Lsjr_vdom_VdomNode$();
26+
var xs = $$x2.wrapRefArray__AO__sci_ArraySeq(new ($j_sjr_vdom_TagMod.$d_Lsjr_vdom_TagMod.getArrayOf().constr)([$$x1, new $j_sjr_vdom_VdomNode$$anon$1.$c_Lsjr_vdom_VdomNode$$anon$1(v), $j_sjr_vdom_html_$.$m_Lsjr_vdom_html_$().Lsjr_vdom_html_$__f_$up.Lsjr_vdom_HtmlAttrAndStyles$__f_onClick.$minus$minus$greater__F0__F1__Lsjr_vdom_TagMod(new $j_AnonFunction0.$c_sjsr_AnonFunction0((s$2 => () => {
27+
$j_sjr_Reusable$.$m_Lsjr_Reusable$();
28+
var r = $j_sjr_hooks_Hooks$UseStateF.$f_Lsjr_hooks_Hooks$UseStateF__modState__Lsjr_Reusable(s$2);
29+
var ev$1 = $j_scala_Function1.$as_F1(r.value__O()).apply__O__O(new $j_scala_Function1.$c_sjsr_AnonFunction1(_$2 => {
30+
var _$2$1 = $j_java_lang_Object.$uI(_$2);
31+
32+
return 1 + _$2$1 | 0;
33+
}));
34+
return new $j_sjr_callback_CallbackTo.$c_Lsjr_callback_CallbackTo(ev$1 === null ? null : $j_sjr_callback_CallbackTo.$as_Lsjr_callback_CallbackTo(ev$1).Lsjr_callback_CallbackTo__f_trampoline);
35+
})(s$1)), $j_sjr_vdom_Attr$EventCallback$.$m_Lsjr_vdom_Attr$EventCallback$().Lsjr_vdom_Attr$EventCallback$__f_defaultSync)]));
36+
return $j_sjr_vdom_TagLite.$f_Lsjr_vdom_TagLite__apply__T__sci_Seq__Lsjr_vdom_TagOf(this$16, self, xs);
37+
}))).apply__O__O(_$4$1));
38+
}), $j_sjr_CtorType$Summoner$.$m_Lsjr_CtorType$Summoner$().summonN__Lsjr_internal_Singleton__Lsjr_CtorType$Summoner($j_sjr_internal_Singleton$.$m_Lsjr_internal_Singleton$().Lsjr_internal_Singleton$__f_BoxUnit));
3839
}
3940

4041
export { $c_Lsjr_test_emissions_UseState$ };

0 commit comments

Comments
 (0)