Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Тесты
Исправлена ошибка обработки выражения в скобках
  • Loading branch information
alkoleft committed Nov 11, 2022
1 parent 8c26fd0 commit 63348ed
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,46 @@
class PreprocessorExpressionTreeBuildingVisitor extends BSLParserBaseVisitor<ParseTree> {

private BslExpression resultExpression;
private int recursionLevel = -1;

private final Deque<BslExpression> operands = new ArrayDeque<>();
private final Deque<BslOperator> operators = new ArrayDeque<>();
private final Deque<State> states = new ArrayDeque<>();

BslExpression getExpressionTree() {
return resultExpression;
}

@Override
public ParseTree visitPreproc_expression(BSLParser.Preproc_expressionContext ctx) {
return super.visitPreproc_expression(ctx);
super.visitPreproc_expression(ctx);

return ctx;
}

@Override
public ParseTree visitPreproc_logicalExpression(BSLParser.Preproc_logicalExpressionContext ctx) {
var nestingCount = operators.size();
recursionLevel++;
var addToOperands = recursionLevel > 0;

boolean isRoot = states.isEmpty();
var currentState = new State();
states.push(currentState);

super.visitPreproc_logicalExpression(ctx);

while (nestingCount < operators.size()) {
while (!currentState.operators.isEmpty()) {
buildOperation(ctx);
}

if (!addToOperands) {
resultExpression = operands.pop();
}
states.remove();

recursionLevel--;
if (isRoot) {
resultExpression = currentState.operands.pop();
} else {
getOperands().push(currentState.operands.pop());
}
return ctx;
}

@Override
public ParseTree visitPreproc_logicalOperand(BSLParser.Preproc_logicalOperandContext ctx) {
var operands = getOperands();

if (ctx.preproc_symbol() != null) {
operands.push(new PreprocessorSymbolNode(ctx.preproc_symbol()));
Expand All @@ -54,6 +58,7 @@ public ParseTree visitPreproc_logicalOperand(BSLParser.Preproc_logicalOperandCon
}

if (ctx.PREPROC_NOT_KEYWORD() != null) {
var operators = getOperators();
operators.push(BslOperator.NOT);
buildOperation(ctx);
}
Expand All @@ -72,6 +77,7 @@ public ParseTree visitPreproc_boolOperation(BSLParser.Preproc_boolOperationConte
}

private void processOperation(BslOperator operator, ParseTree ctx) {
var operators = getOperators();
if (operators.isEmpty()) {
operators.push(operator);
return;
Expand All @@ -86,10 +92,12 @@ private void processOperation(BslOperator operator, ParseTree ctx) {
}

private void buildOperation(ParseTree ctx) {
var operators = getOperators();
if (operators.isEmpty()) {
return;
}

var operands = getOperands();
var operator = operators.pop();
if (operator == BslOperator.NOT) {
var operand = operands.pop();
Expand All @@ -102,4 +110,24 @@ private void buildOperation(ParseTree ctx) {
operands.push(binaryOp);
}
}

private Deque<BslExpression> getOperands() {
if (states.isEmpty()) {
throw new IllegalStateException();
}
return states.peek().operands;
}

private Deque<BslOperator> getOperators() {
if (states.isEmpty()) {
throw new IllegalStateException();
}
return states.peek().operators;
}

private static class State {
private final Deque<BslExpression> operands = new ArrayDeque<>();
private final Deque<BslOperator> operators = new ArrayDeque<>();

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.utils;

import com.github._1c_syntax.bsl.languageserver.cfg.PreprocessorConstraints;
import com.github._1c_syntax.bsl.languageserver.util.TestUtils;
import com.github._1c_syntax.bsl.languageserver.utils.expressiontree.BinaryOperationNode;
import com.github._1c_syntax.bsl.languageserver.utils.expressiontree.BslExpression;
Expand All @@ -30,12 +31,15 @@
import com.github._1c_syntax.bsl.languageserver.utils.expressiontree.ExpressionNodeType;
import com.github._1c_syntax.bsl.languageserver.utils.expressiontree.ExpressionParseTreeRewriter;
import com.github._1c_syntax.bsl.languageserver.utils.expressiontree.MethodCallNode;
import com.github._1c_syntax.bsl.languageserver.utils.expressiontree.PreprocessorSymbolNode;
import com.github._1c_syntax.bsl.languageserver.utils.expressiontree.SkippedCallArgumentNode;
import com.github._1c_syntax.bsl.languageserver.utils.expressiontree.UnaryOperationNode;
import com.github._1c_syntax.bsl.parser.BSLParser;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Map;

import static org.assertj.core.api.Assertions.as;
import static org.assertj.core.api.Assertions.assertThat;

Expand Down Expand Up @@ -317,6 +321,127 @@ void realLifeHardExpression() {
assertThat(binary.getRight().<BinaryOperationNode>cast().getOperator()).isEqualTo(BslOperator.EQUAL);
}

@Test
void preprocessorUno() {
var variants = Map.ofEntries(
Map.entry("Клиент", PreprocessorConstraints.CLIENT),
Map.entry("Client", PreprocessorConstraints.CLIENT),
Map.entry("НаКлиенте", PreprocessorConstraints.CLIENT),
Map.entry("AtClient", PreprocessorConstraints.CLIENT),
Map.entry("НаСервере", PreprocessorConstraints.SERVER),
Map.entry("AtServer", PreprocessorConstraints.SERVER),
Map.entry("Сервер", PreprocessorConstraints.SERVER),
Map.entry("Server", PreprocessorConstraints.SERVER),
Map.entry("ТонкийКлиент", PreprocessorConstraints.THIN_CLIENT),
Map.entry("ThinClient", PreprocessorConstraints.THIN_CLIENT),
Map.entry("ВебКлиент", PreprocessorConstraints.WEB_CLIENT),
Map.entry("WebClient", PreprocessorConstraints.WEB_CLIENT),
Map.entry("МобильныйАвтономныйСервер", PreprocessorConstraints.MOBILE_STANDALONE_SERVER),
Map.entry("MobileStandaloneServer", PreprocessorConstraints.MOBILE_STANDALONE_SERVER),
Map.entry("МобильноеПриложениеКлиент", PreprocessorConstraints.MOBILE_APP_CLIENT),
Map.entry("MobileAppClient", PreprocessorConstraints.MOBILE_APP_CLIENT),
Map.entry("МобильноеПриложениеСервер", PreprocessorConstraints.MOBILE_APP_SERVER),
Map.entry("MobileAppServer", PreprocessorConstraints.MOBILE_APP_SERVER),
Map.entry("МобильныйКлиент", PreprocessorConstraints.MOBILE_CLIENT),
Map.entry("MobileClient", PreprocessorConstraints.MOBILE_CLIENT),
Map.entry("ТолстыйКлиентОбычноеПриложение", PreprocessorConstraints.ORDINARY_THICK_CLIENT),
Map.entry("ThickClientOrdinaryApplication", PreprocessorConstraints.ORDINARY_THICK_CLIENT),
Map.entry("ТолстыйКлиентУправляемоеПриложение", PreprocessorConstraints.MANAGED_THICK_CLIENT),
Map.entry("ThickClientManagedApplication", PreprocessorConstraints.MANAGED_THICK_CLIENT),
Map.entry("ВнешнееСоединение", PreprocessorConstraints.EXTERNAL_CONNECTION),
Map.entry("ExternalConnection", PreprocessorConstraints.EXTERNAL_CONNECTION));

for (var variant : variants.entrySet()) {
var expression = getPreprocessorExpressionTree(variant.getKey());
assertThat(expression).isInstanceOf(PreprocessorSymbolNode.class);
assertThat(((PreprocessorSymbolNode) expression).getSymbol()).isEqualTo(variant.getValue());
}
}

@Test
void preprocessorNot() {
var variants = Map.of(
"Not Клиент", PreprocessorConstraints.CLIENT,
"Не Server", PreprocessorConstraints.SERVER
);

for (var variant : variants.entrySet()) {
var expression = getPreprocessorExpressionTree(variant.getKey());
assertThat(expression).isInstanceOf(UnaryOperationNode.class);
var operation = (UnaryOperationNode) expression;
assertThat(operation.getOperator()).isEqualTo(BslOperator.NOT);
assertThat(operation.getOperand()).isInstanceOf(PreprocessorSymbolNode.class);
assertThat(((PreprocessorSymbolNode) operation.getOperand()).getSymbol()).isEqualTo(variant.getValue());
}
}

@Test
void preprocessorAND() {
var expression = getPreprocessorExpressionTree("Сервер И Клиент");
assertThat(expression).isInstanceOf(BinaryOperationNode.class);
var operation = (BinaryOperationNode) expression;
assertThat(operation.getOperator()).isEqualTo(BslOperator.AND);
assertThat(operation.getLeft())
.isInstanceOf(PreprocessorSymbolNode.class)
.extracting("symbol").isEqualTo(PreprocessorConstraints.SERVER)
;
assertThat(operation.getRight())
.isInstanceOf(PreprocessorSymbolNode.class)
.extracting("symbol").isEqualTo(PreprocessorConstraints.CLIENT)
;
expression = getPreprocessorExpressionTree("НЕ Сервер И Клиент");
assertThat(expression)
.extracting("left").isInstanceOf(UnaryOperationNode.class)
.extracting("operand")
.isInstanceOf(PreprocessorSymbolNode.class)
.extracting("symbol").isEqualTo(PreprocessorConstraints.SERVER)
;
expression = getPreprocessorExpressionTree("Клиент AND Server AND MobileAppClient");
operation = (BinaryOperationNode) expression;
assertThat(operation.getLeft()).isInstanceOf(PreprocessorSymbolNode.class)
.extracting("symbol").isEqualTo(PreprocessorConstraints.CLIENT);
assertThat(operation.getRight()).isInstanceOf(BinaryOperationNode.class);
}

@Test
void preprocessorOR() {
var expression = getPreprocessorExpressionTree("Сервер ИЛИ Клиент");
assertThat(expression).isInstanceOf(BinaryOperationNode.class);
var operation = (BinaryOperationNode) expression;
assertThat(operation.getOperator()).isEqualTo(BslOperator.OR);
assertThat(operation.getLeft())
.isInstanceOf(PreprocessorSymbolNode.class)
.extracting("symbol").isEqualTo(PreprocessorConstraints.SERVER)
;
expression = getPreprocessorExpressionTree("Клиент OR Server OR MobileAppClient");
operation = (BinaryOperationNode) expression;
assertThat(operation.getLeft()).isInstanceOf(PreprocessorSymbolNode.class)
.extracting("symbol").isEqualTo(PreprocessorConstraints.CLIENT);
assertThat(operation.getRight()).isInstanceOf(BinaryOperationNode.class);
}

@Test
void preprocessorComplex() {
var expression = getPreprocessorExpressionTree("Client AND Not MobileClient OR Server И (ExternalConnection ИЛИ Клиент)");
var operation = (BinaryOperationNode) expression;
assertThat(operation.getOperator()).isEqualTo(BslOperator.OR);
assertThat(operation.getLeft())
.extracting("left.symbol", "operator", "right.operator", "right.operand.symbol")
.containsExactly(PreprocessorConstraints.CLIENT, BslOperator.AND, BslOperator.NOT, PreprocessorConstraints.MOBILE_CLIENT)
;
assertThat(operation.getRight())
.extracting("left.symbol", "operator", "right.left.symbol", "right.operator", "right.right.symbol")
.containsExactly(PreprocessorConstraints.SERVER, BslOperator.AND, PreprocessorConstraints.EXTERNAL_CONNECTION, BslOperator.OR, PreprocessorConstraints.CLIENT)
;
}

BslExpression getPreprocessorExpressionTree(String code) {
var preprocessorPredicate = String.format("#Если %s Тогда\n#КонецЕсли", code);
var dContext = TestUtils.getDocumentContext(preprocessorPredicate);
var expression = dContext.getAst().preprocessor(0).preproc_if().preproc_expression();
return ExpressionParseTreeRewriter.buildExpressionTree(expression);
}

BslExpression getExpressionTree(String code) {
var expression = parse(code);
return ExpressionParseTreeRewriter.buildExpressionTree(expression);
Expand Down

0 comments on commit 63348ed

Please sign in to comment.