package org.spoofax.jsglr2.layoutsensitive;

import org.metaborg.parsetable.IParseTable;
import org.metaborg.parsetable.actions.IReduce;
import org.metaborg.sdf2table.grammar.LayoutConstraintAttribute;
import org.metaborg.sdf2table.parsetable.ParseTableProduction;
import org.spoofax.jsglr2.parseforest.ParseForestConstruction;
import org.spoofax.jsglr2.parseforest.ParseForestManager;
import org.spoofax.jsglr2.parser.AbstractParseState;
import org.spoofax.jsglr2.parser.ParserVariant;
import org.spoofax.jsglr2.parser.observing.ParserObserving;
import org.spoofax.jsglr2.reducing.ReduceManager;
import org.spoofax.jsglr2.reducing.ReduceManagerFactory;
import org.spoofax.jsglr2.stack.AbstractStackManager;
import org.spoofax.jsglr2.stack.IStackNode;
import org.spoofax.jsglr2.stack.StackLink;
import org.spoofax.jsglr2.stack.paths.StackPath;

public class LayoutSensitiveReduceManager
//@formatter:off
   <StackNode   extends IStackNode,
    ParseState  extends AbstractParseState<ILayoutSensitiveParseForest, StackNode>>
//@formatter:on
    extends
    ReduceManager<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>, ILayoutSensitiveParseNode<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>>, StackNode, ParseState> {

    public LayoutSensitiveReduceManager(IParseTable parseTable,
        AbstractStackManager<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>, ILayoutSensitiveParseNode<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>>, StackNode, ParseState> stackManager,
        ParseForestManager<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>, ILayoutSensitiveParseNode<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>>, StackNode, ParseState> parseForestManager,
        ParseForestConstruction parseForestConstruction) {
        super(parseTable, stackManager, parseForestManager, parseForestConstruction);
    }

    public static
    //@formatter:off
       <StackNode_    extends IStackNode,
        ParseState_   extends AbstractParseState<ILayoutSensitiveParseForest, StackNode_>,
        StackManager_ extends AbstractStackManager<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>, ILayoutSensitiveParseNode<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>>, StackNode_, ParseState_>>
    //@formatter:on
    ReduceManagerFactory<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>, ILayoutSensitiveParseNode<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>>, StackNode_, ParseState_, StackManager_, LayoutSensitiveReduceManager<StackNode_, ParseState_>>
        factoryLayoutSensitive(ParserVariant parserVariant) {
        return (parseTable, stackManager, parseForestManager) -> new LayoutSensitiveReduceManager<>(parseTable,
            stackManager, parseForestManager, parserVariant.parseForestConstruction);
    }

    @Override protected void doReductionsHelper(
        ParserObserving<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>, ILayoutSensitiveParseNode<ILayoutSensitiveParseForest, ILayoutSensitiveDerivation<ILayoutSensitiveParseForest>>, StackNode, ParseState> observing,
        ParseState parseState, StackNode stack, IReduce reduce,
        StackLink<ILayoutSensitiveParseForest, StackNode> throughLink) {
        pathsLoop: for(StackPath<ILayoutSensitiveParseForest, StackNode> path : stackManager.findAllPathsOfLength(stack,
            reduce.arity())) {
            if(throughLink == null || path.contains(throughLink)) {
                StackNode pathBegin = path.head();
                ILayoutSensitiveParseForest[] parseNodes = stackManager.getParseForests(parseForestManager, path);

                if(reduce.production() instanceof ParseTableProduction) {
                    ParseTableProduction sdf2tableProduction = (ParseTableProduction) reduce.production();

                    for(LayoutConstraintAttribute lca : sdf2tableProduction.getLayoutConstraints()) {
                        // Skip the reduction if the constraint evaluates to false
                        if(!LayoutConstraintEvaluator.evaluate(lca.getLayoutConstraint(), parseNodes).orElse(true))
                            continue pathsLoop;
                    }
                }

                reducer(observing, parseState, pathBegin, reduce, parseNodes);
            }
        }
    }

}

@@ -484,68 +484,8 @@
 nt;%0A
-import org.spoofax.jsglr2.parser.observing.ParserObserving;%0A
 impo
@@ -688,100 +688,8 @@
 ode;
-%0Aimport org.spoofax.jsglr2.stack.StackLink;%0Aimport org.spoofax.jsglr2.stack.paths.StackPath;
 %0A%0Apu
@@ -2968,336 +2968,49 @@
 ted 
-void doReductionsHelper(%0A        ParserObserving%3CILayoutSensitiveParseForest, ILayoutSensitiveDerivation%3CILayoutSensitiveParseForest%3E, ILayoutSensitiveParseNode%3CILayoutSensitiveParseForest, ILayoutSensitiveDerivation%3CILayoutSensitiveParseForest%3E%3E, StackNode, ParseState%3E observing,%0A        ParseState parseState, StackNode stack
+boolean ignoreReducer(StackNode pathBegin
 , IR
@@ -3035,18 +3035,8 @@
     
-StackLink%3C
 ILay
@@ -3062,431 +3062,25 @@
 rest
-, StackNode%3E throughLink) %7B%0A        pathsLoop: for(StackPath%3CILayoutSensitiveParseForest, StackNode%3E path : stackManager.findAllPathsOfLength(stack,%0A            reduce.arity())) %7B%0A            if(throughLink == null %7C%7C path.contains(throughLink)) %7B%0A                StackNode pathBegin = path.head();%0A                ILayoutSensitiveParseForest%5B%5D parseNodes = stackManager.getParseForests(parseForestManager, path);%0A%0A        
+%5B%5D parseNodes) %7B%0A
     
@@ -3137,32 +3137,24 @@
 oduction) %7B%0A
-        
             
@@ -3253,24 +3253,16 @@
         
-    
-    
 for(Layo
@@ -3351,24 +3351,16 @@
         
-        
 // Skip 
@@ -3426,24 +3426,16 @@
         
-  
-      
 if(!Layo
@@ -3542,179 +3542,67 @@
     
-        continue pathsLoop;%0A                    %7D%0A                %7D%0A%0A                reducer(observing, parseState, pathBegin, reduce, parseNodes);%0A            %7D%0A        %7D
+return true;%0A            %7D%0A        %7D%0A%0A        return false;
 %0A   

Refactor layout sensitive reducing to use mechanism for ignoring reducers