Skip to content
Snippets Groups Projects
Commit dd686d49 authored by olale's avatar olale
Browse files

Moved assignment code to clean repository

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 513 additions and 0 deletions
package interpreter.lisp;
public class Conditional extends CompoundExpression {
private Expr condition;
private Expr consequent;
private Expr antecedent;
public Conditional(Expr condition, Expr consequent, Expr antecedent) {
this.condition = condition;
this.consequent = consequent;
this.antecedent = antecedent;
}
public Expr getCondition() {
return condition;
}
public Expr getConsequent() {
return consequent;
}
public Expr getAntecedent() {
return antecedent;
}
@Override
public Expr evaluate(Context context) {
return condition.evaluate(context) == Constants.TRUE ? consequent
.evaluate(context) : antecedent.evaluate(context);
}
}
package interpreter.lisp;
public enum Constants implements Expr {
TRUE, FALSE, EMPTY_LIST;
@Override
public Expr evaluate(Context context) {
return this;
}
}
package interpreter.lisp;
import java.util.HashMap;
public class Context {
public HashMap<Symbol, Expr> bindings = new HashMap<Symbol, Expr>();
private Context parent;
private static Context topLevelContext = new Context();
private static final Context TOP_LEVEL_CONTEXT = topLevelContext;
private Context() {
bindings.put(new Symbol("="), new Eq());
bindings.put(new Symbol("*"), new Mult());
bindings.put(new Symbol("-"), new Sub());
// Add new top level bindings here
}
public Context(Context parent) {
this.parent=parent;
}
public Expr get(Symbol var) {
Expr value = bindings.get(var);
if (value == null && hasParent()) {
value = getParent().get(var);
}
return value;
}
public void put(Symbol key, Expr value) {
bindings.put(key, value);
}
@Override
public String toString() {
return bindings.toString();
}
public void extend(Context context) {
this.parent = context;
}
public Context getParent() {
return parent;
}
public boolean hasParent() {
return parent != null;
}
public static Context getTopLevelContext() {
return TOP_LEVEL_CONTEXT;
}
}
package interpreter.lisp;
public class Eq extends BinaryExpression<Expr> {
@Override
Expr evalBinaryExpression(Expr value1, Expr value2) {
return value1.equals(value2) ? Constants.TRUE : Constants.FALSE;
}
}
package interpreter.lisp;
public interface Expr {
public Expr evaluate(Context context);
}
package interpreter.lisp;
import java.util.List;
public interface Fun {
public abstract List<Symbol> getParameters();
public abstract Expr getBody();
}
\ No newline at end of file
package interpreter.lisp;
import java.util.List;
public class FunctionCall extends CompoundExpression {
private List<Expr> arguments;
private Symbol fn;
public FunctionCall(Symbol fn, List<Expr> subList) {
this.fn = fn;
this.arguments = subList;
}
@Override
public Expr evaluate(Context context) {
Fun definition = (Fun) context.get(fn);
// Add a new stack frame for the function call
Context newContext = new Context(context);
List<Expr> args = this.arguments;
List<Symbol> parameters = definition.getParameters();
int index = 0;
for (Expr expr : args) {
Expr argument = expr.evaluate(context);
newContext.put(parameters.get(index++), argument);
}
return definition.getBody().evaluate(newContext);
}
}
package interpreter.lisp;
public class InterpreterTest {
public static void main(String[] args) {
Expr expr = Reader
.read("(def fac (x) (if (= x 0) 1 (* x (fac (- x 1)))))");
/*
* The expression above is a function definition of the function 'fac'
* with parameter 'x', that calculates the factorial of x.
*
* All expressions are delimited by parentheses, and all 'significant
* names' are listed directly after the opening parenthesis, in prefix
* form (operator first, operands later).
*
* In another programming language (Python), the code above would read
*
* def fac(x):
* if(x == 0):
* 1
* else:
* x * fac(x-1)
*
*
*/
Expr result = expr.evaluate(Context.getTopLevelContext());
Expr expr2 = Reader.read("(fac 5)"); // fac(5) in Python
result = expr2.evaluate(Context.getTopLevelContext());
System.out.println(result);
}
}
package interpreter.lisp;
public class Mult extends BinaryExpression<Num> {
@Override
Expr evalBinaryExpression(Num value1, Num value2) {
return new Num(value1.getValue()*value2.getValue());
}
}
package interpreter.lisp;
import java.text.MessageFormat;
public class Num implements Expr {
private int value;
public Num(int value) {
this.value = value;
}
public int getValue() {
return value;
}
@Override
public String toString() {
return MessageFormat.format("{0}", value);
}
@Override
public Expr evaluate(Context context) {
return this;
}
@Override
public boolean equals(Object obj) {
boolean result = false;
if (obj instanceof Num) {
Num otherNum = (Num) obj;
result = otherNum.getValue() == getValue();
}
return result;
}
@Override
public int hashCode() {
return getValue();
}
}
package interpreter.lisp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Reader {
/**
*
* All expressions are either atomic (numbers, variables) or compound
* expressions (function definitions, conditional if-expressions, function
* calls). This method creates an Expr object from such a string.
*
* @param expression
* @return
*/
public static Expr read(String expression) {
/*
* Replaces parentheses with parentheses surrounded by spaces, to
* enable clean split-on-whitespace functionality
*/
expression = expression.replaceAll("\\(", " ( ").replaceAll("\\)",
" ) ");
List<String> l = new ArrayList<String>();
l.addAll(Arrays.asList(expression.split("\\s+")));
// Trim the list
l.removeAll(Arrays.asList(""));
return read(l);
}
/**
* Create an abstract expression, either a compound term or an atom, from a
* list of tokens
*
* @param arr
* @return
*/
private static Expr read(List<String> arr) {
Expr result = null;
String elt = "";
elt = arr.get(0);
arr.remove(0);
if (elt.equals("(")) {
CompoundExpression compoundNode = new CompoundExpression();
while (!arr.isEmpty() && !arr.get(0).equals(")")) {
compoundNode.add(read(arr));
}
if (!arr.isEmpty()) {
arr.remove(0);
}
result = compoundNode;
} else if (elt.matches("\\d+")) {
result = new Num(Integer.parseInt(elt));
} else {
result = new Symbol(elt);
}
return result;
}
}
package interpreter.lisp;
public class Sub extends BinaryExpression<Num> {
/**
*
* We assume that the operands have been evaluated to Num objects
*
* @see interpreter.lisp.BinaryExpression#evalBinaryExpression(interpreter.lisp.Expr, interpreter.lisp.Expr)
*/
@Override
Expr evalBinaryExpression(Num value1, Num value2) {
return new Num(value1.getValue()-value2.getValue());
}
}
package interpreter.lisp;
import java.text.MessageFormat;
public class Symbol implements Expr {
private String value;
public Symbol(String elt) {
this.value = elt;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return MessageFormat.format("{0}", value);
}
@Override
public Expr evaluate(Context context) {
return context.get(this);
}
@Override
public boolean equals(Object obj) {
return obj.getClass() == Symbol.class && ((Symbol)obj).value.equals(value);
}
@Override
public int hashCode() {
return value.hashCode();
}
}
package interpreter.lisp.test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({ CompoundExpressionTest.class, ReaderTest.class })
public class AllTests {
}
package interpreter.lisp.test;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import interpreter.lisp.CompoundExpression;
import interpreter.lisp.Context;
import interpreter.lisp.Expr;
import interpreter.lisp.Num;
import interpreter.lisp.Reader;
import org.junit.Test;
public class CompoundExpressionTest {
private static final String fac = "(def fac (x) (if (= x 0) 1 (* x (fac (- x 1)))))";
private static final String applyFac = "(fac 5)";
@Test
public void testEvaluateFac() {
Expr definition = Reader.read(fac).evaluate(Context.getTopLevelContext());
assertThat(definition, is(instanceOf(CompoundExpression.class)));
}
@Test
public void testEvaluateApplyFac() {
Reader.read(fac).evaluate(Context.getTopLevelContext());
Expr value = Reader.read(applyFac).evaluate(Context.getTopLevelContext());
assertEquals(new Num(120), value);
}
}
package interpreter.lisp.test;
import static org.junit.Assert.assertEquals;
import interpreter.lisp.CompoundExpression;
import interpreter.lisp.Num;
import interpreter.lisp.Reader;
import interpreter.lisp.Symbol;
import org.junit.Test;
public class ReaderTest {
@Test
public void testReadFunctionDefinition() {
String functionDefinition = "(def fac (x) (if (= x 0) 1 (* x (fac (- x 1)))))";
assertEquals(CompoundExpression.class, Reader.read(functionDefinition).getClass());
}
@Test
public void testReadSimpleExpression() {
assertEquals(new Num(1), Reader.read("1"));
}
@Test
public void testReadVariable() {
assertEquals(new Symbol("x"), Reader.read("x"));
}
}
package polymorphism;
import java.text.MessageFormat;
public class ABaseClass {
public void aMethod(ASubClass x) {
System.out.println(MessageFormat.format(
"ABaseClass.aMethod(ASubClass {0})", x));
}
public void aMethod(ABaseClass x) {
System.out.println(MessageFormat.format(
"ABaseClass.aMethod(ABaseClass {0})", x));
}
@Override
public String toString() {
return "'Base class object'";
}
}
package polymorphism;
import java.text.MessageFormat;
public class ASubClass extends ABaseClass {
public void aMethod(ASubClass x) {
System.out.println(MessageFormat.format(
"ASubClass.aMethod(ASubClass {0})", x));
}
public void aMethod(ABaseClass x) {
System.out.println(MessageFormat.format(
"ASubClass.aMethod(ABaseClass {0})", x));
}
@Override
public String toString() {
return "'Subclass object'";
}
}
package polymorphism;
public class PolymorphismTest {
public static void main(String[] args) {
ABaseClass base = new ABaseClass();
ASubClass sub = new ASubClass();
ABaseClass subAsBase = new ASubClass();
// base.aMethod(sub);
base.aMethod(subAsBase); // The runtime type of subAsBase does not matter here ...
// base.aMethod(base);
// sub.aMethod(sub);
sub.aMethod(subAsBase);
// sub.aMethod(base);
subAsBase.aMethod(sub); // but it matters here. Why?
// subAsBase.aMethod(subAsBase);
// subAsBase.aMethod(base);
}
}
package visitor;
public abstract class AbstractExpression {
public abstract void accept(Visitor v);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment