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
---
| script | lisp interpreter fixture |
| evaluate | (defun adderx (x) (lambda (y) (+ x y))) |
| evaluate | (setf adder20 (adderx 20)) |
| show | evaluate | (defun adderx (x) (lambda (y) (+ x y))) |
| show | evaluate | (setf adder20 (adderx 20)) |
| check | evaluate | (funcall adder20 2) | 22 |
| script | lisp interpreter fixture |
| evaluate |{{{!-
| # | Let Over Lambda Over Let Over Lambda |
| show | evaluate |!-
(let ((direction 'up))
(defun toggle-counter-direction ()
@ -23,16 +24,16 @@ Test
(if (eq direction 'up)
(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) | 2 |
| 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) | 1 |
| 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) | 2 |
| 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.TestOne||09:26:08 Fri, Feb 24, 2017|
|LispInterpreter.SuiteSetUp||14:27:52 Wed, Feb 22, 2017|

View File

@ -29,19 +29,19 @@
)
(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 ()
(assert= 90250 (compound-interest 100000 (- 5) 2))
(assert= 90250 (compound-interest 100000 -5 2))
)
(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 ()
(assert= 81450 (compound-interest 100000 (- 5) 4))
(assert= 81450 (compound-interest 100000 -5 4))
)
)

View File

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

View File

@ -1,9 +1,9 @@
package token;
import static java.lang.Character.isDigit;
import static util.Characters.*;
import file.FilePosition;
import util.Characters;
public class TokenFactoryImpl implements TokenFactory {
@ -23,9 +23,9 @@ public class TokenFactoryImpl implements TokenFactory {
case DOUBLE_QUOTE:
return new QuotedString(text, position);
default:
if (Character.isDigit(firstCharacter)) {
if (isNumeric(firstCharacter, text)) {
return new Number(text, position);
} else if (Characters.isLegalIdentifierCharacter(firstCharacter)) {
} else if (isLegalIdentifierCharacter(firstCharacter)) {
return new Identifier(text, position);
}
}
@ -33,6 +33,18 @@ public class TokenFactoryImpl implements TokenFactory {
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) {
return new Eof("EOF", position);
}

View File

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

View File

@ -161,6 +161,15 @@ public class LispScannerTypeTester {
assertTokenTypesMatch(input);
}
@Test
public void givenPrefixedIdentifiers_ReturnsCorrectTypes() {
String input = "-a +b";
expectedTypes.add(Identifier.class);
expectedTypes.add(Identifier.class);
assertTokenTypesMatch(input);
}
@Test
public void givenSingleDigitNumber_ReturnsCorrectTypes() {
String input = "1";
@ -169,6 +178,58 @@ public class LispScannerTypeTester {
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
public void givenMultipleDigitNumber_ReturnsCorrectTypes() {
String input = "1234567890";