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

org.unlaxer.tinyexpression.formatter.Formatter Maven / Gradle / Ivy

The newest version!
package org.unlaxer.tinyexpression.formatter;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.unlaxer.Parsed;
import org.unlaxer.StringSource;
import org.unlaxer.Token;
import org.unlaxer.context.ParseContext;
import org.unlaxer.parser.Parser;
import org.unlaxer.tinyexpression.parser.ExpressionTags;
import org.unlaxer.tinyexpression.parser.FormulaParser;
import org.unlaxer.tinyexpression.parser.IfExpressionParser;
import org.unlaxer.tinyexpression.parser.RightCurlyBraceParser;

public class Formatter {
  
  public static String format(String expression) {
    
    
    try(ParseContext parseContext = new ParseContext(new StringSource(expression))){
      FormatterContext formatterContext = new FormatterContext(0);
      
      FormulaParser formulaParser = Parser.get(FormulaParser.class);
      Parsed parsed = formulaParser.parse(parseContext);
      
      if(false == parsed.isSucceeded()) {
        return expression;
      }
      Token rootToken = parsed.getRootToken(true);
      
      render(formatterContext, rootToken);
      
      return formatterContext.toString();
      
    }catch (Exception e) {
      e.printStackTrace();
      return expression;
    }
  }
  
  static Comparator tokenComparator = (o1,o2)->{
    return o1.getTokenRange().compareTo(o2.tokenRange);
  };
  
  public static void renderIf(FormatterContext context , Token token) {
    
    FormatterContext formatterContext = new FormatterContext(context.startPosition());
    
    List filteredChildren = token.filteredChildren;
    for (Token child : filteredChildren) {
//      if(child.getParser() instanceof NumberExpressionParser) {
      if(child.getParser().hasTag(ExpressionTags.thenAndElse.tag())) {
          renderIf(formatterContext, child);
          context.append(formatterContext.toString());
          formatterContext.clear();
          continue;
      }
      if(child.getParser().hasTag(ExpressionTags.returning.tag())) {
//        formatterContext.n();
        formatterContext.increment();
        render(formatterContext, child);
//        formatterContext.n();
        formatterContext.decrement();
      }else {
        render(formatterContext, child);
      }
    }
    context.append(formatterContext.toString());
  }
  
  public static void renderCaseExpression(FormatterContext context , Token token) {
    
    List filteredChildren = token.filteredChildren.stream()
//      .filter(child->child.getParser() instanceof NumberCaseFactorParser)
        .filter(child->child.getParser().hasTag(ExpressionTags.matchCaseFactor.tag()))
        .collect(Collectors.toList());
    Iterator iterator = filteredChildren.iterator();
    while (iterator.hasNext()) {
      Token child = (Token) iterator.next();
      render(context, child);
      context
          .append(",")
          .n()
          .tab();
    }
  }

  
  public static void renderMatch(FormatterContext context , Token token) {
    
    FormatterContext formatterContext = new FormatterContext(context.startPosition());
    
    List filteredChildren = token.filteredChildren;
    for (Token child : filteredChildren) {
//    if(child.getParser() instanceof NumberCaseExpressionParser) {
      if(child.getParser().hasTag(ExpressionTags.matchCase.tag())) {
        formatterContext.increment();
      }
      if(child.getParser() instanceof RightCurlyBraceParser) {
        formatterContext.decrement();
      }
      render(formatterContext, child);
    }
    context.append(formatterContext.toString());
  }
  
  public static void render(FormatterContext context , Token token) {
    
    Parser parser = token.getParser();
    
    if(parser instanceof IfExpressionParser) {
      renderIf(context, token);
      return;
    }
    
    if(parser.hasTag(ExpressionTags.matchExpression.tag())) {
      renderMatch(context, token);
      return;
    }
    
//    if(parser instanceof NumberCaseExpressionParser) {
    if(parser.hasTag(ExpressionTags.matchCase.tag())) {

      renderCaseExpression(context, token);
      return;
    }
    
    //FIXME! DefaultCaseFactorParser starts ",", to change starts default->
    if(parser.hasTag(ExpressionTags.matchDefaultFactor.tag())) {
      context
        .append("default->");
        render(context, token.filteredChildren.get(3));
        return;
    }
    
    List tokens = new ArrayList<>(token.filteredChildren);
    if(tokens.size() ==0) {
      token.getRangedString().token.ifPresent(context::append);
      return;
    }
      
    tokens.sort(tokenComparator);
    for (Token child: tokens) {
      render(context, child);
    }
     
  }
  
  public static class FormatterContext{
    final String tab="  ";
    
    int tabSize = 2;
    int level = 0;
    Map startPositionByLevel = new HashMap<>();
    Map positionByLevel = new HashMap<>();
    StringBuilder builder = new StringBuilder();
    
    public FormatterContext(int startPosition) {
      super();
      positionByLevel.put(level, startPosition);
      startPositionByLevel.put(level, startPosition);
    }
    
    public FormatterContext append(String text) {
      builder.append(text);
      Integer position = positionByLevel.get(level);
      positionByLevel.put(level, position+text.length());
      return this;
    }
    
    public FormatterContext appendWithSpace(String text) {
      append(text+" ");
      return this;
    }
    
    public FormatterContext increment() {
      n();
      Integer positionByCurrent = startPositionByLevel.get(level);
      level++;
      startPositionByLevel.put(level, positionByCurrent+tabSize);
      positionByLevel.put(level, positionByLevel.get(level-1)+tabSize);
      tab();
      return this;
    }
    
    public FormatterContext decrement() {
      n();
      level--;
      tab();
      return this;
    }
    
    public FormatterContext n() {
      builder.append("\n");
      return this;
    }
    
    public int startPosition() {
      return startPositionByLevel.get(level);
    }
    
    public FormatterContext tab() {
      if(startPosition()==0) {
        return this;
      }
      builder.append(String.format("%"+startPosition()+"s", ""));
      return this;
    }
    
    public String toString() {
      return builder.toString();
    }
    
    public FormatterContext trimLast() {
      builder.deleteCharAt(builder.length()-1);
      return this;
    }
    
    public FormatterContext clear() {
      builder = new StringBuilder();
      return this;
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy