Refactored LispScanner and some unit tests
This commit is contained in:
		
							parent
							
								
									0d406c3e36
								
							
						
					
					
						commit
						abdd89737f
					
				| @ -1,9 +1,6 @@ | ||||
| package scanner; | ||||
| 
 | ||||
| import static util.Characters.BACKSLASH; | ||||
| import static util.Characters.DOUBLE_QUOTE; | ||||
| import static util.Characters.EOF; | ||||
| import static util.Characters.NEWLINE; | ||||
| import static util.Characters.*; | ||||
| 
 | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.IOException; | ||||
| @ -39,11 +36,10 @@ public class LispScanner { | ||||
|             char currentCharacter = (char) c; | ||||
|             positionTracker.incrementColumn(); | ||||
| 
 | ||||
|             if (Character.isWhitespace(currentCharacter)) { | ||||
|                 if (currentCharacter == NEWLINE) | ||||
|                     positionTracker.incrementLine(); | ||||
|             } else | ||||
|             if (!Character.isWhitespace(currentCharacter)) | ||||
|                 return createTokenFromCharacter(currentCharacter); | ||||
|             else if (currentCharacter == NEWLINE) | ||||
|                 positionTracker.incrementLine(); | ||||
|         } | ||||
| 
 | ||||
|         return tokenFactory.createEOFToken(positionTracker.getCurrentPosition()); | ||||
| @ -60,70 +56,100 @@ public class LispScanner { | ||||
|         String tokenText = "" + firstCharacter; | ||||
| 
 | ||||
|         if (firstCharacter == DOUBLE_QUOTE) | ||||
|             tokenText = retrieveString(firstCharacter); | ||||
|             tokenText = retrieveStringTokenText(firstCharacter); | ||||
|         else if (Character.isDigit(firstCharacter)) | ||||
|             tokenText = retrieveNumber(firstCharacter); | ||||
|             tokenText = retrieveNumberTokenText(firstCharacter); | ||||
|         else if (Characters.isLegalIdentifierCharacter(firstCharacter)) | ||||
|             tokenText = retrieveIdentifier(firstCharacter); | ||||
|             tokenText = retrieveIdentifierTokenText(firstCharacter); | ||||
| 
 | ||||
|         return tokenText; | ||||
|     } | ||||
| 
 | ||||
|     private String retrieveString(char firstDoubleQuote) throws IOException { | ||||
|         StringBuilder text = new StringBuilder(); | ||||
|         FilePosition stringPosition = positionTracker.getCurrentPosition(); | ||||
|         char prevChar = firstDoubleQuote; | ||||
|     private String retrieveStringTokenText(char firstDoubleQuote) throws IOException { | ||||
|         ComplexTokenTextRetriever retriever = new ComplexTokenTextRetriever(firstDoubleQuote, | ||||
|                                                                             Characters::isLegalStringCharacter); | ||||
| 
 | ||||
|         text.append(firstDoubleQuote); | ||||
|         return retriever.retrieveToken(); | ||||
|     } | ||||
| 
 | ||||
|         for (int c = inputStream.read(); c != EOF; c = inputStream.read()) { | ||||
|             char nextChar = (char) c; | ||||
|     private String retrieveNumberTokenText(char firstDigit) throws IOException { | ||||
|         ComplexTokenTextRetriever retriever = new ComplexTokenTextRetriever(firstDigit, Character::isDigit); | ||||
| 
 | ||||
|             positionTracker.incrementColumn(); | ||||
|             text.append(nextChar); | ||||
|         return retriever.retrieveToken(); | ||||
|     } | ||||
| 
 | ||||
|             if (nextChar == NEWLINE) | ||||
|                 positionTracker.incrementLine(); | ||||
|             else if ((nextChar == DOUBLE_QUOTE) && (prevChar != BACKSLASH)) | ||||
|                 return text.toString(); | ||||
|     private String retrieveIdentifierTokenText(char firstCharacter) throws IOException { | ||||
|         ComplexTokenTextRetriever retriever = new ComplexTokenTextRetriever(firstCharacter, | ||||
|                                                                             Characters::isLegalIdentifierCharacter); | ||||
| 
 | ||||
|             prevChar = nextChar; | ||||
|         return retriever.retrieveToken(); | ||||
|     } | ||||
| 
 | ||||
|     public class ComplexTokenTextRetriever { | ||||
| 
 | ||||
|         Function<Character, Boolean> isPartOfToken; | ||||
|         StringBuilder text; | ||||
|         FilePosition position; | ||||
|         char firstCharacter; | ||||
|         char currentCharacter; | ||||
|         char previousCharacter; | ||||
| 
 | ||||
|         public ComplexTokenTextRetriever(char firstCharacter, Function<Character, Boolean> isPartOfToken) { | ||||
|             this.isPartOfToken = isPartOfToken; | ||||
|             this.text = new StringBuilder(); | ||||
|             this.position = positionTracker.getCurrentPosition(); | ||||
|             this.firstCharacter = firstCharacter; | ||||
|             this.currentCharacter = firstCharacter; | ||||
|             this.previousCharacter = firstCharacter; | ||||
|         } | ||||
| 
 | ||||
|         throw new UnterminatedStringException(stringPosition); | ||||
|     } | ||||
|         public String retrieveToken() throws IOException { | ||||
|             text.append(firstCharacter); | ||||
|             inputStream.mark(1); | ||||
| 
 | ||||
|     private String retrieveNumber(char firstDigit) throws IOException { | ||||
|         return retrieveNumberOrIdentifier(firstDigit, Character::isDigit); | ||||
|     } | ||||
|             for (int c = inputStream.read(); c != EOF; c = inputStream.read()) { | ||||
|                 currentCharacter = (char) c; | ||||
| 
 | ||||
|     private String retrieveIdentifier(char firstCharacter) throws IOException { | ||||
|         return retrieveNumberOrIdentifier(firstCharacter, Characters::isLegalIdentifierCharacter); | ||||
|     } | ||||
|                 if (!isPartOfToken.apply(currentCharacter)) { | ||||
|                     inputStream.reset(); | ||||
| 
 | ||||
|     private String retrieveNumberOrIdentifier(char firstCharacter, Function<Character, Boolean> isPartOfToken) | ||||
|             throws IOException { | ||||
|         StringBuilder text = new StringBuilder(); | ||||
|                     return text.toString(); | ||||
|                 } | ||||
| 
 | ||||
|         text.append(firstCharacter); | ||||
|         inputStream.mark(1); | ||||
|                 addCharacterToToken(); | ||||
| 
 | ||||
|         for (int c = inputStream.read(); c != EOF; c = inputStream.read()) { | ||||
|             char nextChar = (char) c; | ||||
|                 if (isStringToken() && isTerminatingDoubleQuote()) | ||||
|                     return text.toString(); | ||||
| 
 | ||||
|             if (isPartOfToken.apply(nextChar)) { | ||||
|                 text.append(nextChar); | ||||
|                 positionTracker.incrementColumn(); | ||||
|             } else { | ||||
|                 inputStream.reset(); | ||||
| 
 | ||||
|                 return text.toString(); | ||||
|                 previousCharacter = currentCharacter; | ||||
|             } | ||||
| 
 | ||||
|             inputStream.mark(1); | ||||
|             return terminateTokenWithEOF(); | ||||
|         } | ||||
| 
 | ||||
|         return text.toString(); | ||||
|         private void addCharacterToToken() { | ||||
|             text.append(currentCharacter); | ||||
|             positionTracker.incrementColumn(); | ||||
|             inputStream.mark(1); | ||||
| 
 | ||||
|             if (currentCharacter == NEWLINE) | ||||
|                 positionTracker.incrementLine(); | ||||
|         } | ||||
| 
 | ||||
|         private boolean isStringToken() { | ||||
|             return firstCharacter == DOUBLE_QUOTE; | ||||
|         } | ||||
| 
 | ||||
|         private boolean isTerminatingDoubleQuote() { | ||||
|             return (currentCharacter == DOUBLE_QUOTE) && (previousCharacter != BACKSLASH); | ||||
|         } | ||||
| 
 | ||||
|         private String terminateTokenWithEOF() { | ||||
|             if (isStringToken()) | ||||
|                 throw new UnterminatedStringException(position); | ||||
| 
 | ||||
|             return text.toString(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static class UnterminatedStringException extends LispException { | ||||
| @ -145,7 +171,6 @@ public class LispScanner { | ||||
|             return MessageFormat.format("unterminated quoted string - line {0}, column {1}", position.getLineNumber(), | ||||
|                                         position.getColumnNumber()); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -39,5 +39,9 @@ public class Characters { | ||||
|     public static boolean isLegalIdentifierCharacter(char c) { | ||||
|         return (!Character.isWhitespace(c)) && (!illegalIdentifierCharacters.contains(c)); | ||||
|     } | ||||
|      | ||||
|     public static boolean isLegalStringCharacter(char c) { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -19,39 +19,24 @@ public class FilePositionTrackerTester { | ||||
| 
 | ||||
|     @Test | ||||
|     public void filePositionEquality_CorrectlyReturnsTrue() { | ||||
|         FilePosition positionOne = new FilePosition(FILE_NAME); | ||||
|         positionOne.setLineNumber(5); | ||||
|         positionOne.setColumnNumber(9); | ||||
| 
 | ||||
|         FilePosition positionTwo = new FilePosition(FILE_NAME); | ||||
|         positionTwo.setLineNumber(5); | ||||
|         positionTwo.setColumnNumber(9); | ||||
|         FilePosition positionOne = createFilePosition(5, 9); | ||||
|         FilePosition positionTwo = createFilePosition(5, 9); | ||||
| 
 | ||||
|         assertTrue(positionOne.isEqual(positionTwo)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void filePositionEquality_CorrectlyReturnsFalseWithDifferentLine() { | ||||
|         FilePosition positionOne = new FilePosition(FILE_NAME); | ||||
|         positionOne.setLineNumber(5); | ||||
|         positionOne.setColumnNumber(9); | ||||
| 
 | ||||
|         FilePosition positionTwo = new FilePosition(FILE_NAME); | ||||
|         positionTwo.setLineNumber(8); | ||||
|         positionTwo.setColumnNumber(9); | ||||
|         FilePosition positionOne = createFilePosition(5, 9); | ||||
|         FilePosition positionTwo = createFilePosition(8, 9); | ||||
| 
 | ||||
|         assertFalse(positionOne.isEqual(positionTwo)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void filePositionEquality_CorrectlyReturnsFalseWithDifferentColumn() { | ||||
|         FilePosition positionOne = new FilePosition(FILE_NAME); | ||||
|         positionOne.setLineNumber(5); | ||||
|         positionOne.setColumnNumber(9); | ||||
| 
 | ||||
|         FilePosition positionTwo = new FilePosition(FILE_NAME); | ||||
|         positionTwo.setLineNumber(5); | ||||
|         positionTwo.setColumnNumber(10); | ||||
|         FilePosition positionOne = createFilePosition(5, 9); | ||||
|         FilePosition positionTwo = createFilePosition(5, 10); | ||||
| 
 | ||||
|         assertFalse(positionOne.isEqual(positionTwo)); | ||||
|     } | ||||
| @ -71,18 +56,14 @@ public class FilePositionTrackerTester { | ||||
| 
 | ||||
|     @Test | ||||
|     public void noMovement_ReturnsInitialPosition() { | ||||
|         FilePosition expectedPosition = new FilePosition(FILE_NAME); | ||||
|         expectedPosition.setLineNumber(1); | ||||
|         expectedPosition.setColumnNumber(0); | ||||
|         FilePosition expectedPosition = createFilePosition(1, 0); | ||||
| 
 | ||||
|         assertTrue(expectedPosition.isEqual(trackerUnderTest.getCurrentPosition())); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void advanceOneColumn_ReturnsCorrectPosition() { | ||||
|         FilePosition expectedPosition = new FilePosition(FILE_NAME); | ||||
|         expectedPosition.setLineNumber(1); | ||||
|         expectedPosition.setColumnNumber(1); | ||||
|         FilePosition expectedPosition = createFilePosition(1, 1); | ||||
| 
 | ||||
|         trackerUnderTest.incrementColumn(); | ||||
| 
 | ||||
| @ -91,9 +72,7 @@ public class FilePositionTrackerTester { | ||||
| 
 | ||||
|     @Test | ||||
|     public void advanceOneLine_ReturnsCorrectPosition() { | ||||
|         FilePosition expectedPosition = new FilePosition(FILE_NAME); | ||||
|         expectedPosition.setLineNumber(2); | ||||
|         expectedPosition.setColumnNumber(0); | ||||
|         FilePosition expectedPosition = createFilePosition(2, 0); | ||||
| 
 | ||||
|         trackerUnderTest.incrementLine(); | ||||
| 
 | ||||
| @ -102,9 +81,7 @@ public class FilePositionTrackerTester { | ||||
| 
 | ||||
|     @Test | ||||
|     public void advanceOneLine_ResetsColumn() { | ||||
|         FilePosition expectedPosition = new FilePosition(FILE_NAME); | ||||
|         expectedPosition.setLineNumber(2); | ||||
|         expectedPosition.setColumnNumber(0); | ||||
|         FilePosition expectedPosition = createFilePosition(2, 0); | ||||
| 
 | ||||
|         trackerUnderTest.incrementColumn(); | ||||
|         trackerUnderTest.incrementLine(); | ||||
| @ -112,4 +89,12 @@ public class FilePositionTrackerTester { | ||||
|         assertTrue(expectedPosition.isEqual(trackerUnderTest.getCurrentPosition())); | ||||
|     } | ||||
| 
 | ||||
|     private FilePosition createFilePosition(int lineNumber, int columnNumber) { | ||||
|         FilePosition position = new FilePosition(FILE_NAME); | ||||
|         position.setLineNumber(lineNumber); | ||||
|         position.setColumnNumber(columnNumber); | ||||
| 
 | ||||
|         return position; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user