blob: 7c7de97372245b57e313e5640aef390444b9f156 [file] [log] [blame]
/*
* Copyright (c) 2013, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
*
* 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.google.dart.engine.parser;
import com.google.dart.engine.EngineTestCase;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.error.GatheringErrorListener;
import com.google.dart.engine.scanner.CharSequenceReader;
import com.google.dart.engine.scanner.IncrementalScanner;
import com.google.dart.engine.scanner.Scanner;
import com.google.dart.engine.scanner.Token;
import com.google.dart.engine.source.Source;
import com.google.dart.engine.source.TestSource;
import com.google.dart.engine.utilities.ast.AstComparator;
public class IncrementalParserTest extends EngineTestCase {
public void fail_replace_identifier_with_functionLiteral_in_initializer() {
// Function literals aren't allowed inside initializers; incremental parsing needs to gather
// the appropriate context.
//
// "class A { var a; A(b) : a = b ? b : 0 { } }"
// "class A { var a; A(b) : a = b ? () {} : 0 { } }"
assertParse("class A { var a; A(b) : a = b ? ", "b", "() {}", " : 0 { } }");
}
public void test_delete_everything() {
// "f() => a + b;"
// ""
assertParse("", "f() => a + b;", "", "");
}
public void test_delete_identifier_beginning() {
// "f() => abs + b;"
// "f() => s + b;"
assertParse("f() => ", "ab", "", "s + b;");
}
public void test_delete_identifier_end() {
// "f() => abs + b;"
// "f() => a + b;"
assertParse("f() => a", "bs", "", " + b;");
}
public void test_delete_identifier_middle() {
// "f() => abs + b;"
// "f() => as + b;"
assertParse("f() => a", "b", "", "s + b;");
}
public void test_delete_mergeTokens() {
// "f() => a + b + c;"
// "f() => ac;"
assertParse("f() => a", " + b + ", "", "c;");
}
public void test_insert_afterIdentifier1() {
// "f() => a + b;"
// "f() => abs + b;"
assertParse("f() => a", "", "bs", " + b;");
}
public void test_insert_afterIdentifier2() {
// "f() => a + b;"
// "f() => a + bar;"
assertParse("f() => a + b", "", "ar", ";");
}
public void test_insert_beforeIdentifier1() {
// "f() => a + b;"
// "f() => xa + b;"
assertParse("f() => ", "", "x", "a + b;");
}
public void test_insert_beforeIdentifier2() {
// "f() => a + b;"
// "f() => a + xb;"
assertParse("f() => a + ", "", "x", "b;");
}
public void test_insert_convertOneFunctionToTwo() {
// "f() {}"
// "f() => 0; g() {}"
assertParse("f()", "", " => 0; g()", " {}");
}
public void test_insert_end() {
// "class A {}"
// "class A {} class B {}"
assertParse("class A {}", "", " class B {}", "");
}
public void test_insert_insideClassBody() {
// "class C {C(); }"
// "class C { C(); }"
assertParse("class C {", "", " ", "C(); }");
}
public void test_insert_insideIdentifier() {
// "f() => cob;"
// "f() => cow.b;"
assertParse("f() => co", "", "w.", "b;");
}
public void test_insert_newIdentifier1() {
// "f() => a; c;"
// "f() => a; b c;"
assertParse("f() => a;", "", " b", " c;");
}
public void test_insert_newIdentifier2() {
// "f() => a; c;"
// "f() => a;b c;"
assertParse("f() => a;", "", "b", " c;");
}
public void test_insert_newIdentifier3() {
// "/** A simple function. */ f() => a; c;"
// "/** A simple function. */ f() => a; b c;"
assertParse("/** A simple function. */ f() => a;", "", " b", " c;");
}
public void test_insert_newIdentifier4() {
// "/** An [A]. */ class A {} class B { m() { return 1; } }"
// "/** An [A]. */ class A {} class B { m() { return 1 + 2; } }"
assertParse("/** An [A]. */ class A {} class B { m() { return 1", "", " + 2", "; } }");
}
public void test_insert_period() {
// "f() => a + b;"
// "f() => a + b.;"
assertParse("f() => a + b", "", ".", ";");
}
public void test_insert_period_betweenIdentifiers1() {
// "f() => a b;"
// "f() => a. b;"
assertParse("f() => a", "", ".", " b;");
}
public void test_insert_period_betweenIdentifiers2() {
// "f() => a b;"
// "f() => a .b;"
assertParse("f() => a ", "", ".", "b;");
}
public void test_insert_period_betweenIdentifiers3() {
// "f() => a b;"
// "f() => a . b;"
assertParse("f() => a ", "", ".", " b;");
}
public void test_insert_period_insideExistingIdentifier() {
// "f() => ab;"
// "f() => a.b;"
assertParse("f() => a", "", ".", "b;");
}
public void test_insert_periodAndIdentifier() {
// "f() => a + b;"
// "f() => a + b.x;"
assertParse("f() => a + b", "", ".x", ";");
}
public void test_insert_simpleToComplexExression() {
// "/** An [A]. */ class A {} class B { m() => 1; }"
// "/** An [A]. */ class A {} class B { m() => 1 + 2; }"
assertParse("/** An [A]. */ class A {} class B { m() => 1", "", " + 2", "; }");
}
public void test_insert_whitespace_end() {
// "f() => a + b;"
// "f() => a + b; "
assertParse("f() => a + b;", "", " ", "");
}
public void test_insert_whitespace_end_multiple() {
// "f() => a + b;"
// "f() => a + b; "
assertParse("f() => a + b;", "", " ", "");
}
public void test_insert_whitespace_middle() {
// "f() => a + b;"
// "f() => a + b;"
assertParse("f() => a", "", " ", " + b;");
}
public void test_replace_identifier_beginning() {
// "f() => bell + b;"
// "f() => fell + b;"
assertParse("f() => ", "b", "f", "ell + b;");
}
public void test_replace_identifier_end() {
// "f() => bell + b;"
// "f() => belt + b;"
assertParse("f() => bel", "l", "t", " + b;");
}
public void test_replace_identifier_middle() {
// "f() => first + b;"
// "f() => frost + b;"
assertParse("f() => f", "ir", "ro", "st + b;");
}
public void test_replace_multiple_partialFirstAndLast() {
// "f() => aa + bb;"
// "f() => ab * ab;"
assertParse("f() => a", "a + b", "b * a", "b;");
}
public void test_replace_operator_oneForMany() {
// "f() => a + b;"
// "f() => a * c - b;"
assertParse("f() => a ", "+", "* c -", " b;");
}
public void test_replace_operator_oneForOne() {
// "f() => a + b;"
// "f() => a * b;"
assertParse("f() => a ", "+", "*", " b;");
}
/**
* Given a description of the original and modified contents, perform an incremental scan of the
* two pieces of text.
*
* @param prefix the unchanged text before the edit region
* @param removed the text that was removed from the original contents
* @param added the text that was added to the modified contents
* @param suffix the unchanged text after the edit region
*/
private void assertParse(String prefix, String removed, String added, String suffix) {
//
// Compute the information needed to perform the test.
//
String originalContents = prefix + removed + suffix;
String modifiedContents = prefix + added + suffix;
int replaceStart = prefix.length();
Source source = new TestSource();
//
// Parse the original contents.
//
GatheringErrorListener originalListener = new GatheringErrorListener();
Scanner originalScanner = new Scanner(
source,
new CharSequenceReader(originalContents),
originalListener);
Token originalTokens = originalScanner.tokenize();
assertNotNull(originalTokens);
Parser originalParser = new Parser(source, originalListener);
CompilationUnit originalUnit = originalParser.parseCompilationUnit(originalTokens);
assertNotNull(originalUnit);
//
// Parse the modified contents.
//
GatheringErrorListener modifiedListener = new GatheringErrorListener();
Scanner modifiedScanner = new Scanner(
source,
new CharSequenceReader(modifiedContents),
modifiedListener);
Token modifiedTokens = modifiedScanner.tokenize();
assertNotNull(modifiedTokens);
Parser modifiedParser = new Parser(source, modifiedListener);
CompilationUnit modifiedUnit = modifiedParser.parseCompilationUnit(modifiedTokens);
assertNotNull(modifiedUnit);
//
// Incrementally parse the modified contents.
//
GatheringErrorListener incrementalListener = new GatheringErrorListener();
IncrementalScanner incrementalScanner = new IncrementalScanner(source, new CharSequenceReader(
modifiedContents), incrementalListener);
Token incrementalTokens = incrementalScanner.rescan(
originalTokens,
replaceStart,
removed.length(),
added.length());
assertNotNull(incrementalTokens);
IncrementalParser incrementalParser = new IncrementalParser(
source,
incrementalScanner.getTokenMap(),
incrementalListener);
CompilationUnit incrementalUnit = incrementalParser.reparse(
originalUnit,
incrementalScanner.getLeftToken(),
incrementalScanner.getRightToken(),
replaceStart,
prefix.length() + removed.length());
assertNotNull(incrementalUnit);
//
// Validate that the results of the incremental parse are the same as the full parse of the
// modified source.
//
assertTrue(AstComparator.equalNodes(modifiedUnit, incrementalUnit));
// TODO(brianwilkerson) Verify that the errors are correct?
}
}