Package org.zkoss.selector.lang

Source Code of org.zkoss.selector.lang.InSequenceStateMachine

/**
*
*/
package org.zkoss.selector.lang;

import java.util.List;

import org.zkoss.selector.lang.Parser.ParseException;
import org.zkoss.selector.lang.InSequenceStateMachine.SubState;
import org.zkoss.selector.lang.Token.Type;
import org.zkoss.selector.model.Selector;
import org.zkoss.selector.model.SimpleSelectorSequence;
import org.zkoss.selector.model.Attribute.Operator;
import org.zkoss.selector.model.Selector.Combinator;
import org.zkoss.selector.util.Debugger;
import org.zkoss.selector.util.MacroStateCtx;
import org.zkoss.selector.util.StateCtx;
import org.zkoss.selector.util.StateMachine;
import org.zkoss.selector.util.StateCtx.TransitionListener;
import org.zkoss.selector.util.StateMachine.StateMachineException;

/**
*
* @author simonpai
*/
public class Parser {
 
  private String _source;
  private Selector _selector;
  private Debugger _debugger;
 
  private InSequenceStateMachine _submachine;
 
  private StateMachine<State, CharClass, Token> _machine =
    new StateMachine<State, CharClass, Token>(){

    @Override
    protected void init() {
     
      getState(State.PRE_SELECTOR)
        .addTransition(CharClass.SELECTOR_LITERAL, State.IN_SELECTOR);
     
      setState(State.IN_SELECTOR,
          new MacroStateCtx<State, CharClass, Token, SubState, Type>(
              _submachine = new InSequenceStateMachine()) {
       
            @Override
            protected void init() {
              addReturningClasses(CharClass.SELECTOR_LITERAL);
              addTransition(CharClass.WHITESPACE, State.PRE_COMBINATOR);
            }
          });
     
      setState(State.PRE_COMBINATOR,
          new StateCtx<State, CharClass, Token>(){
           
            @Override
            protected void init() {
              addTransition(CharClass.COMBINATOR, State.POST_COMBINATOR,
                  new TransitionListener<Token, CharClass>(){
                public void onTransit(Token input, CharClass inputClass) {
                  _selector.attachCombinator(getCombinator(input));
                }
              });
              addTransition(CharClass.SELECTOR_LITERAL, State.IN_SELECTOR);
            }
      });
     
      getState(State.POST_COMBINATOR)
        .addTransition(CharClass.WHITESPACE, State.PRE_SELECTOR);
    }
   
    @Override
    protected CharClass getClass(Token input) {
      switch(input.getType()){
      case WHITESPACE:
        return CharClass.WHITESPACE;
       
      case CBN_CHILD:
      case CBN_ADJACENT_SIBLING:
      case CBN_GENERAL_SIBLING:
        return CharClass.COMBINATOR;
       
      default:
        return CharClass.SELECTOR_LITERAL;
      }
    }

    @Override
    protected State getLandingState(Token input, CharClass inputClass) {
      switch(inputClass){
      case WHITESPACE:
        return State.PRE_SELECTOR;
      case SELECTOR_LITERAL:
        return State.IN_SELECTOR;
      }
      return null;
    }
   
    @Override
    protected void onReset() {
      _submachine.setSelector(_selector);
      _submachine.setSource(_source);
    }

    @Override
    protected void onDebug(String message) {
      super.onDebug(message);
      if(_debugger != null)
        _debugger.debug(message);
    }
   
  };
 
  public Selector getSelector(){
    return _selector;
  }
 
  public Selector parse(List<Token> tokens, String source){
    _source = source;
    _selector = new Selector();
    _machine.start(tokens.iterator());
    return _selector;
  }
 
  public void setDebugMode(boolean mode){
    _machine.setDebugMode(mode);
    _submachine.setDebugMode(mode);
  }
 
  public void setDebugger(Debugger debugger){
    _debugger = debugger;
  }
 
 
 
  // state, char class //
  public enum State {
    PRE_SELECTOR, IN_SELECTOR, PRE_COMBINATOR, POST_COMBINATOR;
  }
 
