Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion skiplang/compiler/src/SkipParseTree.sk
Original file line number Diff line number Diff line change
Expand Up @@ -759,12 +759,14 @@ class CatchClauseTree{
}

class ChildClassTree{
extension: ParseTree.ParseTree,
annotations: ParseTree.ParseTree,
name: ParseTree.ParseTree,
constructor: ParseTree.ParseTree,
} extends ParseTree.ParseTree {
fun getNamedFields(): List<(String, ParseTree.ParseTree)> {
List<(String, ParseTree.ParseTree)>[
("extension", this.extension),
("annotations", this.annotations),
("name", this.name),
("constructor", this.constructor),
Expand All @@ -776,6 +778,7 @@ class ChildClassTree{
}

fun getChildren(): mutable Iterator<ParseTree.ParseTree> {
yield this.extension;
yield this.annotations;
yield this.name;
yield this.constructor;
Expand All @@ -785,29 +788,38 @@ class ChildClassTree{
fun transform(
codemod: mutable CodeMod,
): (ParseTree.ParseTree, Vector<Subst>) {
tx_extension = codemod.transform(this.extension);
tx_annotations = codemod.transform(this.annotations);
tx_name = codemod.transform(this.name);
tx_constructor = codemod.transform(this.constructor);
(
ChildClassTree{
range => this.range,
extension => tx_extension.i0,
annotations => tx_annotations.i0,
name => tx_name.i0,
constructor => tx_constructor.i0,
},
Vector[tx_annotations.i1, tx_name.i1, tx_constructor.i1].flatten(),
Vector[
tx_extension.i1,
tx_annotations.i1,
tx_name.i1,
tx_constructor.i1,
].flatten(),
);
}
}

class ChildrenTree{
modifiers: ParseTree.ParseTree,
childrenKeyword: ParseTree.ParseTree,
equal: ParseTree.ParseTree,
bar: ParseTree.ParseTree,
childClasses: ParseTree.ParseTree,
} extends ParseTree.ParseTree {
fun getNamedFields(): List<(String, ParseTree.ParseTree)> {
List<(String, ParseTree.ParseTree)>[
("modifiers", this.modifiers),
("childrenKeyword", this.childrenKeyword),
("equal", this.equal),
("bar", this.bar),
Expand All @@ -820,6 +832,7 @@ class ChildrenTree{
}

fun getChildren(): mutable Iterator<ParseTree.ParseTree> {
yield this.modifiers;
yield this.childrenKeyword;
yield this.equal;
yield this.bar;
Expand All @@ -830,19 +843,22 @@ class ChildrenTree{
fun transform(
codemod: mutable CodeMod,
): (ParseTree.ParseTree, Vector<Subst>) {
tx_modifiers = codemod.transform(this.modifiers);
tx_childrenKeyword = codemod.transform(this.childrenKeyword);
tx_equal = codemod.transform(this.equal);
tx_bar = codemod.transform(this.bar);
tx_childClasses = codemod.transform(this.childClasses);
(
ChildrenTree{
range => this.range,
modifiers => tx_modifiers.i0,
childrenKeyword => tx_childrenKeyword.i0,
equal => tx_equal.i0,
bar => tx_bar.i0,
childClasses => tx_childClasses.i0,
},
Vector[
tx_modifiers.i1,
tx_childrenKeyword.i1,
tx_equal.i1,
tx_bar.i1,
Expand Down
33 changes: 23 additions & 10 deletions skiplang/compiler/src/SkipParser.sk
Original file line number Diff line number Diff line change
Expand Up @@ -1543,9 +1543,10 @@ mutable class SkipParser{
| TokenKind.READONLY()
| TokenKind.UNTRACKED() ->
true
// type constant
// type constant or extension children
| TokenKind.NONTYPE_IDENTIFIER() ->
this.peekPredefinedName(PredefinedName.type)
this.peekPredefinedName(PredefinedName.type) ||
this.peekPredefinedName(PredefinedName.extension)
| _ -> false
}
}
Expand All @@ -1570,6 +1571,8 @@ mutable class SkipParser{
| TokenKind.READONLY()
| TokenKind.UNTRACKED() ->
true
| TokenKind.NONTYPE_IDENTIFIER() ->
this.peekPredefinedName(PredefinedName.extension)
| _ -> false
}
}
Expand Down Expand Up @@ -1603,9 +1606,14 @@ mutable class SkipParser{

// 9.4 Child classes
// child-class:
// annotation-list-opt type-identifier constructor-parameters-opt
// extension-opt annotation-list-opt type-identifier constructor-parameters-opt
mutable fun parseChildClass(): ParseTree {
start = this.mark();
extension = if (this.peekPredefinedName(PredefinedName.extension)) {
this.tokenResult()
} else {
this.createEmptyTreeAfter()
};
annotations = this.parseList(
parser -> parser.peekAnnotation(),
parser -> parser.parseAnnotation(),
Expand All @@ -1614,25 +1622,29 @@ mutable class SkipParser{
constructor = this.parseChildrenConstructorOpt();
ParseTree.ChildClassTree{
range => this.createRange(start),
extension,
annotations,
name,
constructor,
};
}

// children-declaration:
// children = |-opt child-class-list
// extension-opt children = |-opt child-class-list
//
// child-class-list:
// child-class
// child-class-list | child-class
mutable fun parseChildClasses(modifiers: ParseTree): ParseTree {
if (!modifiers.isEmptyList()) {
this.addErrorAtTree(
modifiers,
errorNoModifiersOnChildren,
"Modifiers are not permitted on 'children'",
);
// Only 'extension' modifier is allowed on 'children'
for (modifier in tokenModifiers(modifiers)) {
if (modifier.getTokenString() != PredefinedName.extension) {
this.addErrorAtTree(
modifier,
errorNoModifiersOnChildren,
"Only 'extension' modifier is permitted on 'children'",
);
}
};
childrenKeyword = this.eatTree(TokenKind.CHILDREN());
equal = this.eatTree(TokenKind.EQUAL());
Expand All @@ -1642,6 +1654,7 @@ mutable class SkipParser{
);
ParseTree.ChildrenTree{
range => createRangeOfModifiers(modifiers, childClasses),
modifiers,
childrenKeyword,
equal,
bar,
Expand Down
29 changes: 26 additions & 3 deletions skiplang/compiler/src/convertTree.sk
Original file line number Diff line number Diff line change
Expand Up @@ -2084,10 +2084,19 @@ class Converter{file: FileCache.InputSource} {

fun convertChild(tree: ParseTree): SkipAst.Child {
tree match {
| ParseTree.ChildClassTree{range, annotations, name, constructor} ->
| ParseTree.ChildClassTree{
range,
extension,
annotations,
name,
constructor,
} ->
className = this.convertGlobalName(name);
SkipAst.Child{
chi_range => this.convertRange(range),
chi_extension => if (extension.isEmpty()) None() else {
Some(this.convertRange(extension.range))
},
chi_name => className,
chi_params => this.convertClassParamsOpt(className, constructor),
chi_annotations => this.convertAnnotations(annotations),
Expand All @@ -2110,8 +2119,22 @@ class Converter{file: FileCache.InputSource} {
childrenMembers
.map(childrenList ->
childrenList match {
| ParseTree.ChildrenTree{childClasses} ->
this.convertList(childClasses, this.convertChild)
| ParseTree.ChildrenTree{modifiers, childClasses} ->
blanketExtension = this.convertModifierName(
modifiers,
PredefinedName.extension,
);
converted = this.convertList(childClasses, this.convertChild);
blanketExtension match {
| None() -> converted
| Some(extRange) ->
converted.map(chi ->
chi.chi_extension match {
| Some _ -> chi
| None() -> chi with {chi_extension => Some(extRange)}
}
)
}
| _ -> invariant_violation("Unexpected children")
}
)
Expand Down
14 changes: 12 additions & 2 deletions skiplang/compiler/src/printer.sk
Original file line number Diff line number Diff line change
Expand Up @@ -1334,14 +1334,24 @@ fun printTree(ctx: Context, t: ParseTree): Doc {
]
},
]
| ParseTree.ChildClassTree{annotations, name, constructor} ->
| ParseTree.ChildClassTree{extension, annotations, name, constructor} ->
Doc.Group[
if (extension.isEmpty()) Doc.Empty() else {
Doc.Concat[print(ctx, extension), Doc.space]
},
printModifiers(ctx, annotations),
print(ctx, name),
print(ctx, constructor),
]
| ParseTree.ChildrenTree{childrenKeyword, equal, bar, childClasses} ->
| ParseTree.ChildrenTree{
modifiers,
childrenKeyword,
equal,
bar,
childClasses,
} ->
Doc.Group[
printModifiers(ctx, modifiers),
print(ctx, childrenKeyword),
Doc.space,
print(ctx, equal),
Expand Down
1 change: 1 addition & 0 deletions skiplang/compiler/src/skipAst.sk
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ type Children = List<Child>;

class Child{
chi_range: FileRange,
chi_extension: ?FileRange,
chi_name: Name,
chi_params: ?Class_params,
chi_annotations: SSet,
Expand Down
2 changes: 1 addition & 1 deletion skiplang/compiler/src/skipExpand.sk
Original file line number Diff line number Diff line change
Expand Up @@ -2858,7 +2858,7 @@ fun child(
A.Class_def{
range => chi.chi_range,
depth => -2,
extension => None(),
extension => chi.chi_extension,
native_ => None(),
kind => A.KClass(),
value => None(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello from A
21 changes: 21 additions & 0 deletions skiplang/compiler/tests/expand/extension_children_blanket.sk
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
base class C {
extension children =
| A()
| B()
}

class A {
fun hello(): String {
"Hello from A"
}
}

class B {
fun hello(): String {
"Hello from B"
}
}

fun main(): void {
print_string(A().hello())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello from A
15 changes: 15 additions & 0 deletions skiplang/compiler/tests/expand/extension_children_per_child.sk
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
base class C {
children =
| extension A()
| B()
}

class A {
fun hello(): String {
"Hello from A"
}
}

fun main(): void {
print_string(A().hello())
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
File "tests/syntax/invalid/modifier_children.sk", line 2, characters 3-9:
Modifiers are not permitted on 'children'
Only 'extension' modifier is permitted on 'children'
1 | base class Foo {
2 | private children = A
| ^^^^^^^
Expand Down