package com.jfreeman.real.pass;

import com.jfreeman.attribute.Attribute;
import com.jfreeman.attribute.LateBoundAttribute;
import com.jfreeman.attribute.EarlyBoundAttribute;
import com.jfreeman.lazy.LazyHelp;
import com.jfreeman.real.syntax.ConsProduction;
import com.jfreeman.real.syntax.DigitNode;
import com.jfreeman.real.syntax.FloatingPointProduction;
import com.jfreeman.real.syntax.IntegerProduction;
import com.jfreeman.real.syntax.ListNode;
import com.jfreeman.real.syntax.Node;
import com.jfreeman.real.syntax.SingletonProduction;

/**
 * syn S.val :: double
 * inh L.side :: left | right
 * syn L.len :: int
 * syn L.val :: double
 * syn B.val :: double
 *
 * Parameterize by base:
 *
 * double BASE = 2.0
 *
 * S -> L1 '.' L2
 * S.val = L1.val + L2.val
 * L1.side = left
 * L2.side = right
 *
 * S -> L
 * S.val = L.val
 * L.side = left
 *
 * L -> L1 B
 * L.len = L1.len + 1
 * L.val = (L.side == left)
 *   ? L1.val * BASE + B.val
 *   : L1.val        + B.val / pow(BASE, L.len)
 * L1.side = L.side
 *
 * L -> B
 * L.len = 1
 * L.val = { double v = B.val; if (L.side == right) { v /= BASE; } return v; }
 *
 * B -> 0
 * B.val = 0.0
 *
 * B -> 1
 * B.val = 1.0
 *
 * @author jfreeman
 */
public class LAttributedValuePass
{
    public static double evaluate(Node root) {
        Visitor visitor = new Visitor();
        root.accept(visitor);
        return LazyHelp.force(visitor._val.get(root));
    }

    private static final double BASE = 2.0;

    private enum Side {
        LEFT, RIGHT;
    }

    private static class Visitor
        extends AbstractPassVisitor
    {
        private Attribute<Node, Double> _val
            = new EarlyBoundAttribute<>();
        private Attribute<ListNode, Integer> _len
            = new EarlyBoundAttribute<>();
        private Attribute<ListNode, Side> _side
            = new LateBoundAttribute<>();

        @Override
        protected void annotate(FloatingPointProduction node) {
            _val.put(node, LazyHelp.delay(
                _val.get(node.left()),
                _val.get(node.right()),
                (l, r) -> l + r
            ));
            _side.put(node.left(), LazyHelp.delay(Side.LEFT));
            _side.put(node.right(), LazyHelp.delay(Side.RIGHT));
        }

        @Override
        protected void annotate(IntegerProduction node) {
            _val.put(node, _val.get(node.list()));
            _side.put(node.list(), LazyHelp.delay(Side.LEFT));
        }

        @Override
        protected void annotate(ConsProduction node) {
            _len.put(node, LazyHelp.delay(
                _len.get(node.head()),
                len -> len + 1
            ));
            _val.put(node, LazyHelp.delay(
                _side.get(node),
                _val.get(node.head()),
                _val.get(node.tail()),
                _len.get(node),
                (side, h, t, len) -> (side == Side.LEFT)
                       ? h * BASE + t
                       : h + t / Math.pow(BASE, len)
            ));
            _side.put(node.head(), _side.get(node));
        }

        @Override
        protected void annotate(SingletonProduction node) {
            _len.put(node, LazyHelp.delay(1));
            _val.put(node, LazyHelp.delay(
                _val.get(node.digit()),
                _side.get(node),
                (v, side) -> (side == Side.RIGHT) ? v / BASE : v
            ));
        }

        @Override
        protected void annotate(DigitNode node) {
            _val.put(node, LazyHelp.delay((double) node.value()));
        }
    }
}

@@ -540,16 +540,25 @@
 n;%0A%0A/**%0A
+ * %3Cpre%3E%0A
  * syn S
@@ -668,22 +668,35 @@
  double%0A
+ * %3C/pre%3E%0A
  *%0A * 
+%3Cp%3E
 Paramete
@@ -708,20 +708,33 @@
 by base:
+%3C/p%3E
 %0A *%0A
+ * %3Cpre%3E%0A
  * doubl
@@ -744,24 +744,43 @@
 ASE = 2.0%0A *
+ %3C/pre%3E%0A *%0A * %3Cpre%3E
 %0A * S -%3E L1 
@@ -848,24 +848,43 @@
 e = right%0A *
+ %3C/pre%3E%0A *%0A * %3Cpre%3E
 %0A * S -%3E L%0A 
@@ -918,16 +918,35 @@
  left%0A *
+ %3C/pre%3E%0A *%0A * %3Cpre%3E
 %0A * L -%3E
@@ -1006,16 +1006,18 @@
 t)%0A *   
+  
 ? L1.val
@@ -1034,16 +1034,18 @@
 B.val%0A *
+  
    : L1.
@@ -1104,16 +1104,35 @@
 .side%0A *
+ %3C/pre%3E%0A *%0A * %3Cpre%3E
 %0A * L -%3E
@@ -1228,16 +1228,35 @@
  v; %7D%0A *
+ %3C/pre%3E%0A *%0A * %3Cpre%3E
 %0A * B -%3E
@@ -1271,24 +1271,43 @@
 val = 0.0%0A *
+ %3C/pre%3E%0A *%0A * %3Cpre%3E
 %0A * B -%3E 1%0A 
@@ -1326,28 +1326,15 @@
 0%0A *
-%0A * @author jfreeman
+ %3C/pre%3E
 %0A */

Fix HTML in Javadoc