Skip to content

Commit

Permalink
Merge PR #176: Implement message cascade
Browse files Browse the repository at this point in the history
  • Loading branch information
smarr committed Jul 26, 2017
2 parents 00f1fe9 + 793eb6b commit 3551a94
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 8 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ the specifications are as follows:

- local variables in methods do not yet support the full slotDeclartion style

- as in SOM method chains are not supported

- as in SOM, blocks can only have 3 arguments (counting `self`)

Obtaining and Running SOMns
Expand Down
57 changes: 57 additions & 0 deletions core-lib/TestSuite/LanguageTests.som
Original file line number Diff line number Diff line change
Expand Up @@ -739,4 +739,61 @@ class LanguageTests usingPlatform: platform testFramework: minitest = Value (
assert: o is: self.
)
) : ( TEST_CONTEXT = () )
public class MessageCascades = TestContext ()(
class Cnt = (| public v ::= 0. |)(
public inc = ( v:: v + 1 )
)
class Setters = (|
public slot1
public slot2
|)(
public runCascadeForEffect = (
self slot1: 23;
slot2: 42
)
public runCascadeForValue = (
^ self slot1;
slot2
)
)
public testCascadeOnFieldRead = (
| c = Cnt new. |
assert: c v equals: 0.
c inc; inc; inc.
assert: c v equals: 3.
)
public testCascadeOnMultipleSends = (
| c = Cnt new. |
assert: c v equals: 0.
c inc inc inc;
inc;
inc;
inc.
assert: c v equals: 6.
)
public testKeywordCascade = (
| arr = Array new: 3. |
arr at: 1 put: 2;
at: 2 put: 3;
at: 3 put: 4.
assert: (arr at: 1) equals: 2.
assert: (arr at: 2) equals: 3.
assert: (arr at: 3) equals: 4.
)
public testSetter = (
| setter = Setters new. |
setter runCascadeForEffect.
assert: setter slot1 equals: 23.
assert: setter slot2 equals: 42.
assert: setter runCascadeForValue equals: 42.
)
) : ( TEST_CONTEXT = () )
)
2 changes: 2 additions & 0 deletions src/som/compiler/Lexer.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ private Symbol doSym() {
} else if (currentChar() == '*' && nextChar() == ')') {
state.incPtr(2);
state.set(Symbol.EndComment, '\0', "*)");
} else if (currentChar() == ';') {
match(Symbol.Semicolon);
} else if (currentChar() == ')') {
match(Symbol.EndTerm);
} else if (currentChar() == '#') {
Expand Down
7 changes: 7 additions & 0 deletions src/som/compiler/MethodBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ public final class MethodBuilder {

private final List<SInvokable> embeddedBlockMethods;

private int cascadeId;


public MethodBuilder(final MixinBuilder holder, final MixinScope clsScope) {
this(holder, clsScope, null, false, holder.getLanguage());
Expand Down Expand Up @@ -339,6 +341,11 @@ public void addArgument(final String arg, final SourceSection source) {
arguments.put(arg, argument);
}

public Local addMessageCascadeTemp(final SourceSection source) throws MethodDefinitionError {
cascadeId += 1;
return addLocal("$cascadeTmp" + cascadeId, true, source);
}

public Local addLocal(final String name, final boolean immutable,
final SourceSection source) throws MethodDefinitionError {
if (arguments.containsKey(name)) {
Expand Down
62 changes: 57 additions & 5 deletions src/som/compiler/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import static som.compiler.Symbol.Pound;
import static som.compiler.Symbol.RCurly;
import static som.compiler.Symbol.STString;
import static som.compiler.Symbol.Semicolon;
import static som.compiler.Symbol.SlotMutableAssign;
import static som.compiler.Symbol.Star;
import static som.interpreter.SNodeFactory.createImplicitReceiverSend;
Expand Down Expand Up @@ -408,7 +409,7 @@ private void mixinApplication(final MixinBuilder mxnBuilder, final int mixinId)
if (sym != NewTerm && sym != MixinOperator && sym != Period) {
mixinFactorySend = (AbstractUninitializedMessageSendNode) messages(
mxnBuilder.getInitializerMethodBuilder(),
mxnBuilder.getInitializerMethodBuilder().getSelfRead(getSource(coord)));
new ExpressionNode[] {mxnBuilder.getInitializerMethodBuilder().getSelfRead(getSource(coord))});

uniqueInitName = MixinBuilder.getInitializerName(
mixinFactorySend.getSelector(), mixinId);
Expand Down Expand Up @@ -439,7 +440,7 @@ private void inheritanceClause(final MixinBuilder mxnBuilder)
// used to create the proper initialize method, on which we rely here.
ExpressionNode superFactorySend = messages(
mxnBuilder.getInitializerMethodBuilder(),
mxnBuilder.getInitializerMethodBuilder().getSuperReadNode(getEmptySource()));
new ExpressionNode[] {mxnBuilder.getInitializerMethodBuilder().getSuperReadNode(getEmptySource())});

SSymbol initializerName = MixinBuilder.getInitializerName(
((AbstractUninitializedMessageSendNode) superFactorySend).getSelector());
Expand Down Expand Up @@ -1044,12 +1045,59 @@ private ExpressionNode evaluation(final MethodBuilder builder)
} else {
exp = primary(builder);
}

if (symIsMessageSend()) {
exp = messages(builder, exp);
SourceCoordinate coord = getCoordinate();
ExpressionNode[] lastReceiver = new ExpressionNode[] {exp};

exp = messages(builder, lastReceiver);

if (sym == Semicolon) {
exp = msgCascade(exp, lastReceiver[0], builder, coord);
}
}
return exp;
}

private ExpressionNode msgCascade(final ExpressionNode nonEmptyMessage,
final ExpressionNode lastReceiver, final MethodBuilder builder,
final SourceCoordinate coord) throws ProgramDefinitionError {
List<ExpressionNode> cascade = new ArrayList<>();
SourceSection tmpSource = getSource(coord);

nonEmptyMessage.adoptChildren();

// first, create a temp variable, to which the result of the receiver is
// written, and then replace receiver use with reads from temp
Local tmp = builder.addMessageCascadeTemp(tmpSource);

// evaluate last receiver, and write value to temp
cascade.add(tmp.getWriteNode(0, lastReceiver, tmpSource));

// replace receiver with read from temp
lastReceiver.replace(tmp.getReadNode(0, tmpSource));

// add the initial message of the cascade, it is now send to the temp read
cascade.add(nonEmptyMessage);

while (sym == Semicolon) {
expect(Semicolon, KeywordTag.class);

ExpressionNode exp;
if (sym == Keyword) {
exp = keywordMessage(builder, tmp.getReadNode(0, tmpSource), false, false, null);
} else if (sym == OperatorSequence || symIn(binaryOpSyms)) {
exp = binaryMessage(builder, tmp.getReadNode(0, tmpSource), false, null);
} else {
assert sym == Identifier;
exp = unaryMessage(tmp.getReadNode(0, tmpSource), false, null);
}
cascade.add(exp);
}

return createSequence(cascade, getSource(coord));
}

private boolean symIsMessageSend() {
return sym == Identifier || sym == Keyword || sym == OperatorSequence
|| symIn(binaryOpSyms) || sym == EventualSend;
Expand Down Expand Up @@ -1148,8 +1196,9 @@ protected ExpressionNode binaryConsecutiveMessages(
}

private ExpressionNode messages(final MethodBuilder builder,
final ExpressionNode receiver) throws ProgramDefinitionError {
ExpressionNode msg = receiver;
final ExpressionNode[] lastReceiver) throws ProgramDefinitionError {
ExpressionNode msg = lastReceiver[0];

SourceCoordinate coord = getCoordinate();
boolean eventualSend = accept(EventualSend, KeywordTag.class);

Expand All @@ -1159,6 +1208,7 @@ private ExpressionNode messages(final MethodBuilder builder,
}

while (sym == Identifier) {
lastReceiver[0] = msg;
msg = unaryMessage(msg, eventualSend, sendOp);
eventualSend = accept(EventualSend, KeywordTag.class);
if (eventualSend) {
Expand All @@ -1167,6 +1217,7 @@ private ExpressionNode messages(final MethodBuilder builder,
}

if (sym == OperatorSequence || symIn(binaryOpSyms)) {
lastReceiver[0] = msg;
msg = binaryConsecutiveMessages(builder, msg, eventualSend, sendOp);
eventualSend = accept(EventualSend, KeywordTag.class);
if (eventualSend) {
Expand All @@ -1175,6 +1226,7 @@ private ExpressionNode messages(final MethodBuilder builder,
}

if (sym == Keyword) {
lastReceiver[0] = msg;
msg = keywordMessage(builder, msg, true, eventualSend, sendOp);
}

Expand Down
2 changes: 1 addition & 1 deletion src/som/compiler/Symbol.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

enum Symbol {
NONE, Numeral, Not, And, Or, Star, Div, Mod, Plus, Minus, Equal, More, Less,
Comma, At, Per, NewBlock, EndBlock, LCurly, RCurly, Colon, Period, Exit, NewTerm,
Comma, At, Per, NewBlock, EndBlock, LCurly, RCurly, Colon, Semicolon, Period, Exit, NewTerm,
EndTerm, Pound, STString,
BeginComment, EndComment, SlotMutableAssign, EventualSend, MixinOperator,
Identifier, Keyword, SetterKeyword,
Expand Down

0 comments on commit 3551a94

Please sign in to comment.