All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.unlaxer.context.Transaction Maven / Gradle / Ivy

package org.unlaxer.context;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.unlaxer.CodePointIndex;
import org.unlaxer.CodePointLength;
import org.unlaxer.Committed;
import org.unlaxer.Cursor.EndExclusiveCursor;
import org.unlaxer.ParserCursor;
import org.unlaxer.Source;
import org.unlaxer.Token;
import org.unlaxer.Token.ScanDirection;
import org.unlaxer.TokenKind;
import org.unlaxer.TokenList;
import org.unlaxer.TransactionElement;
import org.unlaxer.parser.CollectingParser;
import org.unlaxer.parser.LazyInstance;
import org.unlaxer.parser.MetaFunctionParser;
import org.unlaxer.parser.Parser;
import org.unlaxer.parser.Parsers;
import org.unlaxer.parser.combinator.ChoiceInterface;
import org.unlaxer.parser.combinator.NonOrdered;

public interface Transaction extends TransactionListenerContainer , ParseContextBase{
	

	public default TransactionElement getCurrent() {
		return getTokenStack().peekFirst();
	}
	
	public default Optional getPrevious() {
		Iterator iterator = getTokenStack().iterator();
		iterator.next();
		return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.empty();
	}
	
	public default void consume(CodePointLength length) {
		getCurrent().consume(length);
	}

	public default void matchOnly(CodePointLength length) {
		getCurrent().matchOnly(length);
	}
	
	public default void begin(Parser parser) {
		getTokenStack().push(getCurrent().createNew());
		onBegin(get(), parser);
	}
	
	Collection getActions();
	
  default void addActions(AdditionalCommitAction... additionalCommitActions) {
    
    addActions(
      Stream.of(additionalCommitActions).collect(Collectors.toList())
    );
  }
  
  void addActions(List additionalCommitActions);
	
  /**
   * @param parser that processed tokens
   * @param tokenKind commit token's kind
   * @param actions effect ParseContext at committing phase if needed
   * @return last added Tokens
   */
  public default Committed commit(Parser parser, TokenKind tokenKind , AdditionalCommitAction... actions) {
    
    List allActions = new ArrayList<>();
    
    allActions.addAll(getActions());
    
    if(actions.length >0) {
      
      for (AdditionalCommitAction action :actions) {
        allActions.add(action);
      }
    }
      
    ParseContext parseContext = get();
    
    for (AdditionalCommitAction action : allActions) {
      if (action instanceof AdditionalPreCommitAction) {
        ((AdditionalPreCommitAction) action).effect(parser, parseContext);
      }
    }

    TransactionElement current = getTokenStack().pollFirst();
    TransactionElement parent = getCurrent();
    parent.setCursor(new ParserCursor(current.getParserCursor(),false));
    
    boolean outputCollected = doCreateMetaToken() || 
        false == parser instanceof MetaFunctionParser || 
        parser instanceof LazyInstance;

    Committed committed;

    if (parser instanceof CollectingParser && outputCollected) {
      
      Token collected = ((CollectingParser) parser).collect(
          current.tokens, tokenKind , tokenKind.passFilter);
      
      parent.tokens.add(collected);
      onCommit(parseContext, parser, TokenList.of(collected));
      committed = new Committed(collected, current.tokens);

    } else {

      parent.tokens.addAll(current.tokens);
      onCommit(parseContext, parser, current.tokens);
      committed = new Committed(current.tokens);
    }

    for (AdditionalCommitAction action : getActions()) {
      if (action instanceof AdditionalPostCommitAction) {
        ((AdditionalPostCommitAction) action)
          .effect(parser, parseContext , committed);
      }
    }
    return committed;
  }
    
	public default void rollback(Parser parser) {
		if (parser instanceof ChoiceInterface) {
			getChosenParserByChoice().remove(parser);
		}
		if (parser instanceof NonOrdered) {
			getOrderedParsersByNonOrdered().remove(parser);
		}
		TransactionElement pollFirst = getTokenStack().pollFirst();
		onRollback(get(), parser , pollFirst.getTokens());
	}
	
	public default Source getRemain(TokenKind tokenKind) {
		CodePointIndex position = getPosition(tokenKind);
		Source source = getSource();
    return source.peek(position, source.codePointLength().newWithMinus(position));
	}

	public default Source getConsumed(TokenKind tokenKind) {
		CodePointIndex position = getPosition(tokenKind);
		return getSource().peek(new CodePointIndex(0), position);
	}

	public default boolean allMatched() {
		return getPosition(TokenKind.matchOnly).eq(getSource().codePointLength());
	}

	public default boolean allConsumed() {
		return getPosition(TokenKind.consumed).eq(getSource().codePointLength());
	}

	public default Source peek(TokenKind tokenKind, CodePointLength length) {
		return getSource().peek(getCurrent().getPosition(tokenKind), length);
	}

	public default CodePointIndex getConsumedPosition() {
		return getPosition(TokenKind.consumed);
	}

	public default CodePointIndex getMatchedPosition() {
		return getPosition(TokenKind.matchOnly);
	}

	public default CodePointIndex getPosition(TokenKind tokenKind) {
		return getCurrent().getPosition(tokenKind);
	}
	
	
   public default EndExclusiveCursor getCursor(TokenKind tokenKind) {
	    return getCurrent().getCursor(tokenKind);
	 }

	
	public default Optional getChosen(ChoiceInterface choice) {
		return Optional.ofNullable(getChosenParserByChoice().get(choice));
	}

	public default Parsers getOrdered(NonOrdered nonOrdered) {
		return getOrderedParsersByNonOrdered().get(nonOrdered);
	}
	
	interface AdditionalCommitAction{}
	
	public interface AdditionalPreCommitAction extends AdditionalCommitAction {
		public void effect(Parser parser, ParseContext parseContext);
	}
	
	public interface AdditionalPostCommitAction extends AdditionalCommitAction {
		public void effect(Parser parser, ParseContext parseContext , Committed committed);
	}
	
	//check parser equality with instance is expected ? check case of equality by class is better for ?
	//cause , specify Predicate
	public default Optional getMatchedToken(Predicate targetParserPredicate) {

		return getTokenStack().stream()//
				.flatMap(transactionElement -> transactionElement.getTokens().stream())//
				.flatMap(token -> token.flatten().stream())//
				.filter(token -> targetParserPredicate.test(token.parser))//
				.findFirst();
	}
	
	public default TokenList getMatchedTokens(
			Predicate targetTokenPredicate , 
			ScanDirection breadthOrDepth) {

		return TokenList.of( 
		    getTokenStack().stream()//
  				.flatMap(transactionElement -> transactionElement.getTokens().stream())//
  				.flatMap(token -> token.flatten(breadthOrDepth).stream())//
  				.filter(targetTokenPredicate)//
  				.collect(Collectors.toList())
  	);
	}
	
	public default TokenList getMatchedTokens(
			Predicate targetTokenPredicate) {
		return getMatchedTokens(targetTokenPredicate, ScanDirection.Depth);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy