Resolves #7 - Allow prefixing of numbers

This commit is contained in:
Mike Cifelli 2017-02-27 13:34:04 -05:00
parent bf40feadec
commit fb35884479
7 changed files with 113 additions and 20 deletions

View File

@ -2,13 +2,14 @@
Test Test
--- ---
| script | lisp interpreter fixture | | script | lisp interpreter fixture |
| evaluate | (defun adderx (x) (lambda (y) (+ x y))) | | show | evaluate | (defun adderx (x) (lambda (y) (+ x y))) |
| evaluate | (setf adder20 (adderx 20)) | | show | evaluate | (setf adder20 (adderx 20)) |
| check | evaluate | (funcall adder20 2) | 22 | | check | evaluate | (funcall adder20 2) | 22 |
| script | lisp interpreter fixture | | script | lisp interpreter fixture |
| evaluate |{{{!- | # | Let Over Lambda Over Let Over Lambda |
| show | evaluate |!-
(let ((direction 'up)) (let ((direction 'up))
(defun toggle-counter-direction () (defun toggle-counter-direction ()
@ -23,16 +24,16 @@ Test
(if (eq direction 'up) (if (eq direction 'up)
(setq counter (+ counter 1)) (setq counter (+ counter 1))
(setq counter (- counter 1))))))) (setq counter (- counter 1)))))))
-!}}}| -!|
| evaluate | (setq my-counter (counter-class)) | | show | evaluate | (setq my-counter (counter-class)) |
| check | evaluate | (funcall my-counter) | 1 | | check | evaluate | (funcall my-counter) | 1 |
| check | evaluate | (funcall my-counter) | 2 | | check | evaluate | (funcall my-counter) | 2 |
| check | evaluate | (funcall my-counter) | 3 | | check | evaluate | (funcall my-counter) | 3 |
| evaluate | (toggle-counter-direction) | | show | evaluate | (toggle-counter-direction) |
| check | evaluate | (funcall my-counter) | 2 | | check | evaluate | (funcall my-counter) | 2 |
| check | evaluate | (funcall my-counter) | 1 | | check | evaluate | (funcall my-counter) | 1 |
| check | evaluate | (funcall my-counter) | 0 | | check | evaluate | (funcall my-counter) | 0 |
| evaluate | (toggle-counter-direction) | | show | evaluate | (toggle-counter-direction) |
| check | evaluate | (funcall my-counter) | 1 | | check | evaluate | (funcall my-counter) | 1 |
| check | evaluate | (funcall my-counter) | 2 | | check | evaluate | (funcall my-counter) | 2 |
| check | evaluate | (funcall my-counter) | 3 | | check | evaluate | (funcall my-counter) | 3 |

View File

@ -1,4 +1,4 @@
|LispInterpreter.LexicalClosures||11:52:29 Mon, Feb 27, 2017| |LispInterpreter.LexicalClosures||12:10:13 Mon, Feb 27, 2017|
|LispInterpreter.TestClosure||11:24:27 Mon, Feb 27, 2017| |LispInterpreter.TestClosure||11:24:27 Mon, Feb 27, 2017|
|LispInterpreter.TestOne||09:26:08 Fri, Feb 24, 2017| |LispInterpreter.TestOne||09:26:08 Fri, Feb 24, 2017|
|LispInterpreter.SuiteSetUp||14:27:52 Wed, Feb 22, 2017| |LispInterpreter.SuiteSetUp||14:27:52 Wed, Feb 22, 2017|

View File

@ -29,19 +29,19 @@
) )
(defun one-year-with-negative-interest-rate () (defun one-year-with-negative-interest-rate ()
(assert= 95000 (compound-interest 100000 (- 5) 1)) (assert= 95000 (compound-interest 100000 -5 1))
) )
(defun two-years-with-negative-interest-rate () (defun two-years-with-negative-interest-rate ()
(assert= 90250 (compound-interest 100000 (- 5) 2)) (assert= 90250 (compound-interest 100000 -5 2))
) )
(defun three-years-with-negative-interest-rate () (defun three-years-with-negative-interest-rate ()
(assert= 85737 (compound-interest 100000 (- 5) 3)) (assert= 85737 (compound-interest 100000 -5 3))
) )
(defun four-years-with-negative-interest-rate () (defun four-years-with-negative-interest-rate ()
(assert= 81450 (compound-interest 100000 (- 5) 4)) (assert= 81450 (compound-interest 100000 -5 4))
) )
) )

