Package com.intellij.plugins.haxe.lang.lexer

Source Code of com.intellij.plugins.haxe.lang.lexer.HaxeLexer$CalculationException

/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2014-2014 AS3Boyan
* Copyright 2014-2014 Elias Ku
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.plugins.haxe.lang.lexer;

import com.intellij.lexer.Lexer;
import com.intellij.lexer.LexerPosition;
import com.intellij.lexer.LookAheadLexer;
import com.intellij.lexer.MergingLexerAdapter;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.plugins.haxe.config.HaxeProjectSettings;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import gnu.trove.THashSet;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Set;

import static com.intellij.plugins.haxe.lang.lexer.HaxeTokenTypeSets.*;
import static com.intellij.plugins.haxe.lang.lexer.HaxeTokenTypes.*;

public class HaxeLexer extends LookAheadLexer {
  public static Key<Object> DEFINES_KEY = Key.create("haxe.test.defines");
  private static final TokenSet tokensToMerge = TokenSet.create(
    MSL_COMMENT,
    MML_COMMENT,
    WSNLS
  );

  private final static Set<String> SDK_DEFINES = new THashSet<String>(Arrays.asList(
    "macro"
  ));

  @Nullable
  private Project myProject;

  public HaxeLexer(Project project) {
    super(new MergingLexerAdapter(new HaxeFlexLexer(), tokensToMerge));
    myProject = project;
  }

  @Override
  protected void lookAhead(Lexer baseLexer) {
    if (baseLexer.getTokenType() == PPERROR) {
      final LexerPosition position = baseLexer.getCurrentPosition();
      baseLexer.advance();
      while (HaxeTokenTypeSets.WHITESPACES.contains(baseLexer.getTokenType()) ||
             HaxeTokenTypeSets.COMMENTS.contains(baseLexer.getTokenType())) {
        baseLexer.advance();
      }
      if (HaxeTokenTypeSets.STRINGS.contains(baseLexer.getTokenType())) {
        while (HaxeTokenTypeSets.STRINGS.contains(baseLexer.getTokenType())) {
          baseLexer.advance();
        }
      }
      else {
        baseLexer.restore(position);
      }
      advanceAs(baseLexer, PPERROR);
    }

    /*else if (baseLexer.getTokenType() == PPIF || baseLexer.getTokenType() == PPELSEIF) {
      advanceAs(baseLexer, PPIF);
      while (!lookAheadExpressionIsTrue(baseLexer)) {
        IElementType elementType = eatUntil(baseLexer, PPEND, PPELSE, PPELSEIF);
        if (elementType == PPELSEIF) {
          advanceAs(baseLexer, PPBODY);
          continue;
        }
        advanceAs(baseLexer, PPBODY);
        break;
      }
    }*/
    /*else if (baseLexer.getTokenType() == PPELSE) {
      eatUntil(baseLexer, PPEND);
      advanceAs(baseLexer, PPELSE);
    }*/
    else {
      super.lookAhead(baseLexer);
    }
  }

  @Nullable
  protected static IElementType eatUntil(Lexer baseLexer, IElementType... types) {
    final Set<IElementType> typeSet = new THashSet<IElementType>(Arrays.asList(types));
    IElementType type = null;
    int counter = 0;
    do {
      baseLexer.advance();
      type = baseLexer.getTokenType();
      /*if (type == PPIF) {
        ++counter;
      }
      if (counter > 0 && type == PPEND) {
        --counter;
        baseLexer.advance();
        type = baseLexer.getTokenType();
      }*/

      if (type == PPIF || type == PPEND) {
        baseLexer.advance();
        type = baseLexer.getTokenType();
      }
    }
    while (type != null && (!typeSet.contains(type) || counter > 0));
    return type;
  }

  protected boolean lookAheadExpressionIsTrue(Lexer baseLexer) {
    IElementType type = null;
    // reverse polish notation
    final LinkedList<IElementType> stack = new LinkedList<IElementType>();
    final LinkedList<String> rpn = new LinkedList<String>();
    final int expressionStartPosition = baseLexer.getTokenStart();
    do {
      final LexerPosition position = baseLexer.getCurrentPosition();
      type = baseLexer.getTokenType();
      while (HaxeTokenTypeSets.WHITESPACES.contains(type) || HaxeTokenTypeSets.ONLY_COMMENTS.contains(type)) {
        baseLexer.advance();
        type = baseLexer.getTokenType();
      }
      final String tokenText = baseLexer.getTokenText();
      if (type == ID) {
        if (canCalculate(rpn, stack)) {
          //revert
          baseLexer.restore(position);
          break;
        }
        rpn.addFirst(tokenText);
      }
      else if (type == PRPAREN) {
        do {
          IElementType typeOnStack = stack.pollLast();
          if (typeOnStack == PLPAREN) {
            break;
          }
          rpn.addFirst(typeOnStack.toString());
        }
        while (!stack.isEmpty());
        while (!stack.isEmpty() && stack.getLast() == ONOT) {
          rpn.addFirst(stack.pollLast().toString());
        }
      }
      else if (type == OCOND_AND || type == OCOND_OR) {
        while (!stack.isEmpty() && (stack.getLast() == OCOND_AND || stack.getLast() == OCOND_OR)) {
          rpn.addFirst(stack.pollLast().toString());
        }
        stack.add(type);
      }
      else if (type == ONOT || type == PLPAREN) {
        stack.add(type);
      }
      else {
        baseLexer.restore(position);
        break;
      }
    }
    while (advanceAndContinue(baseLexer));
    // not empty token
    if (expressionStartPosition != baseLexer.getTokenStart()) {
      addToken(PPEXPRESSION);
    }
    try {
      return calculate(rpn, stack);
    }
    catch (CalculationException e) {
      return false;
    }
  }

  private static boolean advanceAndContinue(Lexer baseLexer) {
    baseLexer.advance();
    return true;
  }

  private boolean canCalculate(LinkedList<String> rpn, LinkedList<IElementType> stack) {
    try {
      calculate(rpn, stack);
      return true;
    }
    catch (CalculationException e) {
      return false;
    }
  }

  private boolean calculate(LinkedList<String> rpn, LinkedList<IElementType> stack) throws CalculationException {
    final LinkedList<String> list = new LinkedList<String>();
    for (IElementType type : stack) {
      if (type == PLPAREN) {
        throw new CalculationException("Balance error");
      }
      list.add(type.toString());
    }
    Collections.reverse(list);
    list.addAll(rpn);
    return calculateImpl(list);
  }

  private boolean calculateImpl(LinkedList<String> list) throws CalculationException {
    if (list.isEmpty()) {
      throw new CalculationException("Incorrect expression");
    }
    final String token = list.pollFirst();
    if ("!".equals(token)) {
      return !calculateImpl(list);
    }
    else if ("&&".equals(token)) {
      boolean a = calculateImpl(list);
      boolean b = calculateImpl(list);
      return a && b;
    }
    else if ("||".equals(token)) {
      boolean a = calculateImpl(list);
      boolean b = calculateImpl(list);
      return a || b;
    }
    else {
      return isDefined(token);
    }
  }

  protected boolean isDefined(String name) {
    if (name == null) {
      return false;
    }
    if (myProject == null) {
      return SDK_DEFINES.contains(name);
    }
    String[] definitions = null;
    if (ApplicationManager.getApplication().isUnitTestMode()) {
      final Object userData = myProject.getUserData(DEFINES_KEY);
      if (userData instanceof String) {
        definitions = ((String)userData).split(",");
      }
    }
    else {
      definitions = HaxeProjectSettings.getInstance(myProject).getUserCompilerDefinitions();
    }
    return definitions != null && Arrays.asList(definitions).contains(name);
  }

  private static class CalculationException extends Exception {
    private CalculationException(String message) {
      super(message);
    }
  }
}
TOP

Related Classes of com.intellij.plugins.haxe.lang.lexer.HaxeLexer$CalculationException

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.