From c4329c18957c55ec5a15e82d1b3dc05f58aa708f Mon Sep 17 00:00:00 2001 From: Lucas Werkmeister Date: Mon, 1 Jun 2015 18:58:42 +0200 Subject: [PATCH] Support length-based abbreviation for tuple types A SequencedType can now optionally have an IntegerLiteral type to form a tuple of the given length. The syntax Boolean[8] has been around for a while (even before the Ceylon 1.1 release), but was only recently declared an officially supported feature of the language, part of the specification. See ceylon/ceylon-spec#1041. --- .../core/CeylonExpressionTransformer.ceylon | 5 ++- source/ceylon/ast/core/Editor.ceylon | 2 +- source/ceylon/ast/core/SequentialType.ceylon | 35 +++++++++++++++---- source/ceylon/ast/core/Type.ceylon | 4 +-- .../ast/redhat/RedHatTransformer.ceylon | 3 ++ .../ceylon/ast/redhat/SequentialType.ceylon | 2 +- source/test/ceylon/ast/redhat/BaseType.ceylon | 1 + .../ceylon/ast/redhat/IntegerLiteral.ceylon | 1 + .../ceylon/ast/redhat/SequentialType.ceylon | 8 +++-- 9 files changed, 47 insertions(+), 14 deletions(-) diff --git a/source/ceylon/ast/core/CeylonExpressionTransformer.ceylon b/source/ceylon/ast/core/CeylonExpressionTransformer.ceylon index df9d17be..e3a90e88 100644 --- a/source/ceylon/ast/core/CeylonExpressionTransformer.ceylon +++ b/source/ceylon/ast/core/CeylonExpressionTransformer.ceylon @@ -754,7 +754,10 @@ shared class CeylonExpressionTransformer(String indentLevel = " ") satisfies `` indent + indentLevel ``factor = ``transformWithIndent(that.factor)``; `` indent + indentLevel ``scalable = ``transformWithIndent(that.scalable)``; ``indent``}"; - transformSequentialType(SequentialType that) => "SequentialType(``transformWithIndent(that.elementType)``)"; + transformSequentialType(SequentialType that) + => that.length exists + then "SequentialType(``transformWithIndent(that.elementType)``, ``transformWithIndent(that.length)``)" + else "SequentialType(``transformWithIndent(that.elementType)``)"; transformSmallAsOperation(SmallAsOperation that) => "SmallAsOperation { `` indent + indentLevel ``leftOperand = ``transformWithIndent(that.leftOperand)``; diff --git a/source/ceylon/ast/core/Editor.ceylon b/source/ceylon/ast/core/Editor.ceylon index 51ae74c4..75f220cb 100644 --- a/source/ceylon/ast/core/Editor.ceylon +++ b/source/ceylon/ast/core/Editor.ceylon @@ -733,7 +733,7 @@ shared interface Editor satisfies ImmediateNarrowingTransformer { return ret; } shared actual default SequentialType transformSequentialType(SequentialType that) - => that.copy(transformPrimaryType(that.elementType)); + => that.copy(transformPrimaryType(that.elementType), nullsafeInvoke(that.length, transformIntegerLiteral)); shared actual default SetAssignmentOperation transformSetAssignmentOperation(SetAssignmentOperation that) { assert (is SetAssignmentOperation ret = super.transformSetAssignmentOperation(that)); return ret; diff --git a/source/ceylon/ast/core/SequentialType.ceylon b/source/ceylon/ast/core/SequentialType.ceylon index cdacb49a..ba789a8d 100644 --- a/source/ceylon/ast/core/SequentialType.ceylon +++ b/source/ceylon/ast/core/SequentialType.ceylon @@ -1,22 +1,45 @@ -"A sequential type, that is, a shortcut for `TypeNameWithTypeArguments(UIdentifier(\"Sequential\"), [elementType])`. +"A sequential type, that is, a [[primary type|elementType]], followed by an opening bracket, + optionally an integer [[length]], and a closing bracket. + + If the length is absent, this is a shortcut for `Sequential`; + with the length present, it is a shortcut for a tuple of `length` elements of the element type. Examples: String[] - Integer>[]" -shared class SequentialType(elementType) + Integer>[] + Boolean[2] // shortcut for [Boolean,Boolean]" +shared class SequentialType(elementType, length = null) extends PrimaryType() { "The element type." shared PrimaryType elementType; - shared actual [PrimaryType] children = [elementType]; + shared IntegerLiteral? length; + + shared actual [PrimaryType, IntegerLiteral=] children; + if (exists length) { + children = [elementType, length]; + } else { + children = [elementType]; + } shared actual Result transform(Transformer transformer) => transformer.transformSequentialType(this); shared actual Boolean equals(Object that) { if (is SequentialType that) { + if (exists length) { + if (exists length_ = that.length) { + if (length != length_) { + return false; + } + } else { + return false; + } + } else if (that.length exists) { + return false; + } return elementType == that.elementType; } else { return false; @@ -26,8 +49,8 @@ shared class SequentialType(elementType) shared actual Integer hash => 31 * elementType.hash; - shared SequentialType copy(PrimaryType elementType = this.elementType) { - value ret = SequentialType(elementType); + shared SequentialType copy(PrimaryType elementType = this.elementType, IntegerLiteral? length = this.length) { + value ret = SequentialType(elementType, length); copyExtraInfoTo(ret); return ret; } diff --git a/source/ceylon/ast/core/Type.ceylon b/source/ceylon/ast/core/Type.ceylon index cdc860e9..1979d75b 100644 --- a/source/ceylon/ast/core/Type.ceylon +++ b/source/ceylon/ast/core/Type.ceylon @@ -6,7 +6,7 @@ shared abstract class TypeIsh() of Type | NameWithTypeArguments | VariadicType | DefaultedType | TypeList | SpreadType | TypeArgument | TypeArguments | PackageQualifier extends Node() { - shared actual formal [] children; + shared actual formal [] children; } "Representation of a type." @@ -14,7 +14,7 @@ shared abstract class Type() of MainType | EntryType extends TypeIsh() { - shared actual formal TypeIsh[] children; + shared actual formal [] children; "Tests for equality of two type nodes. diff --git a/source/ceylon/ast/redhat/RedHatTransformer.ceylon b/source/ceylon/ast/redhat/RedHatTransformer.ceylon index 0931fc4c..d1eca45d 100644 --- a/source/ceylon/ast/redhat/RedHatTransformer.ceylon +++ b/source/ceylon/ast/redhat/RedHatTransformer.ceylon @@ -2776,6 +2776,9 @@ shared class RedHatTransformer(TokenFactory tokens) satisfies ImmediateNarrowing JSequenceType ret = JSequenceType(null); ret.elementType = transformPrimaryType(that.elementType); ret.endToken = tokens.token("[", lbracket); // unreachable, but we need to have it in the token stream + if (exists length = that.length) { + ret.length = transformIntegerLiteral(length); + } ret.endToken = tokens.token("]", rbracket); return ret; } diff --git a/source/ceylon/ast/redhat/SequentialType.ceylon b/source/ceylon/ast/redhat/SequentialType.ceylon index c7612f0f..ec761041 100644 --- a/source/ceylon/ast/redhat/SequentialType.ceylon +++ b/source/ceylon/ast/redhat/SequentialType.ceylon @@ -11,7 +11,7 @@ import com.redhat.ceylon.compiler.typechecker.tree { "Converts a RedHat AST [[SequenceType|JSequenceType]] to a `ceylon.ast` [[SequentialType]]." shared SequentialType sequentialTypeToCeylon(JSequenceType sequentialType) { assert (is PrimaryType element = typeToCeylon(sequentialType.elementType)); - return SequentialType(element); + return SequentialType(element, if (exists jLength = sequentialType.length) then integerLiteralToCeylon(jLength) else null); } "Compiles the given [[code]] for a Sequential Type diff --git a/source/test/ceylon/ast/redhat/BaseType.ceylon b/source/test/ceylon/ast/redhat/BaseType.ceylon index b43c427c..3c4f0a4f 100644 --- a/source/test/ceylon/ast/redhat/BaseType.ceylon +++ b/source/test/ceylon/ast/redhat/BaseType.ceylon @@ -66,6 +66,7 @@ shared object baseType satisfies ConcreteTest { shared String->BaseType retType = construct("Ret"); shared String->BaseType argsType = construct("Args"); shared String->BaseType systemObjectType = constructO("system"); + shared String->BaseType booleanType = construct("Boolean"); compile = compileBaseType; fromCeylon = RedHatTransformer.transformBaseType; diff --git a/source/test/ceylon/ast/redhat/IntegerLiteral.ceylon b/source/test/ceylon/ast/redhat/IntegerLiteral.ceylon index 9cc68f14..e2827a5d 100644 --- a/source/test/ceylon/ast/redhat/IntegerLiteral.ceylon +++ b/source/test/ceylon/ast/redhat/IntegerLiteral.ceylon @@ -26,6 +26,7 @@ shared object integerLiteral satisfies ConcreteTestIntegerLiteral oneIntegerLiteral = construct("1"); shared String->IntegerLiteral _0IntegerLiteral = construct("0"); shared String->IntegerLiteral _2IntegerLiteral = construct("2"); + shared String->IntegerLiteral _8IntegerLiteral = construct("8"); compile = compileIntegerLiteral; fromCeylon = RedHatTransformer.transformIntegerLiteral; diff --git a/source/test/ceylon/ast/redhat/SequentialType.ceylon b/source/test/ceylon/ast/redhat/SequentialType.ceylon index ce1f05f4..3018e481 100644 --- a/source/test/ceylon/ast/redhat/SequentialType.ceylon +++ b/source/test/ceylon/ast/redhat/SequentialType.ceylon @@ -1,4 +1,5 @@ import ceylon.ast.core { + IntegerLiteral, PrimaryType, SequentialType } @@ -15,14 +16,15 @@ import com.redhat.ceylon.compiler.typechecker.tree { shared object sequentialType satisfies ConcreteTest { - String->SequentialType construct(String->PrimaryType elem) - => "``elem.key``[]"->SequentialType(elem.item); + String->SequentialType construct(String->PrimaryType elem, IntegerLiteral>? length = null) + => "``elem.key``[`` length?.key else "" ``]"->SequentialType(elem.item, length?.item); shared String->SequentialType stringSequentialType = construct(baseType.stringType); shared String->SequentialType iterableOfStringSequentialType = construct(baseType.iterableOfStringType); + shared String->SequentialType byteSequentialType = construct(baseType.booleanType, integerLiteral._8IntegerLiteral); compile = compileSequentialType; fromCeylon = RedHatTransformer.transformSequentialType; toCeylon = sequentialTypeToCeylon; - codes = [stringSequentialType, iterableOfStringSequentialType]; + codes = [stringSequentialType, iterableOfStringSequentialType, byteSequentialType]; }