View File

@ -1,5 +1,6 @@
package scanner; package scanner;
import static java.lang.Character.*;
import static util.Characters.*; import static util.Characters.*;
import java.io.InputStream; import java.io.InputStream;
@ -30,7 +31,7 @@ public class LispScanner {
char currentCharacter = (char) c; char currentCharacter = (char) c;
positionTracker.incrementColumn(); positionTracker.incrementColumn();
if (!Character.isWhitespace(currentCharacter)) if (!isWhitespace(currentCharacter))
return createTokenFromCharacter(currentCharacter); return createTokenFromCharacter(currentCharacter);
else if (currentCharacter == NEWLINE) else if (currentCharacter == NEWLINE)
positionTracker.incrementLine(); positionTracker.incrementLine();
@ -51,9 +52,11 @@ public class LispScanner {
if (firstCharacter == DOUBLE_QUOTE) if (firstCharacter == DOUBLE_QUOTE)
tokenText = retrieveStringTokenText(firstCharacter); tokenText = retrieveStringTokenText(firstCharacter);
else if (Character.isDigit(firstCharacter)) else if (isNumberPrefix(firstCharacter))
tokenText = retrieveNumberOrIdentifierTokenText(firstCharacter);
else if (isDigit(firstCharacter))
tokenText = retrieveNumberTokenText(firstCharacter); tokenText = retrieveNumberTokenText(firstCharacter);
else if (Characters.isLegalIdentifierCharacter(firstCharacter)) else if (isLegalIdentifierCharacter(firstCharacter))
tokenText = retrieveIdentifierTokenText(firstCharacter); tokenText = retrieveIdentifierTokenText(firstCharacter);
return tokenText; return tokenText;
@ -66,8 +69,18 @@ public class LispScanner {
return retriever.retrieveToken(); return retriever.retrieveToken();
} }
private String retrieveNumberTokenText(char firstDigit) { private String retrieveNumberOrIdentifierTokenText(char firstCharacter) {
ComplexTokenTextRetriever retriever = new ComplexTokenTextRetriever(firstDigit, Character::isDigit); char nextCharacter = (char) inputStream.read();
inputStream.unreadLastCharacter();
if (isDigit(nextCharacter))
return retrieveNumberTokenText(firstCharacter);
return retrieveIdentifierTokenText(firstCharacter);
}
private String retrieveNumberTokenText(char firstCharacter) {
ComplexTokenTextRetriever retriever = new ComplexTokenTextRetriever(firstCharacter, Character::isDigit);
return retriever.retrieveToken(); return retriever.retrieveToken();
} }

View File

@ -1,9 +1,9 @@
package token; package token;
import static java.lang.Character.isDigit;
import static util.Characters.*; import static util.Characters.*;
import file.FilePosition; import file.FilePosition;
import util.Characters;
public class TokenFactoryImpl implements TokenFactory { public class TokenFactoryImpl implements TokenFactory {
@ -23,9 +23,9 @@ public class TokenFactoryImpl implements TokenFactory {
case DOUBLE_QUOTE: case DOUBLE_QUOTE:
return new QuotedString(text, position); return new QuotedString(text, position);
default: default:
if (Character.isDigit(firstCharacter)) { if (isNumeric(firstCharacter, text)) {
return new Number(text, position); return new Number(text, position);
} else if (Characters.isLegalIdentifierCharacter(firstCharacter)) { } else if (isLegalIdentifierCharacter(firstCharacter)) {
return new Identifier(text, position); return new Identifier(text, position);
} }
} }
@ -33,6 +33,18 @@ public class TokenFactoryImpl implements TokenFactory {
throw new BadCharacterException(text, position); throw new BadCharacterException(text, position);
} }
private boolean isNumeric(char firstCharacter, String text) {
return isDigit(firstCharacter) || isPrefixedNumeric(firstCharacter, text);
}
private boolean isPrefixedNumeric(char firstCharacter, String text) {
return isNumberPrefix(firstCharacter) && isNextCharacterDigit(text);
}
private boolean isNextCharacterDigit(String text) {
return (text.length() > 1) && isDigit(text.charAt(1));
}
public Token createEOFToken(FilePosition position) { public Token createEOFToken(FilePosition position) {
return new Eof("EOF", position); return new Eof("EOF", position);
} }

View File

@ -9,12 +9,14 @@ public final class Characters {
public static final int EOF = -1; public static final int EOF = -1;
public static final char BACKSLASH = '\\'; public static final char BACKSLASH = '\\';
public static final char DASH = '-';
public static final char DOUBLE_QUOTE = '\"'; public static final char DOUBLE_QUOTE = '\"';
public static final char HASH = '#'; public static final char HASH = '#';
public static final char LEFT_PARENTHESIS = '('; public static final char LEFT_PARENTHESIS = '(';
public static final char LEFT_SQUARE_BRACKET = '['; public static final char LEFT_SQUARE_BRACKET = '[';
public static final char NEWLINE = '\n'; public static final char NEWLINE = '\n';
public static final char PERIOD = '.'; public static final char PERIOD = '.';
public static final char PLUS = '+';
public static final char RIGHT_PARENTHESIS = ')'; public static final char RIGHT_PARENTHESIS = ')';
public static final char RIGHT_SQUARE_BRACKET = ']'; public static final char RIGHT_SQUARE_BRACKET = ']';
public static final char SEMICOLON = ';'; public static final char SEMICOLON = ';';
@ -44,5 +46,9 @@ public final class Characters {
public static boolean isLegalStringCharacter(char c) { public static boolean isLegalStringCharacter(char c) {
return true; return true;
} }
public static boolean isNumberPrefix(char c) {
return c == DASH || c == PLUS;
}
} }

View File

@ -161,6 +161,15 @@ public class LispScannerTypeTester {
assertTokenTypesMatch(input); assertTokenTypesMatch(input);
} }
@Test
public void givenPrefixedIdentifiers_ReturnsCorrectTypes() {
String input = "-a +b";
expectedTypes.add(Identifier.class);
expectedTypes.add(Identifier.class);
assertTokenTypesMatch(input);
}
@Test @Test
public void givenSingleDigitNumber_ReturnsCorrectTypes() { public void givenSingleDigitNumber_ReturnsCorrectTypes() {
String input = "1"; String input = "1";
@ -169,6 +178,58 @@ public class LispScannerTypeTester {
assertTokenTypesMatch(input); assertTokenTypesMatch(input);
} }
@Test
public void givenPrefixedNegativeNumber_ReturnsCorrectTypes() {
String input = "-1";
expectedTypes.add(Number.class);
assertTokenTypesMatch(input);
}
@Test
public void givenPrefixedNumber_ReturnsCorrectTypes() {
String input = "+1";
expectedTypes.add(Number.class);
assertTokenTypesMatch(input);
}
@Test
public void givenPrefixedNegativeNumberAndIdentifier_ReturnsCorrectTypes() {
String input = "-1apple";
expectedTypes.add(Number.class);
expectedTypes.add(Identifier.class);
assertTokenTypesMatch(input);
}
@Test
public void givenPrefixedNumberAndIdentifier_ReturnsCorrectTypes() {
String input = "+1apple";
expectedTypes.add(Number.class);
expectedTypes.add(Identifier.class);
assertTokenTypesMatch(input);
}
@Test
public void givenPrefixedNegativeNumberAndString_ReturnsCorrectTypes() {
String input = "-1\"apple\"";
expectedTypes.add(Number.class);
expectedTypes.add(QuotedString.class);
assertTokenTypesMatch(input);
}
@Test
public void givenPrefixedNumberAndString_ReturnsCorrectTypes() {
String input = "+1\"apple\"";
expectedTypes.add(Number.class);
expectedTypes.add(QuotedString.class);
assertTokenTypesMatch(input);
}
@Test @Test
public void givenMultipleDigitNumber_ReturnsCorrectTypes() { public void givenMultipleDigitNumber_ReturnsCorrectTypes() {
String input = "1234567890"; String input = "1234567890";