-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ecdbdd2
commit b6a2b38
Showing
9 changed files
with
237 additions
and
11 deletions.
There are no files selected for viewing
117 changes: 117 additions & 0 deletions
117
src/main/java/me/predatorray/bud/lisp/evaluator/ConcurrentEvaluator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package me.predatorray.bud.lisp.evaluator; | ||
|
||
import me.predatorray.bud.lisp.lang.BudObject; | ||
import me.predatorray.bud.lisp.lang.Environment; | ||
import me.predatorray.bud.lisp.parser.Expression; | ||
import me.predatorray.bud.lisp.parser.ExpressionVisitorAdapter; | ||
import me.predatorray.bud.lisp.parser.ProcedureCall; | ||
import me.predatorray.bud.lisp.util.ConcurrentUtils; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.ForkJoinPool; | ||
import java.util.concurrent.ForkJoinTask; | ||
import java.util.concurrent.RecursiveTask; | ||
|
||
public class ConcurrentEvaluator implements Evaluator { | ||
|
||
@Override | ||
public BudObject evaluate(Expression expression, Environment environment) { | ||
ForkJoinPool pool = new ForkJoinPool(); | ||
TaskConstructor taskConstructor = new TaskConstructor(environment); | ||
expression.accept(taskConstructor); | ||
ForkJoinTask<BudObject> submitted = pool.submit(taskConstructor.task); | ||
|
||
try { | ||
return ConcurrentUtils.getUninterruptibly(submitted); | ||
} catch (ExecutionException e) { | ||
throw toRuntimeException(e); | ||
} | ||
} | ||
|
||
private static RuntimeException toRuntimeException(ExecutionException e) { | ||
Throwable cause = e.getCause(); | ||
if (cause instanceof RuntimeException) { | ||
throw ((RuntimeException) cause); | ||
} else { | ||
throw new EvaluatingException("unknown", cause); | ||
} | ||
} | ||
|
||
private class SimpleEvaluatingTask extends RecursiveTask<BudObject> { | ||
|
||
private final Expression expression; | ||
private final Environment environment; | ||
|
||
SimpleEvaluatingTask(Expression expression, Environment environment) { | ||
this.expression = expression; | ||
this.environment = environment; | ||
} | ||
|
||
@Override | ||
protected BudObject compute() { | ||
return expression.evaluate(environment, ConcurrentEvaluator.this); | ||
} | ||
} | ||
|
||
private class ProcedureCallTask extends RecursiveTask<BudObject> { | ||
|
||
private final ProcedureCall procedureCall; | ||
private final Environment environment; | ||
|
||
ProcedureCallTask(ProcedureCall procedureCall, Environment environment) { | ||
this.procedureCall = procedureCall; | ||
this.environment = environment; | ||
} | ||
|
||
@Override | ||
protected BudObject compute() { | ||
Expression operator = procedureCall.getOperator(); | ||
List<? extends Expression> operands = procedureCall.getOperands(); | ||
int operandSize = operands.size(); | ||
|
||
List<RecursiveTask<BudObject>> tasks = new ArrayList<>(operandSize + 1); | ||
TaskConstructor taskConstructor = new TaskConstructor(environment); | ||
operator.accept(taskConstructor); | ||
tasks.add(taskConstructor.task); | ||
for (Expression operand : operands) { | ||
operand.accept(taskConstructor); | ||
tasks.add(taskConstructor.task); | ||
} | ||
|
||
invokeAll(tasks); | ||
try { | ||
BudObject applicative = ConcurrentUtils.getUninterruptibly(tasks.get(0)); | ||
List<BudObject> arguments = new ArrayList<>(operandSize); | ||
for (int i = 0; i < operandSize; i++) { | ||
arguments.add(ConcurrentUtils.getUninterruptibly(tasks.get(i + 1))); | ||
} | ||
return ProcedureCall.apply(applicative, arguments); | ||
} catch (ExecutionException e) { | ||
throw toRuntimeException(e); | ||
} | ||
} | ||
} | ||
|
||
private class TaskConstructor extends ExpressionVisitorAdapter { | ||
|
||
private final Environment environment; | ||
|
||
RecursiveTask<BudObject> task = null; | ||
|
||
TaskConstructor(Environment environment) { | ||
this.environment = environment; | ||
} | ||
|
||
@Override | ||
public void visit(ProcedureCall procedureCall) { | ||
task = new ProcedureCallTask(procedureCall, environment); | ||
} | ||
|
||
@Override | ||
protected void visitByDefault(final Expression expression) { | ||
task = new SimpleEvaluatingTask(expression, environment); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/main/java/me/predatorray/bud/lisp/util/ConcurrentUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package me.predatorray.bud.lisp.util; | ||
|
||
import java.util.concurrent.ExecutionException; | ||
import java.util.concurrent.Future; | ||
|
||
public class ConcurrentUtils { | ||
|
||
public static <V> V getUninterruptibly(Future<V> future) throws ExecutionException { | ||
boolean interrupted = false; | ||
try { | ||
while (true) { | ||
try { | ||
return future.get(); | ||
} catch (InterruptedException e) { | ||
interrupted = true; | ||
} | ||
} | ||
} finally { | ||
if (interrupted) { | ||
Thread.currentThread().interrupt(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package me.predatorray.bud.lisp.util; | ||
|
||
import org.junit.Test; | ||
|
||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.Set; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
public class SetsTest { | ||
|
||
@Test | ||
public void testAsSet1() { | ||
Object[] objects = new Object [] {new Object(), new Object()}; | ||
Set<Object> set = Sets.asSet(objects); | ||
assertEquals(2, set.size()); | ||
for (Object object : objects) { | ||
assertTrue(set.contains(object)); | ||
} | ||
} | ||
|
||
@Test | ||
public void testAsSet2() { | ||
Set<Object> set = Sets.asSet(); | ||
assertEquals(0, set.size()); | ||
} | ||
|
||
@Test | ||
public void testUnion1() { | ||
Collection<Object> collection1 = Arrays.asList(new Object(), new Object()); | ||
Collection<Object> collection2 = Arrays.asList(new Object(), new Object(), new Object()); | ||
Set<Object> union = Sets.union(collection1, collection2); | ||
assertEquals(5, union.size()); | ||
for (Object o1 : collection1) { | ||
union.contains(o1); | ||
} | ||
for (Object o2 : collection2) { | ||
union.contains(o2); | ||
} | ||
} | ||
} |