Package dtool.parser

Source Code of dtool.parser.DeeParsingChecks

/*******************************************************************************
* Copyright (c) 2013, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Bruno Medeiros - initial API and implementation
*******************************************************************************/
package dtool.parser;

import static melnorme.utilbox.core.Assert.AssertNamespace.assertFail;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import static melnorme.utilbox.core.CoreUtil.areEqual;

import java.util.ArrayList;

import melnorme.utilbox.tests.CommonTestUtils;
import dtool.ast.ASTNode;
import dtool.ast.ASTNodeTypes;
import dtool.ast.ASTVisitor;
import dtool.ast.IASTNode;
import dtool.ast.definitions.IFunctionParameter;
import dtool.ast.definitions.TemplateParameter;
import dtool.ast.util.ASTSourceRangeChecker;
import dtool.parser.DeeParser_Parameters.AmbiguousParameter;
import dtool.parser.DeeParser_Parameters.TplOrFnMode;
import dtool.parser.ParserError.ParserErrorTypes;

/**
* Various checks for invariants in node parsing.
* These don't require additional test specification to check against.
*/
public class DeeParsingChecks extends CommonTestUtils {
 
  public static class DeeTestsChecksParser extends DeeParser {
   
    public DeeTestsChecksParser(String source) {
      super(new DeeLexer(source));
    }
   
    @Override
    protected void nodeConcluded(ASTNode node) {
      assertTrue(node.isParsedStatus());
      checkNodeSourceRange(node, getSource());
     
      node.accept(new ASTSwitchVisitorTester()); // Test ASTSwitchVisitor
     
      // Run additional tests on the node just parsed
      // These might include node/rule specific tests
      runNodeParsingChecks(node, getSource());
    }
   
  }
 
  public static void checkNodeSourceRange(ASTNode node, final String fullSource) {
    assertTrue(node.hasSourceRangeInfo());
    assertTrue(node.getStartPos() <= fullSource.length() && node.getEndPos() <= fullSource.length());
   
    // Check consistency of source ranges (no overlapping ranges)
    new ASTSourceRangeChecker(node) {
      @Override
      public boolean visitChildrenAfterPreVisitOk() {
        return depth < 2;
      }
     
      @Override
      protected void handleSourceRangeStartPosBreach(ASTNode elem) {
        //String nodeStr = NodeUtil.getSubString(fullSource, elem.getSourceRange());
        //String parentStr = NodeUtil.getSubString(fullSource, elem.getParent().getSourceRange());
        assertFail();
      }
    };
  }
 
  public static final DeeTokens[] structuralControlTokens = array(
    DeeTokens.OPEN_PARENS, DeeTokens.CLOSE_PARENS,
    DeeTokens.OPEN_BRACE, DeeTokens.CLOSE_BRACE,
    DeeTokens.OPEN_BRACKET, DeeTokens.CLOSE_BRACKET,
    DeeTokens.COLON,
    DeeTokens.SEMICOLON
  );
 
  public static void runNodeParsingChecks(ASTNode node, final String fullSource) {
    String nodeSnippedSource = fullSource.substring(node.getStartPos(), node.getEndPos());
    if(!areThereMissingTokenErrorsInNode(node)) {
      SourceEquivalenceChecker.assertCheck(nodeSnippedSource, node.toStringAsCode());
    } else {
      SourceEquivalenceChecker.assertCheck(nodeSnippedSource, node.toStringAsCode(), structuralControlTokens);
    }
   
    DeeParsingSourceRangeChecks.runParsingSourceRangeChecks(node, fullSource);
  }
 
  protected static boolean areThereMissingTokenErrorsInNode(ASTNode node) {
    CheckForMissingTokenErrors visitor = new CheckForMissingTokenErrors();
    node.accept(visitor);
    return visitor.hasMissingTokenErrors;
  }
 
  protected static final class CheckForMissingTokenErrors extends ASTVisitor {
    public boolean hasMissingTokenErrors = false;
   
    @Override
    public boolean preVisit(ASTNode node) {
      for (ParserError error : node.getData().getNodeErrors()) {
        if(error.errorType == ParserErrorTypes.INVALID_EXTERN_ID ||
          (error.errorType == ParserErrorTypes.EXPECTED_TOKEN && error.msgData != DeeTokens.IDENTIFIER)) {
          hasMissingTokenErrors = true;
          return DONT_VISIT_CHILDREN;
        }
      }
      return VISIT_CHILDREN;
    }
  }
 
