Started refactoring the sexpression package and cleaned up some unit test code
This commit is contained in:
parent
c4e3740dfb
commit
7b7556cc65
|
@ -1,3 +0,0 @@
|
||||||
<body>
|
|
||||||
Provides a class for managing errors in the Lisp Interpreter.
|
|
||||||
</body>
|
|
|
@ -67,7 +67,7 @@ public class DEFUN extends LispFunction {
|
||||||
|
|
||||||
// place the function in the function table
|
// place the function in the function table
|
||||||
functionTable.put(name.toString(),
|
functionTable.put(name.toString(),
|
||||||
new UDFunction(name.toString(), lambdaList, body));
|
new UserDefinedFunction(name.toString(), lambdaList, body));
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class LAMBDA extends LispFunction {
|
||||||
* @throws RuntimeException
|
* @throws RuntimeException
|
||||||
* Indicates that <code>lexpr</code> is not a valid lambda expression.
|
* Indicates that <code>lexpr</code> is not a valid lambda expression.
|
||||||
*/
|
*/
|
||||||
public static UDFunction createFunction(Cons lexpr) {
|
public static UserDefinedFunction createFunction(Cons lexpr) {
|
||||||
LAMBDA lambda = new LAMBDA();
|
LAMBDA lambda = new LAMBDA();
|
||||||
SExpression cdr = lexpr.getCdr();
|
SExpression cdr = lexpr.getCdr();
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ public class LAMBDA extends LispFunction {
|
||||||
Cons lambdaList = (Cons) car;
|
Cons lambdaList = (Cons) car;
|
||||||
Cons body = (Cons) argList.getCdr();
|
Cons body = (Cons) argList.getCdr();
|
||||||
Cons lexpr = new Cons(new Symbol("LAMBDA"), argList);
|
Cons lexpr = new Cons(new Symbol("LAMBDA"), argList);
|
||||||
UDFunction function = new UDFunction(":LAMBDA", lambdaList, body);
|
UserDefinedFunction function = new UserDefinedFunction(":LAMBDA", lambdaList, body);
|
||||||
|
|
||||||
return new LambdaExpression(lexpr, function);
|
return new LambdaExpression(lexpr, function);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import sexpression.SExpression;
|
||||||
public class LambdaExpression extends SExpression {
|
public class LambdaExpression extends SExpression {
|
||||||
|
|
||||||
private Cons lexpr;
|
private Cons lexpr;
|
||||||
private UDFunction function;
|
private UserDefinedFunction function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new FUNCTION with the specified lambda expression and
|
* Create a new FUNCTION with the specified lambda expression and
|
||||||
|
@ -27,7 +27,7 @@ public class LambdaExpression extends SExpression {
|
||||||
* @param function
|
* @param function
|
||||||
* the internal representation of this FUNCTION
|
* the internal representation of this FUNCTION
|
||||||
*/
|
*/
|
||||||
public LambdaExpression(Cons lexpr, UDFunction function) {
|
public LambdaExpression(Cons lexpr, UserDefinedFunction function) {
|
||||||
this.lexpr = lexpr;
|
this.lexpr = lexpr;
|
||||||
this.function = function;
|
this.function = function;
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ public class LambdaExpression extends SExpression {
|
||||||
* @return
|
* @return
|
||||||
* the user-defined function of this FUNCTION
|
* the user-defined function of this FUNCTION
|
||||||
*/
|
*/
|
||||||
public UDFunction getFunction() {
|
public UserDefinedFunction getFunction() {
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,10 +44,10 @@ public class SYMBOL_FUNCTION extends LispFunction {
|
||||||
|
|
||||||
// make sure the function actually exists
|
// make sure the function actually exists
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
if (function instanceof UDFunction) {
|
if (function instanceof UserDefinedFunction) {
|
||||||
// this is a user-defined function
|
// this is a user-defined function
|
||||||
|
|
||||||
UDFunction udFunction = (UDFunction) function;
|
UserDefinedFunction udFunction = (UserDefinedFunction) function;
|
||||||
|
|
||||||
return udFunction.getLexpr();
|
return udFunction.getLexpr();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,10 @@
|
||||||
/*
|
|
||||||
* Name: Mike Cifelli
|
|
||||||
* Course: CIS 443 - Programming Languages
|
|
||||||
* Assignment: Lisp Interpreter 2
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eval;
|
package eval;
|
||||||
|
|
||||||
import parser.*;
|
|
||||||
import sexpression.Cons;
|
|
||||||
import sexpression.SExpression;
|
|
||||||
import sexpression.Symbol;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
import sexpression.*;
|
||||||
* A <code>UDFunction</code> is an internal representation of a user-defined
|
|
||||||
* function in the Lisp programming language.
|
public class UserDefinedFunction extends LispFunction {
|
||||||
*/
|
|
||||||
public class UDFunction extends LispFunction {
|
|
||||||
|
|
||||||
// the number of arguments that this user-defined function takes.
|
// the number of arguments that this user-defined function takes.
|
||||||
private final int NUM_ARGS;
|
private final int NUM_ARGS;
|
||||||
|
@ -40,7 +27,7 @@ public class UDFunction extends LispFunction {
|
||||||
* @param body
|
* @param body
|
||||||
* the body of this user-defined function (MUST BE A PROPER LIST)
|
* the body of this user-defined function (MUST BE A PROPER LIST)
|
||||||
*/
|
*/
|
||||||
public UDFunction(String name, Cons lambdaList, Cons body) {
|
public UserDefinedFunction(String name, Cons lambdaList, Cons body) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
this.lexpr = new Cons(new Symbol(name), new Cons(lambdaList, body));
|
this.lexpr = new Cons(new Symbol(name), new Cons(lambdaList, body));
|
|
@ -1,4 +0,0 @@
|
||||||
<body>
|
|
||||||
Provides functions and forms to be used during the evaluation of an
|
|
||||||
S-expression.
|
|
||||||
</body>
|
|
|
@ -1,7 +1,5 @@
|
||||||
package file;
|
package file;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class FilePosition {
|
public class FilePosition {
|
||||||
|
|
||||||
private String fileName;
|
private String fileName;
|
||||||
|
@ -11,29 +9,25 @@ public class FilePosition {
|
||||||
public FilePosition(String fileName) {
|
public FilePosition(String fileName) {
|
||||||
this.fileName = fileName;
|
this.fileName = fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFileName() {
|
public String getFileName() {
|
||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLineNumber() {
|
public int getLineNumber() {
|
||||||
return lineNumber;
|
return lineNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLineNumber(int lineNumber) {
|
public void setLineNumber(int lineNumber) {
|
||||||
this.lineNumber = lineNumber;
|
this.lineNumber = lineNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getColumnNumber() {
|
public int getColumnNumber() {
|
||||||
return columnNumber;
|
return columnNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColumnNumber(int columnNumber) {
|
public void setColumnNumber(int columnNumber) {
|
||||||
this.columnNumber = columnNumber;
|
this.columnNumber = columnNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEqual(FilePosition otherFilePosition) {
|
|
||||||
return Objects.equals(this.fileName, otherFilePosition.fileName) && (this.lineNumber == otherFilePosition.lineNumber)
|
|
||||||
&& (this.columnNumber == otherFilePosition.columnNumber);
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -16,11 +16,10 @@ import java.io.*;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>LispInterpreter</code> is an interpreter for the Lisp programming
|
* This is an interpreter for the Lisp programming language. It takes the name of a file as a
|
||||||
* language. It takes the name of a file as a command-line argument, evaluates
|
* command-line argument, evaluates the s-expressions found in the file and then prints the results
|
||||||
* the S-expressions found in the file and then prints the results to the
|
* to the console. If no file name is provided at the command-line, this program will read from
|
||||||
* console. If no file name is provided at the command-line, this program will
|
* standard input.
|
||||||
* read from standard input.
|
|
||||||
*/
|
*/
|
||||||
public class LispInterpreter {
|
public class LispInterpreter {
|
||||||
|
|
||||||
|
@ -31,15 +30,9 @@ public class LispInterpreter {
|
||||||
public static final String ANSI_GREEN = "\u001B[32m";
|
public static final String ANSI_GREEN = "\u001B[32m";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluate the S-expressions found in the file given as a command-line
|
* Evaluate the s-expressions found in the file given as a command-line argument and print the
|
||||||
* argument and print the results to the console. If no file name was given,
|
* results to the console. If no file name was given, retrieve the s-expressions from standard
|
||||||
* retrieve the S-expressions from standard input.
|
* input.
|
||||||
*
|
|
||||||
* @param args
|
|
||||||
* the command-line arguments:
|
|
||||||
* <ul>
|
|
||||||
* <li><code>args[0]</code> - file name (optional)</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
LispParser parser = null;
|
LispParser parser = null;
|
||||||
|
@ -94,7 +87,7 @@ public class LispInterpreter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSeverity() {
|
public int getSeverity() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
<body>
|
|
||||||
Provides test drivers for the various stages of the Lisp Interpreter.
|
|
||||||
</body>
|
|
|
@ -9,8 +9,7 @@ import token.Eof;
|
||||||
import token.Token;
|
import token.Token;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a stream of bytes into internal representations of Lisp
|
* Converts a stream of bytes into internal representations of Lisp s-expressions.
|
||||||
* S-expressions.
|
|
||||||
*/
|
*/
|
||||||
public class LispParser {
|
public class LispParser {
|
||||||
|
|
||||||
|
@ -50,7 +49,7 @@ public class LispParser {
|
||||||
|
|
||||||
isNextTokenStored = false;
|
isNextTokenStored = false;
|
||||||
|
|
||||||
return nextToken.sExpr(scanner::getNextToken);
|
return nextToken.parseSExpression(scanner::getNextToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void throwDelayedExceptionIfNecessary() {
|
private void throwDelayedExceptionIfNecessary() {
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
<body>
|
|
||||||
Provides the classes necessary for creating an internal representation of
|
|
||||||
the Lisp programming language.
|
|
||||||
</body>
|
|
|
@ -1,3 +0,0 @@
|
||||||
<body>
|
|
||||||
Provides the classes necessary to perform a lexical analysis of the Lisp programming language.
|
|
||||||
</body>
|
|
|
@ -1,44 +1,17 @@
|
||||||
/*
|
|
||||||
* Name: Mike Cifelli
|
|
||||||
* Course: CIS 443 - Programming Languages
|
|
||||||
* Assignment: Lisp Parser
|
|
||||||
*/
|
|
||||||
|
|
||||||
package sexpression;
|
package sexpression;
|
||||||
|
|
||||||
/**
|
public abstract class Atom extends SExpression {
|
||||||
* This class represents an ATOM in the PL-Lisp implementation.
|
|
||||||
*/
|
|
||||||
public class Atom extends SExpression {
|
|
||||||
|
|
||||||
private String text;
|
private String text;
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new ATOM with the specified text.
|
|
||||||
*
|
|
||||||
* @param text
|
|
||||||
* the text representing this ATOM
|
|
||||||
*/
|
|
||||||
public Atom(String text) {
|
public Atom(String text) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is an ATOM.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>true</code>
|
|
||||||
*/
|
|
||||||
public boolean atomp() {
|
public boolean atomp() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of this ATOM.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* a string representation of this ATOM
|
|
||||||
*/
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,88 +1,35 @@
|
||||||
/*
|
|
||||||
* Name: Mike Cifelli
|
|
||||||
* Course: CIS 443 - Programming Languages
|
|
||||||
* Assignment: Lisp Parser
|
|
||||||
*/
|
|
||||||
|
|
||||||
package sexpression;
|
package sexpression;
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents a Lisp CONS cell in the PL-Lisp implementation.
|
|
||||||
*/
|
|
||||||
public class Cons extends SExpression {
|
public class Cons extends SExpression {
|
||||||
|
|
||||||
private SExpression car;
|
private SExpression car;
|
||||||
private SExpression cdr;
|
private SExpression cdr;
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new CONS cell with the specified car and cdr.
|
|
||||||
*
|
|
||||||
* @param car
|
|
||||||
* the car of this CONS cell
|
|
||||||
* @param cdr
|
|
||||||
* the cdr of this CONS cell
|
|
||||||
*/
|
|
||||||
public Cons(SExpression car, SExpression cdr) {
|
public Cons(SExpression car, SExpression cdr) {
|
||||||
this.car = car;
|
this.car = car;
|
||||||
this.cdr = cdr;
|
this.cdr = cdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the car of this CONS cell.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* the car of this CONS cell
|
|
||||||
*/
|
|
||||||
public SExpression getCar() {
|
public SExpression getCar() {
|
||||||
return car;
|
return car;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the cdr of this CONS cell.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* the cdr of this CONS cell
|
|
||||||
*/
|
|
||||||
public SExpression getCdr() {
|
public SExpression getCdr() {
|
||||||
return cdr;
|
return cdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the car of this CONS cell to the specified value.
|
|
||||||
*
|
|
||||||
* @param newCar
|
|
||||||
* the value to assign to the car of this CONS cell
|
|
||||||
*/
|
|
||||||
public void setCar(SExpression newCar) {
|
public void setCar(SExpression newCar) {
|
||||||
car = newCar;
|
car = newCar;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the cdr of this CONS cell to the specified value.
|
|
||||||
*
|
|
||||||
* @param newCdr
|
|
||||||
* the value to assign to the cdr of this CONS cell
|
|
||||||
*/
|
|
||||||
public void setCdr(SExpression newCdr) {
|
public void setCdr(SExpression newCdr) {
|
||||||
cdr = newCdr;
|
cdr = newCdr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a CONS cell.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>true</code>
|
|
||||||
*/
|
|
||||||
public boolean consp() {
|
public boolean consp() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of this CONS cell.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* a string representation of this CONS cell
|
|
||||||
*/
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return ("(" + toStringAux());
|
return ("(" + toStringAux());
|
||||||
}
|
}
|
||||||
|
@ -94,17 +41,12 @@ public class Cons extends SExpression {
|
||||||
// this method. When used in conjunction with the 'toString' method of this
|
// this method. When used in conjunction with the 'toString' method of this
|
||||||
// class, this method provides a means for creating the correct string
|
// class, this method provides a means for creating the correct string
|
||||||
// representation of a list.
|
// representation of a list.
|
||||||
//
|
|
||||||
// Returns: a string representation of the car of a CONS cell followed by
|
|
||||||
// its cdr
|
|
||||||
private String toStringAux() {
|
private String toStringAux() {
|
||||||
if (cdr.nullp()) {
|
if (cdr.nullp())
|
||||||
return (car.toString() + ")");
|
return (car.toString() + ")");
|
||||||
} else if (cdr.consp()) {
|
else if (cdr.consp())
|
||||||
return (car.toString() + " " + ((Cons) cdr).toStringAux());
|
return (car.toString() + " " + ((Cons) cdr).toStringAux());
|
||||||
}
|
|
||||||
|
|
||||||
// the cdr of this CONS cell is not a list
|
|
||||||
return (car.toString() + " . " + cdr.toString() + ")");
|
return (car.toString() + " . " + cdr.toString() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,65 +1,29 @@
|
||||||
/*
|
|
||||||
* Name: Mike Cifelli
|
|
||||||
* Course: CIS 443 - Programming Languages
|
|
||||||
* Assignment: Lisp Parser
|
|
||||||
*/
|
|
||||||
|
|
||||||
package sexpression;
|
package sexpression;
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents a NUMBER in the PL-Lisp implementation.
|
|
||||||
*/
|
|
||||||
public class LispNumber extends Atom {
|
public class LispNumber extends Atom {
|
||||||
|
|
||||||
private int value;
|
private int value;
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new NUMBER with the specified text.
|
|
||||||
*
|
|
||||||
* @param text
|
|
||||||
* the text representing this NUMBER
|
|
||||||
* @throws IllegalArgumentException
|
|
||||||
* Indicates that <code>text</code> does not represent a valid integer.
|
|
||||||
*/
|
|
||||||
public LispNumber(String text) {
|
public LispNumber(String text) {
|
||||||
super(text.replaceFirst("^0+(?!$)", ""));
|
super(text.replaceFirst("^0+(?!$)", ""));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.value = Integer.parseInt(text);
|
this.value = Integer.parseInt(text);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
throw new IllegalArgumentException(text +
|
throw new IllegalArgumentException(text + " is not a valid integer");
|
||||||
" is not a valid integer");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new NUMBER with the specified value.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* the integer value of this NUMBER
|
|
||||||
*/
|
|
||||||
public LispNumber(int value) {
|
public LispNumber(int value) {
|
||||||
super(Integer.toString(value));
|
super(Integer.toString(value));
|
||||||
|
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a NUMBER.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>true</code>
|
|
||||||
*/
|
|
||||||
public boolean numberp() {
|
public boolean numberp() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the integer value of this NUMBER.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* the integer value of this NUMBER
|
|
||||||
*/
|
|
||||||
public int getValue() {
|
public int getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,11 @@
|
||||||
/*
|
|
||||||
* Name: Mike Cifelli
|
|
||||||
* Course: CIS 443 - Programming Languages
|
|
||||||
* Assignment: Lisp Parser
|
|
||||||
*/
|
|
||||||
|
|
||||||
package sexpression;
|
package sexpression;
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents a STRING in the PL-Lisp implementation.
|
|
||||||
*/
|
|
||||||
public class LispString extends Atom {
|
public class LispString extends Atom {
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new STRING with the specified text.
|
|
||||||
*
|
|
||||||
* @param text
|
|
||||||
* the text representing this STRING
|
|
||||||
*/
|
|
||||||
public LispString(String text) {
|
public LispString(String text) {
|
||||||
super(text);
|
super(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a STRING.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>true</code>
|
|
||||||
*/
|
|
||||||
public boolean stringp() {
|
public boolean stringp() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,102 +1,48 @@
|
||||||
/*
|
|
||||||
* Name: Mike Cifelli
|
|
||||||
* Course: CIS 443 - Programming Languages
|
|
||||||
* Assignment: Lisp Parser
|
|
||||||
*/
|
|
||||||
|
|
||||||
package sexpression;
|
package sexpression;
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents NIL in the PL-Lisp implementation.
|
|
||||||
*/
|
|
||||||
public class Nil extends Cons {
|
public class Nil extends Cons {
|
||||||
|
|
||||||
private static Nil uniqueInstance = new Nil();
|
private static Nil uniqueInstance = new Nil();
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the single unique instance of NIL.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* the single unique instance of NIL
|
|
||||||
*/
|
|
||||||
public static Nil getUniqueInstance() {
|
public static Nil getUniqueInstance() {
|
||||||
return uniqueInstance;
|
return uniqueInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are using the Singleton pattern, so the constructor for 'Nil' is
|
|
||||||
// private.
|
|
||||||
private Nil() {
|
private Nil() {
|
||||||
super(null, null);
|
super(null, null);
|
||||||
|
|
||||||
// the car and cdr of NIL both refer to NIL
|
|
||||||
super.setCar(this);
|
super.setCar(this);
|
||||||
super.setCdr(this);
|
super.setCdr(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is NULL.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>true</code>
|
|
||||||
*/
|
|
||||||
public boolean nullp() {
|
public boolean nullp() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is an ATOM.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>true</code>
|
|
||||||
*/
|
|
||||||
public boolean atomp() {
|
public boolean atomp() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a CONS cell.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>false</code>
|
|
||||||
*/
|
|
||||||
public boolean consp() {
|
public boolean consp() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a SYMBOL.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>true</code>
|
|
||||||
*/
|
|
||||||
public boolean symbolp() {
|
public boolean symbolp() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the car of this CONS cell to the specified value. This method does
|
* Set the car of this CONS cell to the specified value. This method does nothing (the car of
|
||||||
* nothing (the car of NIL can not be changed).
|
* NIL can not be changed).
|
||||||
*
|
|
||||||
* @param newCar
|
|
||||||
* the value to assign to the car of this CONS cell
|
|
||||||
*/
|
*/
|
||||||
public void setCar(SExpression newCar) {}
|
public void setCar(SExpression newCar) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the cdr of this CONS cell to the specified value. This method does
|
* Set the cdr of this CONS cell to the specified value. This method does nothing (the cdr of
|
||||||
* nothing (the cdr of NIL can not be changed).
|
* NIL can not be changed).
|
||||||
*
|
|
||||||
* @param newCdr
|
|
||||||
* the value to assign to the cdr of this CONS cell
|
|
||||||
*/
|
*/
|
||||||
public void setCdr(SExpression newCdr) {}
|
public void setCdr(SExpression newCdr) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of NIL.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* a string representation of NIL
|
|
||||||
*/
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "NIL";
|
return "NIL";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,120 +1,49 @@
|
||||||
/*
|
|
||||||
* Name: Mike Cifelli
|
|
||||||
* Course: CIS 443 - Programming Languages
|
|
||||||
* Assignment: Lisp Parser
|
|
||||||
*/
|
|
||||||
|
|
||||||
package sexpression;
|
package sexpression;
|
||||||
|
|
||||||
/**
|
public abstract class SExpression {
|
||||||
* This is the base class for memory in the PL-Lisp implementation.
|
|
||||||
*/
|
|
||||||
public class SExpression {
|
|
||||||
|
|
||||||
// for mark and sweep garbage collection
|
// for mark and sweep garbage collection
|
||||||
private boolean marked = false;
|
private boolean marked = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if this <code>SExpression</code> is marked.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>true</code> if this <code>SExpression</code> is marked;
|
|
||||||
* <code>false</code> otherwise
|
|
||||||
*/
|
|
||||||
public final boolean isMarked() {
|
public final boolean isMarked() {
|
||||||
return marked;
|
return marked;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the marked status of this S-expression to the specified value.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* the value to assign to this S-expression's marked status
|
|
||||||
*/
|
|
||||||
public final void setMarked(final boolean value) {
|
public final void setMarked(final boolean value) {
|
||||||
marked = value;
|
marked = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lisp type predicates;
|
// Lisp type predicates...
|
||||||
// by default, all return false (an SExpression effectively has NO type);
|
|
||||||
// overridden in subclasses to describe their Lisp type
|
// overridden in subclasses to describe their Lisp type
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is NULL.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>false</code>
|
|
||||||
*/
|
|
||||||
public boolean nullp() {
|
public boolean nullp() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is an ATOM.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>false</code>
|
|
||||||
*/
|
|
||||||
public boolean atomp() {
|
public boolean atomp() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a CONS cell.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>false</code>
|
|
||||||
*/
|
|
||||||
public boolean consp() {
|
public boolean consp() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a LIST.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* the value of <code>(consp() || nullp())</code>
|
|
||||||
*/
|
|
||||||
public boolean listp() {
|
public boolean listp() {
|
||||||
return (consp() || nullp());
|
return (consp() || nullp());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a NUMBER.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>false</code>
|
|
||||||
*/
|
|
||||||
public boolean numberp() {
|
public boolean numberp() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a SYMBOL.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>false</code>
|
|
||||||
*/
|
|
||||||
public boolean symbolp() {
|
public boolean symbolp() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a FUNCTION.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>false</code>
|
|
||||||
*/
|
|
||||||
public boolean functionp() {
|
public boolean functionp() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a STRING.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>false</code>
|
|
||||||
*/
|
|
||||||
public boolean stringp() {
|
public boolean stringp() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,17 @@
|
||||||
/*
|
|
||||||
* Name: Mike Cifelli
|
|
||||||
* Course: CIS 443 - Programming Languages
|
|
||||||
* Assignment: Lisp Parser
|
|
||||||
*/
|
|
||||||
|
|
||||||
package sexpression;
|
package sexpression;
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents a SYMBOL in the PL-Lisp implementation.
|
|
||||||
*/
|
|
||||||
public class Symbol extends Atom {
|
public class Symbol extends Atom {
|
||||||
|
|
||||||
/** This SYMBOL represents TRUE in the PL-Lisp implementation. */
|
|
||||||
public static final Symbol T = new Symbol("T");
|
public static final Symbol T = new Symbol("T");
|
||||||
|
|
||||||
|
public static Symbol createQuote() {
|
||||||
|
return new Symbol("QUOTE");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new SYMBOL with the specified text.
|
|
||||||
*
|
|
||||||
* @param text
|
|
||||||
* the text representing this SYMBOL
|
|
||||||
*/
|
|
||||||
public Symbol(String text) {
|
public Symbol(String text) {
|
||||||
super(text.toUpperCase());
|
super(text.toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if this S-expression is a SYMBOL.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* <code>true</code>
|
|
||||||
*/
|
|
||||||
public boolean symbolp() {
|
public boolean symbolp() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class Eof extends Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SExpression sExpr(Supplier<Token> getNextToken) {
|
public SExpression parseSExpression(Supplier<Token> getNextToken) {
|
||||||
throw new EofEncounteredException(this);
|
throw new EofEncounteredException(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class Identifier extends Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SExpression sExpr(Supplier<Token> getNextToken) {
|
public SExpression parseSExpression(Supplier<Token> getNextToken) {
|
||||||
return new Symbol(getText());
|
return new Symbol(getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,10 @@ public class LeftParenthesis extends Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SExpression sExpr(Supplier<Token> getNextToken) {
|
public SExpression parseSExpression(Supplier<Token> getNextToken) {
|
||||||
Token nextToken = getNextToken.get();
|
Token nextToken = getNextToken.get();
|
||||||
|
|
||||||
return nextToken.sExprTail(getNextToken);
|
return nextToken.parseSExpressionTail(getNextToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class Number extends Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SExpression sExpr(Supplier<Token> getNextToken) {
|
public SExpression parseSExpression(Supplier<Token> getNextToken) {
|
||||||
return new LispNumber(getText());
|
return new LispNumber(getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,11 @@ public class QuoteMark extends Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SExpression sExpr(Supplier<Token> getNextToken) {
|
public SExpression parseSExpression(Supplier<Token> getNextToken) {
|
||||||
Token nextToken = getNextToken.get();
|
Token nextToken = getNextToken.get();
|
||||||
SExpression argument = nextToken.sExpr(getNextToken);
|
SExpression argument = nextToken.parseSExpression(getNextToken);
|
||||||
|
|
||||||
return new Cons(new Symbol("QUOTE"), new Cons(argument, Nil.getUniqueInstance()));
|
return new Cons(Symbol.createQuote(), new Cons(argument, Nil.getUniqueInstance()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class QuotedString extends Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SExpression sExpr(Supplier<Token> getNextToken) {
|
public SExpression parseSExpression(Supplier<Token> getNextToken) {
|
||||||
return new LispString(getText());
|
return new LispString(getText());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,12 @@ public class RightParenthesis extends Token {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SExpression sExpr(Supplier<Token> getNextToken) {
|
public SExpression parseSExpression(Supplier<Token> getNextToken) {
|
||||||
throw new StartsWithRightParenthesisException(this);
|
throw new StartsWithRightParenthesisException(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SExpression sExprTail(Supplier<Token> getNextToken) {
|
public SExpression parseSExpressionTail(Supplier<Token> getNextToken) {
|
||||||
return Nil.getUniqueInstance();
|
return Nil.getUniqueInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,16 +35,15 @@ public abstract class Token {
|
||||||
return position.getColumnNumber();
|
return position.getColumnNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
// sExpr ::= NUMBER | IDENTIFIER | STRING | QUOTE_MARK sExpr |
|
// sExpr ::= NUMBER | IDENTIFIER | STRING | QUOTE_MARK sExpr | LEFT_PAREN sExprTail
|
||||||
// LEFT_PAREN sExprTail
|
public abstract SExpression parseSExpression(Supplier<Token> getNextToken);
|
||||||
public abstract SExpression sExpr(Supplier<Token> getNextToken);
|
|
||||||
|
|
||||||
// sExprTail ::= RIGHT_PAREN | sExpr sExprTail
|
// sExprTail ::= RIGHT_PAREN | sExpr sExprTail
|
||||||
public SExpression sExprTail(Supplier<Token> getNextToken) {
|
public SExpression parseSExpressionTail(Supplier<Token> getNextToken) {
|
||||||
SExpression car = sExpr(getNextToken);
|
SExpression car = parseSExpression(getNextToken);
|
||||||
|
|
||||||
Token nextToken = getNextToken.get();
|
Token nextToken = getNextToken.get();
|
||||||
SExpression cdr = nextToken.sExprTail(getNextToken);
|
SExpression cdr = nextToken.parseSExpressionTail(getNextToken);
|
||||||
|
|
||||||
return new Cons(car, cdr);
|
return new Cons(car, cdr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package file;
|
package file;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -20,81 +21,46 @@ public class FilePositionTrackerTester {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertTrackerPositionEquals(FilePosition expectedPosition) {
|
||||||
|
assertTrue(arePositionsEqual(expectedPosition, trackerUnderTest.getCurrentPosition()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean arePositionsEqual(FilePosition position1, FilePosition position2) {
|
||||||
|
return Objects.equals(position1.getFileName(), position2.getFileName())
|
||||||
|
&& Objects.equals(position1.getLineNumber(), position2.getLineNumber())
|
||||||
|
&& Objects.equals(position1.getColumnNumber(), position2.getColumnNumber());
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
trackerUnderTest = new FilePositionTracker(FILE_NAME);
|
trackerUnderTest = new FilePositionTracker(FILE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void filePositionEquality_CorrectlyReturnsTrue() {
|
|
||||||
FilePosition positionOne = createFilePosition(5, 9);
|
|
||||||
FilePosition positionTwo = createFilePosition(5, 9);
|
|
||||||
|
|
||||||
assertTrue(positionOne.isEqual(positionTwo));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void filePositionEquality_CorrectlyReturnsFalseWithDifferentLine() {
|
|
||||||
FilePosition positionOne = createFilePosition(5, 9);
|
|
||||||
FilePosition positionTwo = createFilePosition(8, 9);
|
|
||||||
|
|
||||||
assertFalse(positionOne.isEqual(positionTwo));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void filePositionEquality_CorrectlyReturnsFalseWithDifferentColumn() {
|
|
||||||
FilePosition positionOne = createFilePosition(5, 9);
|
|
||||||
FilePosition positionTwo = createFilePosition(5, 10);
|
|
||||||
|
|
||||||
assertFalse(positionOne.isEqual(positionTwo));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void filePositionEquality_CorrectlyReturnsFalseWithDifferentFileName() {
|
|
||||||
FilePosition positionOne = new FilePosition("FileOne");
|
|
||||||
positionOne.setLineNumber(5);
|
|
||||||
positionOne.setColumnNumber(9);
|
|
||||||
|
|
||||||
FilePosition positionTwo = new FilePosition("FileTwo");
|
|
||||||
positionTwo.setLineNumber(5);
|
|
||||||
positionTwo.setColumnNumber(9);
|
|
||||||
|
|
||||||
assertFalse(positionOne.isEqual(positionTwo));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void noMovement_ReturnsInitialPosition() {
|
public void noMovement_ReturnsInitialPosition() {
|
||||||
FilePosition expectedPosition = createFilePosition(1, 0);
|
assertTrackerPositionEquals(createFilePosition(1, 0));
|
||||||
|
|
||||||
assertTrue(expectedPosition.isEqual(trackerUnderTest.getCurrentPosition()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void advanceOneColumn_ReturnsCorrectPosition() {
|
public void advanceOneColumn_ReturnsCorrectPosition() {
|
||||||
FilePosition expectedPosition = createFilePosition(1, 1);
|
|
||||||
|
|
||||||
trackerUnderTest.incrementColumn();
|
trackerUnderTest.incrementColumn();
|
||||||
|
|
||||||
assertTrue(expectedPosition.isEqual(trackerUnderTest.getCurrentPosition()));
|
assertTrackerPositionEquals(createFilePosition(1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void advanceOneLine_ReturnsCorrectPosition() {
|
public void advanceOneLine_ReturnsCorrectPosition() {
|
||||||
FilePosition expectedPosition = createFilePosition(2, 0);
|
|
||||||
|
|
||||||
trackerUnderTest.incrementLine();
|
trackerUnderTest.incrementLine();
|
||||||
|
|
||||||
assertTrue(expectedPosition.isEqual(trackerUnderTest.getCurrentPosition()));
|
assertTrackerPositionEquals(createFilePosition(2, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void advanceOneLine_ResetsColumn() {
|
public void advanceOneLine_ResetsColumn() {
|
||||||
FilePosition expectedPosition = createFilePosition(2, 0);
|
|
||||||
|
|
||||||
trackerUnderTest.incrementColumn();
|
trackerUnderTest.incrementColumn();
|
||||||
trackerUnderTest.incrementLine();
|
trackerUnderTest.incrementLine();
|
||||||
|
|
||||||
assertTrue(expectedPosition.isEqual(trackerUnderTest.getCurrentPosition()));
|
assertTrackerPositionEquals(createFilePosition(2, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue