Skip to content

Commit

Permalink
Add LetValueList, LetExpression
Browse files Browse the repository at this point in the history
Closes #65.
  • Loading branch information
lucaswerkmeister committed Nov 30, 2014
1 parent 03ff800 commit 4f9ed68
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 13 deletions.
2 changes: 2 additions & 0 deletions source/ceylon/ast/core/CascadingNarrowingTransformer.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ shared interface CascadingNarrowingTransformer<out Result> satisfies NarrowingTr
switch (that)
case (is ValueExpression) { return transformValueExpression(that); }
case (is FunctionExpression) { return transformFunctionExpression(that); }
case (is LetExpression) { return transformLetExpression(that); }
}
shared actual default Result transformExpressionIsh(ExpressionIsh that) {
switch (that)
Expand All @@ -227,6 +228,7 @@ shared interface CascadingNarrowingTransformer<out Result> satisfies NarrowingTr
case (is Subscript) { return transformSubscript(that); }
case (is DecQualifier) { return transformDecQualifier(that); }
case (is AnyMemberOperator) { return transformAnyMemberOperator(that); }
case (is LetValueList) { return transformLetValueList(that); }
}
shared actual default Result transformExpressionStatement(ExpressionStatement that) {
switch (that)
Expand Down
6 changes: 6 additions & 0 deletions source/ceylon/ast/core/CeylonExpressionTransformer.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,12 @@ shared class CeylonExpressionTransformer(String indentLevel = " ") satisfies
`` indent + indentLevel ``specifier = ``transformWithIndent(that.specifier)``;
`` indent + indentLevel ``parameterLists = ``transformWithIndent(that.parameterLists)``;
``indent``}";
transformLetExpression(LetExpression that)
=> "LetExpression {
`` indent + indentLevel ``letValues = ``transformWithIndent(that.letValues)``;
`` indent + indentLevel ``expression = ``transformWithIndent(that.expression)``;
``indent``}";
transformLetValueList(LetValueList that) => "LetValueList(``transformWithIndent(that.letValues)``)";
transformMatchCase(MatchCase that) => "MatchCase(``transformWithIndent(that.expressions)``)";
transformMeasureSubscript(MeasureSubscript that)
=> "MeasureSubscript {
Expand Down
4 changes: 4 additions & 0 deletions source/ceylon/ast/core/Editor.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,10 @@ shared interface Editor satisfies ImmediateNarrowingTransformer<Node> {
=> that.copy(transformLIdentifier(that.name), transformLazySpecifier(that.specifier), that.parameterLists.collect(transformParameters));
shared actual default LazySpecifier transformLazySpecifier(LazySpecifier that)
=> that.copy(transformExpression(that.expression));
shared actual default LetExpression transformLetExpression(LetExpression that)
=> that.copy(transformLetValueList(that.letValues), transformExpression(that.expression));
shared actual default LetValueList transformLetValueList(LetValueList that)
=> that.copy(that.letValues.collect(transformSpecifiedVariable));
shared actual default Literal transformLiteral(Literal that) {
assert (is Literal ret = super.transformLiteral(that));
return ret;
Expand Down
6 changes: 3 additions & 3 deletions source/ceylon/ast/core/Expression.ceylon
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"All node types in the expression sub-hierarchy:
[[Expression]] and some auxiliary node types that aren’t proper Expressions."
shared abstract class ExpressionIsh()
of Expression | TypeIsh | Identifier | FullPackageName | ArgumentList | SpreadArgument | Arguments | NamedArgument | AnySpecifier | Parameters | Bound | Modifier | Body | Comprehension | Subscript | DecQualifier | AnyMemberOperator
of Expression | TypeIsh | Identifier | FullPackageName | ArgumentList | SpreadArgument | Arguments | NamedArgument | AnySpecifier | Parameters | Bound | Modifier | Body | Comprehension | Subscript | DecQualifier | AnyMemberOperator | LetValueList
extends Node() {
shared actual formal <ExpressionIsh|Identifier|Parameter|Declaration|Statement|ComprehensionClause|ExtendedType|SatisfiedTypes>[] children;
shared actual formal <ExpressionIsh|Identifier|Parameter|Declaration|Statement|ComprehensionClause|ExtendedType|SatisfiedTypes|Variable>[] children;
}

"""Abstract superclass of all expression nodes.
Expand Down Expand Up @@ -90,7 +90,7 @@ shared abstract class ExpressionIsh()
- [[ThenElseExpression]]
- [[AssigningExpression]]"""
shared abstract class Expression()
of ValueExpression | FunctionExpression
of ValueExpression | FunctionExpression | LetExpression
extends ExpressionIsh() {
shared actual formal ExpressionIsh[] children;
}
38 changes: 38 additions & 0 deletions source/ceylon/ast/core/LetExpression.ceylon
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"A `let` expression, that is,
the keyword ‘`let`’, followed by a [[list of values|letValues]]
and an [[expression]] that can involve these values.
Examples:
let (dist = sqrt(x^2 + y^2)) [x / dist, y / dist]
let (c = other.a, d = other.b) Complex(a*c - b*d, a*d + b*c)"
shared class LetExpression(letValues, expression)
extends Expression() {

"The values that the `let` expression introduces."
shared LetValueList letValues;
"The expression."
shared Expression expression;

shared actual [LetValueList, Expression] children = [letValues, expression];

shared actual Result transform<out Result>(Transformer<Result> transformer)
=> transformer.transformLetExpression(this);

shared actual Boolean equals(Object that) {
if (is LetExpression that) {
return letValues == that.letValues && expression == that.expression;
} else {
return false;
}
}

shared actual Integer hash
=> 31 * (letValues.hash + 31 * expression.hash);

shared LetExpression copy(LetValueList letValues = this.letValues, Expression expression = this.expression) {
value ret = LetExpression(letValues, expression);
copyExtraInfoTo(ret);
return ret;
}
}
34 changes: 34 additions & 0 deletions source/ceylon/ast/core/LetValueList.ceylon
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"A list of `let` values, enclosed in parentheses.
Examples:
(dist = sqrt(x^2 + y^2))
(c = other.a, d = other.b)"
shared class LetValueList(letValues)
extends ExpressionIsh() {

"The individual values."
shared [SpecifiedVariable+] letValues;

shared actual [SpecifiedVariable+] children = letValues;

shared actual Result transform<out Result>(Transformer<Result> transformer)
=> transformer.transformLetValueList(this);

shared actual Boolean equals(Object that) {
if (is LetValueList that) {
return letValues == that.letValues;
} else {
return false;
}
}

shared actual Integer hash
=> 31 * letValues.hash;

shared LetValueList copy([SpecifiedVariable+] letValues = this.letValues) {
value ret = LetValueList(letValues);
copyExtraInfoTo(ret);
return ret;
}
}
2 changes: 2 additions & 0 deletions source/ceylon/ast/core/Transformer.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ shared interface Transformer<out Result> {
shared formal Result transformLargerOperation(LargerOperation that);
shared formal Result transformLazySpecification(LazySpecification that);
shared formal Result transformLazySpecifier(LazySpecifier that);
shared formal Result transformLetExpression(LetExpression that);
shared formal Result transformLetValueList(LetValueList that);
shared formal Result transformLiteral(Literal that);
shared formal Result transformLocalModifier(LocalModifier that);
shared formal Result transformLogicalAssignmentOperation(LogicalAssignmentOperation that);
Expand Down
4 changes: 4 additions & 0 deletions source/ceylon/ast/core/Visitor.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ shared interface Visitor satisfies WideningTransformer<Anything> {
transformLargerOperation(LargerOperation that) => visitLargerOperation(that);
transformLazySpecification(LazySpecification that) => visitLazySpecification(that);
transformLazySpecifier(LazySpecifier that) => visitLazySpecifier(that);
transformLetExpression(LetExpression that) => visitLetExpression(that);
transformLetValueList(LetValueList that) => visitLetValueList(that);
transformLiteral(Literal that) => visitLiteral(that);
transformLocalModifier(LocalModifier that) => visitLocalModifier(that);
transformLogicalAssignmentOperation(LogicalAssignmentOperation that) => visitLogicalAssignmentOperation(that);
Expand Down Expand Up @@ -460,6 +462,8 @@ shared interface Visitor satisfies WideningTransformer<Anything> {
shared default void visitLazySpecification(LazySpecification that) => super.transformLazySpecification(that);
shared default void visitLazySpecifier(LazySpecifier that) => super.transformLazySpecifier(that);
shared default void visitLIdentifier(LIdentifier that) => super.transformLIdentifier(that);
shared default void visitLetExpression(LetExpression that) => super.transformLetExpression(that);
shared default void visitLetValueList(LetValueList that) => super.transformLetValueList(that);
shared default void visitLiteral(Literal that) => super.transformLiteral(that);
shared default void visitLocalModifier(LocalModifier that) => super.transformLocalModifier(that);
shared default void visitLogicalAssignmentOperation(LogicalAssignmentOperation that) => super.transformLogicalAssignmentOperation(that);
Expand Down
2 changes: 2 additions & 0 deletions source/ceylon/ast/core/WideningTransformer.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ shared interface WideningTransformer<out Result> satisfies Transformer<Result> {
shared actual default Result transformLargerOperation(LargerOperation that) => transformComparisonOperation(that);
shared actual default Result transformLazySpecification(LazySpecification that) => transformSpecification(that);
shared actual default Result transformLazySpecifier(LazySpecifier that) => transformAnySpecifier(that);
shared actual default Result transformLetExpression(LetExpression that) => transformExpression(that);
shared actual default Result transformLetValueList(LetValueList that) => transformExpressionIsh(that);
shared actual default Result transformLiteral(Literal that) => transformNode(that);
shared actual default Result transformLocalModifier(LocalModifier that) => transformTypeModifier(that);
shared actual default Result transformLogicalAssignmentOperation(LogicalAssignmentOperation that) => transformAssignmentOperation(that);
Expand Down
2 changes: 2 additions & 0 deletions source/ceylon/ast/redhat/Expression.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.redhat.ceylon.compiler.typechecker.tree {
Tree {
JExpression=Expression,
JFunctionArgument=FunctionArgument,
JLetExpression=LetExpression,
JOperatorExpression=OperatorExpression,
JPrimary=Primary,
JTerm=Term
Expand All @@ -23,6 +24,7 @@ shared Expression expressionToCeylon(JTerm term) {
}
case (is JOperatorExpression) { return operationToCeylon(term); }
case (is JFunctionArgument) { return functionExpressionToCeylon(term); }
case (is JLetExpression) { return letExpressionToCeylon(term); }
else {
throw AssertionError("Unknown term type!");
}
Expand Down
52 changes: 52 additions & 0 deletions source/ceylon/ast/redhat/LetExpression.ceylon
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import ceylon.ast.core {
LetExpression,
LetValueList,
SpecifiedVariable,
Type,
ValueModifier
}
import com.redhat.ceylon.compiler.typechecker.tree {
Tree {
JLetExpression=LetExpression,
JStaticType=StaticType,
JValueModifier=ValueModifier
}
}
import ceylon.interop.java {
CeylonIterable
}

"Converts a RedHat AST [[LetExpression|JLetExpression]] to a `ceylon.ast` [[LetExpression]]."
shared LetExpression letExpressionToCeylon(JLetExpression letExpression) {
value letClause = letExpression.letClause;
value letValues = CeylonIterable(letClause.variables).collect((jVariable) {
assert (exists jSpecifierExpression = jVariable.specifierExpression);
Type|ValueModifier? type;
assert (is JStaticType|JValueModifier jType = jVariable.type);
switch (jType)
case (is JStaticType) { type = typeToCeylon(jType); }
case (is JValueModifier) {
if (jType.mainToken exists) {
type = valueModifierToCeylon(jType);
} else {
// synthetic ValueModifier
type = null;
}
}
return SpecifiedVariable(lIdentifierToCeylon(jVariable.identifier), specifierToCeylon(jSpecifierExpression), type);
});
"Must have at least one `let` value"
assert (nonempty letValues);
return LetExpression(LetValueList(letValues), expressionToCeylon(letClause.expression));
}

"Compiles the given [[code]] for a Let Expression
into a [[LetExpression]] using the Ceylon compiler
(more specifically, the rule for a `let`)."
shared LetExpression? compileLetExpression(String code) {
if (exists jLet = createParser(code).\ilet()) {
return letExpressionToCeylon(jLet);
} else {
return null;
}
}
47 changes: 38 additions & 9 deletions source/ceylon/ast/redhat/RedHatTransformer.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ import com.redhat.ceylon.compiler.typechecker.tree {
JLargeAsOp=LargeAsOp,
JLargerOp=LargerOp,
JLazySpecifierExpression=LazySpecifierExpression,
JLetClause=LetClause,
JLetExpression=LetExpression,
JListedArgument=ListedArgument,
JLocalModifier=LocalModifier,
JLogicalAssignmentOp=LogicalAssignmentOp,
Expand Down Expand Up @@ -326,6 +328,7 @@ import com.redhat.ceylon.compiler.typechecker.parser {
larger_op=\iLARGER_OP,
lbrace=\iLBRACE,
lbracket=\iLBRACKET,
letType=\iLET,
lidentifier=\iLIDENTIFIER,
lparen=\iLPAREN,
member_op=\iMEMBER_OP,
Expand Down Expand Up @@ -1929,6 +1932,28 @@ shared class RedHatTransformer(TokenFactory tokens) satisfies ImmediateNarrowing
shared actual JIdentifier transformLIdentifier(LIdentifier that)
=> JIdentifier(tokens.token(that.name, lidentifier, that.usePrefix then that.name.size + 2 else that.name.size));

shared actual JLetExpression transformLetExpression(LetExpression that) {
JLetExpression ret = JLetExpression(null);
JLetClause letClause = JLetClause(tokens.token("let", letType));
letClause.endToken = tokens.token("(", lparen);
letClause.addVariable(helpTransformSpecifiedVariable(that.letValues.letValues.first));
for (letValue in that.letValues.letValues.rest) {
letClause.endToken = tokens.token(",", comma);
letClause.addVariable(helpTransformSpecifiedVariable(letValue));
}
letClause.endToken = tokens.token(")", rparen);
letClause.expression = wrapTerm(transformExpression(that.expression));
letClause.endToken = null;
ret.letClause = letClause;
return ret;
}

"The RedHat AST has no direct equivalent of [[LetValueList]];
this method throws."
shared actual Nothing transformLetValueList(LetValueList that) {
throw Exception("LetValueList has no RedHat AST equivalent!");
}

shared actual JLiteral transformLiteral(Literal that) {
assert (is JLiteral ret = super.transformLiteral(that));
return ret;
Expand Down Expand Up @@ -2530,15 +2555,7 @@ shared class RedHatTransformer(TokenFactory tokens) satisfies ImmediateNarrowing
switch (resource)
case (is Expression) { ret.expression = wrapTerm(transformExpression(resource)); }
case (is SpecifiedVariable) {
JVariable var = JVariable(null);
value type = resource.type;
switch (type)
case (is Type) { var.type = transformType(type); }
case (is ValueModifier) { var.type = transformValueModifier(type); }
case (null) { var.type = JValueModifier(null); }
var.identifier = transformLIdentifier(resource.name);
var.specifierExpression = transformSpecifier(resource.specifier);
ret.variable = var;
ret.variable = helpTransformSpecifiedVariable(resource);
}
return ret;
}
Expand Down Expand Up @@ -3449,6 +3466,18 @@ shared class RedHatTransformer(TokenFactory tokens) satisfies ImmediateNarrowing
ret.endToken = tokens.token("`", backtick);
}

JVariable helpTransformSpecifiedVariable(SpecifiedVariable resource) {
JVariable var = JVariable(null);
value type = resource.type;
switch (type)
case (is Type) { var.type = transformType(type); }
case (is ValueModifier) { var.type = transformValueModifier(type); }
case (null) { var.type = JValueModifier(null); }
var.identifier = transformLIdentifier(resource.name);
var.specifierExpression = transformSpecifier(resource.specifier);
return var;
}

JExpression wrapTerm(JTerm term) {
value expression = JExpression(null);
expression.term = term;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ import ceylon.ast.core {
LargerOperation,
LazySpecification,
LazySpecifier,
LetExpression,
LetValueList,
LIdentifier,
MatchCase,
MeasureOperation,
Expand Down Expand Up @@ -546,7 +548,16 @@ shared CompilationUnit completeCompilationUnit
};
clause = IfComprehensionClause {
conditions = Conditions([BooleanCondition(BaseExpression(MemberNameWithTypeArguments(LIdentifier("c"))))]);
clause = ExpressionComprehensionClause(BaseExpression(MemberNameWithTypeArguments(LIdentifier("v"))));
clause = ExpressionComprehensionClause(LetExpression {
letValues = LetValueList([
SpecifiedVariable {
name = LIdentifier("w");
specifier = Specifier(BaseExpression(MemberNameWithTypeArguments(LIdentifier("v"))));
type = null;
}
]);
expression = BaseExpression(MemberNameWithTypeArguments(LIdentifier("w")));
});
};
});
}));
Expand Down

0 comments on commit 4f9ed68

Please sign in to comment.