| /*=============================================================================# |
| # Copyright (c) 2020 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.r.core.rsource.ast; |
| |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| |
| import java.util.List; |
| |
| import org.junit.jupiter.api.Test; |
| import org.junit.jupiter.params.ParameterizedTest; |
| import org.junit.jupiter.params.provider.MethodSource; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.lang.NonNullByDefault; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| import org.eclipse.statet.jcommons.text.core.input.StringParserInput; |
| |
| import org.eclipse.statet.ltk.model.core.ModelManager; |
| import org.eclipse.statet.r.core.rlang.RTerminal; |
| |
| |
| @NonNullByDefault |
| public class RScannerBasicTest { |
| |
| |
| public static class NodeDescr { |
| |
| final NodeType type; |
| |
| final @Nullable RTerminal op0; |
| |
| public NodeDescr(final NodeType type, final @Nullable RTerminal op) { |
| this.type= type; |
| this.op0= op; |
| } |
| |
| @Override |
| public String toString() { |
| return this.type + " ยป " + ((this.op0 != null) ? this.op0.name() : ""); |
| } |
| |
| } |
| |
| static final NodeDescr SYMBOL= new NodeDescr(NodeType.SYMBOL, null); |
| |
| static final NodeDescr MULT_MULT= new NodeDescr(NodeType.MULT, RTerminal.MULT); |
| static final NodeDescr MULT_DIV= new NodeDescr(NodeType.MULT, RTerminal.DIV); |
| static final NodeDescr ADD_PLUS= new NodeDescr(NodeType.ADD, RTerminal.PLUS); |
| static final NodeDescr ADD_MINUS= new NodeDescr(NodeType.ADD, RTerminal.MINUS); |
| |
| static List<NodeDescr> commonOps() { |
| return ImCollections.newList( |
| ADD_PLUS, ADD_MINUS, |
| MULT_MULT, MULT_DIV ); |
| } |
| |
| static final NodeDescr HELP_QUESTIONMARK= new NodeDescr(NodeType.HELP, RTerminal.QUESTIONMARK); |
| |
| static final NodeDescr ASSIGN_LEFT_S= new NodeDescr(NodeType.A_LEFT, RTerminal.ARROW_LEFT_S); |
| static final NodeDescr ASSIGN_LEFT_D= new NodeDescr(NodeType.A_LEFT, RTerminal.ARROW_LEFT_D); |
| static final NodeDescr ASSIGN_RIGHT_S= new NodeDescr(NodeType.A_RIGHT, RTerminal.ARROW_RIGHT_S); |
| static final NodeDescr ASSIGN_RIGHT_D= new NodeDescr(NodeType.A_RIGHT, RTerminal.ARROW_RIGHT_D); |
| static final NodeDescr ASSIGN_EQUALS= new NodeDescr(NodeType.A_EQUALS, RTerminal.EQUAL); |
| |
| static List<NodeDescr> assignOps() { |
| return ImCollections.newList( |
| ASSIGN_LEFT_S, ASSIGN_LEFT_D, |
| ASSIGN_RIGHT_S, ASSIGN_RIGHT_S, |
| ASSIGN_EQUALS ); |
| } |
| |
| |
| private final RScanner scanner= new RScanner(ModelManager.MODEL_FILE); |
| |
| private final StringParserInput input= new StringParserInput(); |
| |
| |
| public RScannerBasicTest() { |
| } |
| |
| |
| @Test |
| public void ADD() { |
| RAstNode expr0; |
| |
| expr0= assertExpr("x + y", 0, 5, ADD_PLUS); |
| assertNode(expr0, new int[] { 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 4, 5, SYMBOL); |
| |
| expr0= assertExpr("x - y", 0, 5, ADD_MINUS); |
| assertNode(expr0, new int[] { 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 4, 5, SYMBOL); |
| |
| expr0= assertExpr("x + y + z", 0, 9, ADD_PLUS); |
| assertNode(expr0, new int[] { 0 }, 0, 5, ADD_PLUS); |
| assertNode(expr0, new int[] { 0, 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 0, 1 }, 4, 5, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 8, 9, SYMBOL); |
| |
| expr0= assertExpr("x + y - z", 0, 9, ADD_MINUS); |
| assertNode(expr0, new int[] { 0 }, 0, 5, ADD_PLUS); |
| assertNode(expr0, new int[] { 0, 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 0, 1 }, 4, 5, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 8, 9, SYMBOL); |
| |
| expr0= assertExpr("x - y - z", 0, 9, ADD_MINUS); |
| assertNode(expr0, new int[] { 0 }, 0, 5, ADD_MINUS); |
| assertNode(expr0, new int[] { 0, 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 0, 1 }, 4, 5, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 8, 9, SYMBOL); |
| |
| expr0= assertExpr("x - y + z", 0, 9, ADD_PLUS); |
| assertNode(expr0, new int[] { 0 }, 0, 5, ADD_MINUS); |
| assertNode(expr0, new int[] { 0, 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 0, 1 }, 4, 5, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 8, 9, SYMBOL); |
| |
| assertTwoOps_differentPrio(ADD_PLUS, MULT_MULT); |
| assertTwoOps_differentPrio(ADD_PLUS, MULT_DIV); |
| assertTwoOps_differentPrio(ADD_MINUS, MULT_MULT); |
| assertTwoOps_differentPrio(ADD_MINUS, MULT_DIV); |
| } |
| |
| @Test |
| public void HELP() { |
| RAstNode expr0; |
| |
| expr0= assertExpr("? y", 0, 3, HELP_QUESTIONMARK); |
| assertEquals(1, expr0.getChildCount()); |
| assertNode(expr0, new int[] { 0 }, 2, 3, SYMBOL); |
| |
| expr0= assertExpr("? y + z", 0, 7, HELP_QUESTIONMARK); |
| assertEquals(1, expr0.getChildCount()); |
| assertNode(expr0, new int[] { 0 }, 2, 7, ADD_PLUS); |
| assertNode(expr0, new int[] { 0, 0 }, 2, 3, SYMBOL); |
| assertNode(expr0, new int[] { 0, 1 }, 6, 7, SYMBOL); |
| |
| expr0= assertExpr("x ? y", 0, 5, HELP_QUESTIONMARK); |
| assertEquals(2, expr0.getChildCount()); |
| assertNode(expr0, new int[] { 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 4, 5, SYMBOL); |
| } |
| |
| @ParameterizedTest |
| @MethodSource("commonOps") |
| public void HELP_commonOps(final NodeDescr opDescr) { |
| assertTwoOps_differentPrio(HELP_QUESTIONMARK, opDescr); |
| } |
| |
| @ParameterizedTest |
| @MethodSource("assignOps") |
| public void HELP_assignOps(final NodeDescr opDescr) { |
| assertTwoOps_differentPrio(HELP_QUESTIONMARK, opDescr); |
| } |
| |
| @ParameterizedTest |
| @MethodSource("commonOps") |
| public void ASSIGN_commonOps(final NodeDescr opDescr) { |
| assertTwoOps_differentPrio(ASSIGN_LEFT_S, opDescr); |
| assertTwoOps_differentPrio(ASSIGN_LEFT_D, opDescr); |
| assertTwoOps_differentPrio(ASSIGN_RIGHT_S, opDescr); |
| assertTwoOps_differentPrio(ASSIGN_RIGHT_D, opDescr); |
| assertTwoOps_differentPrio(ASSIGN_EQUALS, opDescr); |
| } |
| |
| |
| private void assertNode(final RAstNode node, final String nodeLabel, |
| final int startOffset, final int endOffset, |
| final NodeDescr nodeDescr) { |
| assertEquals(nodeDescr.type, node.getNodeType(), nodeLabel + ".nodeType"); |
| assertEquals(startOffset, node.getStartOffset(), nodeLabel + ".startOffset"); |
| assertEquals(endOffset, node.getEndOffset(), nodeLabel + ".endOffset"); |
| assertEquals(nodeDescr.op0, node.getOperator(0), nodeLabel + ".operator[0]"); |
| } |
| |
| private RAstNode assertExpr(final String code, |
| final int startOffset, final int endOffset, |
| final NodeDescr node0Descr) { |
| final SourceComponent root= this.scanner.scanSourceRange(this.input.reset(code).init(), |
| null, false ); |
| assertEquals(1, root.getChildCount()); |
| assertEquals(startOffset, root.getStartOffset(), "root.startOffset"); |
| assertEquals(endOffset, root.getEndOffset(), "root.endOffset"); |
| |
| final RAstNode expr0= root.getChild(0); |
| assertNode(expr0, "expr[0]", startOffset, endOffset, node0Descr); |
| return expr0; |
| } |
| |
| private void assertTwoOps_differentPrio(final NodeDescr lowDescr, final NodeDescr highDescr) { |
| RAstNode expr0; |
| final String ls= lowDescr.op0.text; |
| final int ll= lowDescr.op0.text.length(); |
| final String hs= highDescr.op0.text; |
| final int hl= highDescr.op0.text.length(); |
| |
| expr0= assertExpr("r " + ls + " x " + hs + " y", |
| 0, 7 + ll + hl, lowDescr); |
| assertNode(expr0, new int[] { 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 3 + ll, 7 + ll + hl, highDescr); |
| assertNode(expr0, new int[] { 1, 0 }, 3 + ll, 4 + ll, SYMBOL); |
| assertNode(expr0, new int[] { 1, 1 }, 6 + ll + hl, 7 + ll + hl, SYMBOL); |
| |
| expr0= assertExpr("r " + ls + " x " + hs + " y[z]", |
| 0, 10 + ll + hl, lowDescr); |
| assertNode(expr0, new int[] { 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 3 + ll, 10 + ll + hl, highDescr); |
| |
| expr0= assertExpr("r " + ls + " x[y] " + hs + " z", |
| 0, 10 + ll + hl, lowDescr); |
| assertNode(expr0, new int[] { 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 3 + ll, 10 + ll + hl, highDescr); |
| |
| expr0= assertExpr("r " + hs + " s " + ls + " x", |
| 0, 7 + hl + ll, lowDescr); |
| assertNode(expr0, new int[] { 0 }, 0, 4 + hl, highDescr); |
| assertNode(expr0, new int[] { 0, 0 }, 0, 1, SYMBOL); |
| assertNode(expr0, new int[] { 0, 1 }, 3 + hl, 4 + hl, SYMBOL); |
| assertNode(expr0, new int[] { 1 }, 6 + hl + ll, 7 + hl + ll, SYMBOL); |
| |
| expr0= assertExpr("r " + hs + " s[t] " + ls + " x", |
| 0, 10 + hl + ll, lowDescr); |
| assertNode(expr0, new int[] { 0 }, 0, 7 + hl, highDescr); |
| assertNode(expr0, new int[] { 1 }, 9 + hl + ll, 10 + hl + ll, SYMBOL); |
| } |
| |
| private void assertNode(final RAstNode expr0, final int[] nodeIndex, |
| final int startOffset, final int endOffset, |
| final NodeDescr nodeDescr) { |
| RAstNode node= expr0; |
| final StringBuilder sb= new StringBuilder("expr[0]"); |
| for (int i= 0; i < nodeIndex.length; i++) { |
| node= node.getChild(nodeIndex[i]); |
| sb.append('['); |
| sb.append(nodeIndex[i]); |
| sb.append(']'); |
| } |
| assertNode(node, sb.toString(), startOffset, endOffset, nodeDescr); |
| } |
| |
| } |