  public enum CharClass {
    SELECTOR_LITERAL, WHITESPACE, COMBINATOR;
  }
 
 
 
  // helper //
  private Combinator getCombinator(Token token){
    switch(token.getType()){
    case CBN_CHILD:
      return Combinator.CHILD;
    case CBN_ADJACENT_SIBLING:
      return Combinator.ADJACENT_SIBLING;
    case CBN_GENERAL_SIBLING:
      return Combinator.GENERAL_SIBLING;
    }
    throw new IllegalStateException();
  }
 
 
 
  // exception //
  public static class ParseException extends StateMachineException {
   
    private static final long serialVersionUID = -7479725499711115534L;

    public ParseException(int step, Object state, Token input, String selector) {
      super(step, state, input, "Unexpected token " + input.getType() +
          " ("+input.source(selector)+") at index " + input.getBeginIndex());
    }
   
    public ParseException(String message){
      super(message);
    }
   
  }

}

/*package*/ class InSequenceStateMachine extends StateMachine<SubState, Type, Token> {
 
  private Selector _selector;
  private String _source;
  private SimpleSelectorSequence _seq;
 
  public InSequenceStateMachine setSource(String source){
    _source = source;
    return this;
  }
 
  public InSequenceStateMachine setSelector(Selector selector){
    _selector = selector;
    return this;
  }
 
  @Override
  protected Type getClass(Token input) {
    return input.getType();
  }
 
  @Override
  protected SubState getLandingState(Token input, Type inputClass) {
   
    switch(inputClass){
    case IDENTIFIER:
    case UNIVERSAL:
      return SubState.MAIN;
    case NTN_ID:
      return SubState.ID_PRE_VALUE;
    case NTN_CLASS:
      return SubState.CLASS_PRE_VALUE;
    case NTN_PSDOCLS:
      return SubState.PSDOCLS_PRE_NAME;
    case OPEN_BRACKET:
      return SubState.ATTR_PRE_NAME;
    default:
      return null;
    }
  }
 
  @Override
  protected void init() {
   
    // ID cycle
    getState(SubState.MAIN)
      .addRoute(Type.NTN_ID, SubState.ID_PRE_VALUE)
      .addRoute(Type.IDENTIFIER, SubState.MAIN, new TransitionListener<Token, Type>(){
        public void onTransit(Token input, Type inputClass) {
          // flush ID value
          if(_seq.getId() != null)
            throw new ParseException(
                "Cannot have more than 1 ID, failed at index " +
                input.getBeginIndex());
          _seq.setId(input.source(_source));
        }
      });
   
    // class cycle
    getState(SubState.MAIN)
      .addRoute(Type.NTN_CLASS, SubState.CLASS_PRE_VALUE)
      .addRoute(Type.IDENTIFIER, SubState.MAIN, new TransitionListener<Token, Type>(){
        public void onTransit(Token input, Type inputClass) {
          // flush class value
          _seq.addClass(input.source(_source));
        }
      });
   
    // pseudo class cycle
    getState(SubState.MAIN)
      .addRoute(Type.NTN_PSDOCLS, SubState.PSDOCLS_PRE_NAME)
      .addRoute(Type.IDENTIFIER, SubState.PSDOCLS_POST_NAME,
          new TransitionListener<Token, Type>(){
        public void onTransit(Token input, Type inputClass) {
          // flush pseudo class function name
          _seq.addPseudoClass(input.source(_source));
        }
      })
      .addRoute(Type.OPEN_PAREN, SubState.PSDOCLS_PRE_PARAM)
      .addRoute(Type.IDENTIFIER, SubState.PSDOCLS_POST_PARAM,
          new TransitionListener<Token, Type>(){
        public void onTransit(Token input, Type inputClass) {
          // flush pseudo class function parameter
          // TODO: support multiple parameters separated by comma
          _seq.attachPseudoClassParameter(input.source(_source));
        }
      })
      .addRoute(Type.CLOSE_PAREN, SubState.MAIN);
   
    // pseudo class with no parameter
    getState(SubState.PSDOCLS_POST_NAME)
      .addTransition(Type.NTN_ID, SubState.ID_PRE_VALUE)
      .addTransition(Type.NTN_CLASS, SubState.CLASS_PRE_VALUE)
      .addTransition(Type.NTN_PSDOCLS, SubState.PSDOCLS_PRE_NAME)
      .addTransition(Type.OPEN_BRACKET, SubState.ATTR_PRE_NAME);
   
    // attribute cycle
    getState(SubState.MAIN)
      .addRoute(Type.OPEN_BRACKET, SubState.ATTR_PRE_NAME)
      .addRoute(Type.IDENTIFIER, SubState.ATTR_POST_NAME,
          new TransitionListener<Token, Type>(){
        public void onTransit(Token input, Type inputClass) {
          // set attribute name
          _seq.addAttribute(input.source(_source));
        }
      })
      .addRoutes(SubState.ATTR_PRE_VALUE, new TransitionListener<Token, Type>(){
        public void onTransit(Token input, Type inputClass) {
          // set attribute operator
          _seq.attachAttributeOperator(getOperator(inputClass));
        }
      }, Type.OP_EQUAL, Type.OP_BEGIN_WITH, Type.OP_END_WITH, Type.OP_CONTAIN)
      .addRoute(Type.IDENTIFIER, SubState.ATTR_POST_VALUE,
          new TransitionListener<Token, Type>(){
        public void onTransit(Token input, Type inputClass) {
          // set attribute value
          _seq.attachAttributeValue(input.source(_source));
        }
      })
      .addRoute(Type.CLOSE_BRACKET, SubState.MAIN);
   
    // attribute value with quote
    getState(SubState.ATTR_PRE_VALUE)
      .addRoute(Type.DOUBLE_QUOTE, SubState.ATTR_PRE_VALUE_INQT)
      .addRoute(Type.IDENTIFIER, SubState.ATTR_POST_VALUE_INQT,
          new TransitionListener<Token, Type>(){
        public void onTransit(Token input, Type inputClass) {
          // set attribute value
          _seq.attachAttributeValue(input.source(_source), true);
        }
      })
      .addRoute(Type.DOUBLE_QUOTE, SubState.ATTR_POST_VALUE);
   
  }
 
  @Override
  protected void onStart(Token input, Type inputClass, SubState landing){
    _selector.add(_seq = new SimpleSelectorSequence());
    if(inputClass == Type.IDENTIFIER) _seq.setType(input.source(_source));
  }
 
  @Override
  protected void onStop(boolean endOfInput) {
    switch (_current) {
    case MAIN:
    case PSDOCLS_POST_NAME:
    case PSDOCLS_POST_PARAM:
    case ATTR_POST_VALUE:
      break;
    default:
      if (endOfInput)
        throw new ParseException("Unexpected end of token sequence.");
    }
  }
 
  @Override
  protected void onDebug(String message) {
    super.onDebug("\t" + message);
  }
 
 

  // helper //
  private Operator getOperator(Type inputClass){
    switch(inputClass){
    case OP_EQUAL:
      return Operator.EQUAL;
    case OP_BEGIN_WITH:
      return Operator.BEGIN_WITH;
    case OP_END_WITH:
      return Operator.END_WITH;
    case OP_CONTAIN:
      return Operator.CONTAIN;
    default:
      return null;
    }
  }
 
 
 
  // state //
  public enum SubState {
    MAIN, ID_PRE_VALUE, CLASS_PRE_VALUE,
   
    PSDOCLS_PRE_NAME, PSDOCLS_POST_NAME,
    PSDOCLS_PRE_PARAM, PSDOCLS_POST_PARAM,
   
    ATTR_PRE_NAME, ATTR_POST_NAME,
    ATTR_PRE_VALUE, ATTR_POST_VALUE,
    ATTR_PRE_VALUE_INQT, ATTR_POST_VALUE_INQT;
  }
 
}
TOP

Related Classes of org.zkoss.selector.lang.InSequenceStateMachine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.