  public static void checkNodeEquality(ASTNode reparsedNode, ASTNode node) {
    // We check the nodes are semantically equal by comparing the toStringAsCode
    // TODO: use a more accurate equals method?
    assertEquals(reparsedNode.getClass(), node.getClass());
    assertEquals(reparsedNode.toStringAsCode(), node.toStringAsCode());
    assertEquals(reparsedNode.isParsedStatus(), node.isParsedStatus());
    if(reparsedNode.isParsedStatus()) {
      assertTrue(areEqual(collectNodeErrors(reparsedNode), collectNodeErrors(node)));
    }
  }
 
  public static ArrayList<ParserError> collectNodeErrors(ASTNode node) {
    assertNotNull(node);
    return DeeParser.collectErrors(new ArrayList<ParserError>(), node);
  }
 
  public static class DeeParsingNodeCheck {
   
    protected final String fullSource;
    protected final ASTNode nodeUnderTest;
    protected final String nodeSnippedSource;
   
    public DeeParsingNodeCheck(String source, ASTNode node) {
      this.fullSource = assertNotNull(source);
      this.nodeUnderTest = assertNotNull(node);
      this.nodeSnippedSource = fullSource.substring(nodeUnderTest.getStartPos(), nodeUnderTest.getEndPos());
      assertTrue(nodeUnderTest.getNodeType() != ASTNodeTypes.NULL);
    }
  }
 
  /* ------------------------------------- */
 
  public static class ParametersReparseCheck {
   
    public static Object parseAmbigParameter(String nodeSnippedSource) {
      DeeParser deeParser = new DeeParser(nodeSnippedSource);
      return deeParser.new DeeParser_RuleParameters(TplOrFnMode.AMBIG).parseParameter();
    }
   
    public static void ambigParameterReparseTest(String nodeSource) {
      paramReparseCheck(nodeSource, true);
      paramReparseCheck(nodeSource, false);
    }
   
    public static void paramReparseCheck(String nodeSource, boolean reparseAsFunctionParam) {
      DeeParser unambigParser = new DeeParser(nodeSource);
      IASTNode unambigParsedParameter = reparseAsFunctionParam ?
        unambigParser.parseFunctionParameter() : unambigParser.parseTemplateParameter();
       
      Object ambigParsedParameterResult = parseAmbigParameter(nodeSource);
     
      ASTNode nodeToCompareAgainst = null;
      if(ambigParsedParameterResult instanceof IFunctionParameter) {
        nodeToCompareAgainst = reparseAsFunctionParam ? (ASTNode) ambigParsedParameterResult : null;
      } else if(ambigParsedParameterResult instanceof TemplateParameter) {
        nodeToCompareAgainst = !reparseAsFunctionParam ? (ASTNode) ambigParsedParameterResult : null;
      } else {
        AmbiguousParameter ambigParsedParameter = (AmbiguousParameter) ambigParsedParameterResult;
        nodeToCompareAgainst = reparseAsFunctionParam ?
          ambigParsedParameter.convertToFunction().asNode() : ambigParsedParameter.convertToTemplate();
      }
     
      if(nodeToCompareAgainst != null) {
        assertTrue(unambigParser.lookAhead() == DeeTokens.EOF);
        DeeParsingChecks.checkNodeEquality(unambigParsedParameter.asNode(), nodeToCompareAgainst);
      } else {
        assertTrue(unambigParser.lookAhead() != DeeTokens.EOF ||
          collectNodeErrors(unambigParsedParameter.asNode()).size() > 0);
      }
    }
   
  }
 
  /* ------------------------------------- */
 
  public static DeeParserResult runSimpleSourceParseTest(String source, String defaultModuleName,
      Boolean expectErrors, boolean runBasicContractChecks) {
   
    DeeParserResult parseResult = runBasicContractChecks ?
      new DeeTestsChecksParser(source).parseModuleSource(defaultModuleName, null) :
      new DeeParser(source).parseModuleSource(defaultModuleName, null);
   
    if(expectErrors != null) {
      assertTrue(parseResult.hasSyntaxErrors() == expectErrors, "expectedErrors is not: " + expectErrors);
//      source.substring(parseResult.errors.get(0).getStartPos() - 30);
//      source.substring(parseResult.errors.get(0).getStartPos());
    }
   
    return parseResult;
  }
 
}
TOP

Related Classes of dtool.parser.DeeParsingChecks

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.