From 6f16fd56840f96e938bd3fa55b9c6d68b5cc1077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Koz=C5=82owski?= Date: Sat, 2 Nov 2024 03:40:51 +0100 Subject: [PATCH] Improvements for more coverage --- .../playground/parsergen/ParserGen.scala | 47 +++++++++++++++---- .../playground/generated/nodes/Binding.scala | 10 ++-- .../playground/generated/nodes/Bindings.scala | 2 +- .../playground/generated/nodes/Boolean_.scala | 2 +- .../playground/generated/nodes/Comment.scala | 2 +- .../generated/nodes/Identifier.scala | 2 +- .../generated/nodes/Let_binding.scala | 2 +- .../playground/generated/nodes/List_.scala | 6 ++- .../generated/nodes/List_fields.scala | 2 +- .../playground/generated/nodes/Null_.scala | 2 +- .../playground/generated/nodes/Number.scala | 2 +- .../generated/nodes/Operation_call.scala | 10 ++-- .../generated/nodes/Operation_name.scala | 6 ++- .../nodes/Qualified_identifier.scala | 10 ++-- .../generated/nodes/Source_file.scala | 10 ++-- .../playground/generated/nodes/String_.scala | 2 +- .../playground/generated/nodes/Struct.scala | 6 ++- .../generated/nodes/Top_level_statement.scala | 2 +- .../generated/nodes/Use_clause.scala | 6 ++- .../generated/nodes/Whitespace.scala | 2 +- .../generated/nodes/_Input_node.scala | 11 ++++- .../parser/ParserTreeSitterDemo.scala | 2 +- .../smithyql/parser/demo.worksheet.sc | 4 +- 23 files changed, 108 insertions(+), 42 deletions(-) diff --git a/modules/parser-gen/src/main/scala/playground/parsergen/ParserGen.scala b/modules/parser-gen/src/main/scala/playground/parsergen/ParserGen.scala index 27440cc8..bf5a01fd 100644 --- a/modules/parser-gen/src/main/scala/playground/parsergen/ParserGen.scala +++ b/modules/parser-gen/src/main/scala/playground/parsergen/ParserGen.scala @@ -6,6 +6,7 @@ import org.polyvariant.treesitter4s.Node import smithy4s.Blob import smithy4s.Document import smithy4s.json.Json +import treesittersmithy.FieldName import treesittersmithy.NodeType import treesittersmithy.NodeTypes import treesittersmithy.TypeName @@ -13,6 +14,7 @@ import util.chaining.* import java.nio.file.Files import java.nio.file.Paths +import scala.annotation.targetName import scala.jdk.CollectionConverters.* import scala.meta.Dialect @@ -24,10 +26,16 @@ def debugDump(s: String): String = "" extension (tn: TypeName) { + @targetName("renderTypeName") def render: String = tn.value.smartCapitalize.ident def asEnumCase: TypeName = TypeName(tn.value + "Case") } +extension (fn: FieldName) { + @targetName("renderFieldName") + def render: String = fn.value.ident +} + extension (tpe: NodeType) { def render: String = @@ -52,7 +60,7 @@ def renderAdt(tpe: NodeType) = { |enum $name { |${enumCases.mkString_("\n").indentTrim(2)} | - | def asNode: Node = this match { + | def node: Node = this match { |${tpe .subtypes .map { nodeType => @@ -75,6 +83,18 @@ def renderAdt(tpe: NodeType) = { .mkString_("\n") .indentTrim(4)} | } + | + | def unapply(node: Node): Boolean = node match { + |${tpe + .subtypes + .map { nodeType => + show"""case node @ ${nodeType + .tpe + .render}() => true""" + } + .mkString_("\n") + .indentTrim(4)} + | } |} | |/* @@ -90,12 +110,13 @@ def renderClass(tpe: NodeType) = { .fields .toList .map { (k, fieldType) => - val singleFieldType = fieldType + val typeUnion = fieldType .types .map(tpe => show"${tpe.tpe.render}") - .reduceLeft(_ + " | " + _) + .reduceLeftOption(_ + " | " + _) + .getOrElse(sys.error(s"unexpected empty list of types: $k (in ${tpe.tpe})")) - val fieldTypeAnnotation = singleFieldType.pipe { + val fieldTypeAnnotation = typeUnion.pipe { case s if fieldType.multiple => show"List[$s]" case s => s } @@ -110,9 +131,12 @@ def renderClass(tpe: NodeType) = { |${cases.mkString("\n").indentTrim(2)} |}""".stripMargin else - show"""${singleFieldType}($allFields.head)""" + // todo replace head with a stricter "only" check? + show"""$allFields.head match { + |${cases.mkString("\n").indentTrim(2)} + |}""".stripMargin - show"""def ${k.value}: ${fieldTypeAnnotation} = $fieldValue""" + show"""def ${k.render}: ${fieldTypeAnnotation} = $fieldValue""" } show"""// Generated code! Do not modify by hand. @@ -130,7 +154,7 @@ def renderClass(tpe: NodeType) = { |} | |object $name { - | def unapply(node: Node): scala.Boolean = node.tpe == ${tpe.tpe.value.literal} + | def unapply(node: Node): Boolean = node.tpe == ${tpe.tpe.value.literal} |} | |/* @@ -156,7 +180,14 @@ def renderClass(tpe: NodeType) = { types .filter(_.named) - .map(_.focus(_.fields.each.types).modify(_.filter(_.named))) + .map( + // only render field types that are named + _.focus(_.fields.each.types) + .modify(_.filter(_.named)) + // don't render the field if it has no types + .focus(_.fields) + .modify(_.filter((_, v) => v.types.nonEmpty)) + ) .fproduct( _.render ) diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Binding.scala b/modules/parser/src/main/scala/playground/generated/nodes/Binding.scala index cb267b13..df5f26ae 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Binding.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Binding.scala @@ -5,14 +5,18 @@ import org.polyvariant.treesitter4s.Node case class Binding /* private */(node: Node) extends Node { - def key: Identifier = Identifier(node.fields("key").head) - def value: _Input_node = _Input_node(node.fields("value").head) + def key: Identifier = node.fields("key").head match { + case node @ Identifier() => Identifier(node) + } + def value: _Input_node = node.fields("value").head match { + case node @ _Input_node() => _Input_node(node) + } export node.* } object Binding { - def unapply(node: Node): scala.Boolean = node.tpe == "binding" + def unapply(node: Node): Boolean = node.tpe == "binding" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Bindings.scala b/modules/parser/src/main/scala/playground/generated/nodes/Bindings.scala index 77ca1e46..61156542 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Bindings.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Bindings.scala @@ -11,7 +11,7 @@ case class Bindings /* private */(node: Node) extends Node { } object Bindings { - def unapply(node: Node): scala.Boolean = node.tpe == "bindings" + def unapply(node: Node): Boolean = node.tpe == "bindings" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Boolean_.scala b/modules/parser/src/main/scala/playground/generated/nodes/Boolean_.scala index 8fc52ea7..20e66a50 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Boolean_.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Boolean_.scala @@ -11,7 +11,7 @@ case class Boolean_ /* private */(node: Node) extends Node { } object Boolean_ { - def unapply(node: Node): scala.Boolean = node.tpe == "boolean" + def unapply(node: Node): Boolean = node.tpe == "boolean" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Comment.scala b/modules/parser/src/main/scala/playground/generated/nodes/Comment.scala index 062e860a..64d8aae0 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Comment.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Comment.scala @@ -11,7 +11,7 @@ case class Comment /* private */(node: Node) extends Node { } object Comment { - def unapply(node: Node): scala.Boolean = node.tpe == "comment" + def unapply(node: Node): Boolean = node.tpe == "comment" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Identifier.scala b/modules/parser/src/main/scala/playground/generated/nodes/Identifier.scala index 06e1cf9e..e3fa5e70 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Identifier.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Identifier.scala @@ -11,7 +11,7 @@ case class Identifier /* private */(node: Node) extends Node { } object Identifier { - def unapply(node: Node): scala.Boolean = node.tpe == "identifier" + def unapply(node: Node): Boolean = node.tpe == "identifier" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Let_binding.scala b/modules/parser/src/main/scala/playground/generated/nodes/Let_binding.scala index e18a249f..f92f48bd 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Let_binding.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Let_binding.scala @@ -11,7 +11,7 @@ case class Let_binding /* private */(node: Node) extends Node { } object Let_binding { - def unapply(node: Node): scala.Boolean = node.tpe == "let_binding" + def unapply(node: Node): Boolean = node.tpe == "let_binding" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/List_.scala b/modules/parser/src/main/scala/playground/generated/nodes/List_.scala index 2a31ea3f..755748c5 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/List_.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/List_.scala @@ -5,13 +5,15 @@ import org.polyvariant.treesitter4s.Node case class List_ /* private */(node: Node) extends Node { - def list_fields: List_fields = List_fields(node.fields("list_fields").head) + def list_fields: List_fields = node.fields("list_fields").head match { + case node @ List_fields() => List_fields(node) + } export node.* } object List_ { - def unapply(node: Node): scala.Boolean = node.tpe == "list" + def unapply(node: Node): Boolean = node.tpe == "list" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/List_fields.scala b/modules/parser/src/main/scala/playground/generated/nodes/List_fields.scala index 7923e68a..799bf038 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/List_fields.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/List_fields.scala @@ -11,7 +11,7 @@ case class List_fields /* private */(node: Node) extends Node { } object List_fields { - def unapply(node: Node): scala.Boolean = node.tpe == "list_fields" + def unapply(node: Node): Boolean = node.tpe == "list_fields" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Null_.scala b/modules/parser/src/main/scala/playground/generated/nodes/Null_.scala index 1ab7527c..1d6b39c0 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Null_.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Null_.scala @@ -11,7 +11,7 @@ case class Null_ /* private */(node: Node) extends Node { } object Null_ { - def unapply(node: Node): scala.Boolean = node.tpe == "null" + def unapply(node: Node): Boolean = node.tpe == "null" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Number.scala b/modules/parser/src/main/scala/playground/generated/nodes/Number.scala index 4713a0a8..8cc857ca 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Number.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Number.scala @@ -11,7 +11,7 @@ case class Number /* private */(node: Node) extends Node { } object Number { - def unapply(node: Node): scala.Boolean = node.tpe == "number" + def unapply(node: Node): Boolean = node.tpe == "number" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Operation_call.scala b/modules/parser/src/main/scala/playground/generated/nodes/Operation_call.scala index 57b4f82a..b34f252a 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Operation_call.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Operation_call.scala @@ -5,14 +5,18 @@ import org.polyvariant.treesitter4s.Node case class Operation_call /* private */(node: Node) extends Node { - def input: Struct = Struct(node.fields("input").head) - def operation_name: Operation_name = Operation_name(node.fields("operation_name").head) + def input: Struct = node.fields("input").head match { + case node @ Struct() => Struct(node) + } + def operation_name: Operation_name = node.fields("operation_name").head match { + case node @ Operation_name() => Operation_name(node) + } export node.* } object Operation_call { - def unapply(node: Node): scala.Boolean = node.tpe == "operation_call" + def unapply(node: Node): Boolean = node.tpe == "operation_call" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Operation_name.scala b/modules/parser/src/main/scala/playground/generated/nodes/Operation_name.scala index 9a58e09d..f3a9adfb 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Operation_name.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Operation_name.scala @@ -8,13 +8,15 @@ case class Operation_name /* private */(node: Node) extends Node { def identifier: List[Qualified_identifier] = node.fields("identifier").toList.collect { case node @ Qualified_identifier() => Qualified_identifier(node) } - def name: Identifier = Identifier(node.fields("name").head) + def name: Identifier = node.fields("name").head match { + case node @ Identifier() => Identifier(node) + } export node.* } object Operation_name { - def unapply(node: Node): scala.Boolean = node.tpe == "operation_name" + def unapply(node: Node): Boolean = node.tpe == "operation_name" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Qualified_identifier.scala b/modules/parser/src/main/scala/playground/generated/nodes/Qualified_identifier.scala index 057b5360..5e684301 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Qualified_identifier.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Qualified_identifier.scala @@ -5,8 +5,12 @@ import org.polyvariant.treesitter4s.Node case class Qualified_identifier /* private */(node: Node) extends Node { - def head: Identifier = Identifier(node.fields("head").head) - def selection: Identifier = Identifier(node.fields("selection").head) + def head: Identifier = node.fields("head").head match { + case node @ Identifier() => Identifier(node) + } + def selection: Identifier = node.fields("selection").head match { + case node @ Identifier() => Identifier(node) + } def tail: List[Identifier] = node.fields("tail").toList.collect { case node @ Identifier() => Identifier(node) } @@ -15,7 +19,7 @@ case class Qualified_identifier /* private */(node: Node) extends Node { } object Qualified_identifier { - def unapply(node: Node): scala.Boolean = node.tpe == "qualified_identifier" + def unapply(node: Node): Boolean = node.tpe == "qualified_identifier" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Source_file.scala b/modules/parser/src/main/scala/playground/generated/nodes/Source_file.scala index 19e95f7c..c560a434 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Source_file.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Source_file.scala @@ -5,14 +5,18 @@ import org.polyvariant.treesitter4s.Node case class Source_file /* private */(node: Node) extends Node { - def statements: Top_level_statement = Top_level_statement(node.fields("statements").head) - def use_clause: Use_clause = Use_clause(node.fields("use_clause").head) + def statements: Top_level_statement = node.fields("statements").head match { + case node @ Top_level_statement() => Top_level_statement(node) + } + def use_clause: Use_clause = node.fields("use_clause").head match { + case node @ Use_clause() => Use_clause(node) + } export node.* } object Source_file { - def unapply(node: Node): scala.Boolean = node.tpe == "source_file" + def unapply(node: Node): Boolean = node.tpe == "source_file" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/String_.scala b/modules/parser/src/main/scala/playground/generated/nodes/String_.scala index 69198bcf..b46b7230 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/String_.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/String_.scala @@ -11,7 +11,7 @@ case class String_ /* private */(node: Node) extends Node { } object String_ { - def unapply(node: Node): scala.Boolean = node.tpe == "string" + def unapply(node: Node): Boolean = node.tpe == "string" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Struct.scala b/modules/parser/src/main/scala/playground/generated/nodes/Struct.scala index f2d92645..640f290b 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Struct.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Struct.scala @@ -5,13 +5,15 @@ import org.polyvariant.treesitter4s.Node case class Struct /* private */(node: Node) extends Node { - def bindings: Bindings = Bindings(node.fields("bindings").head) + def bindings: Bindings = node.fields("bindings").head match { + case node @ Bindings() => Bindings(node) + } export node.* } object Struct { - def unapply(node: Node): scala.Boolean = node.tpe == "struct" + def unapply(node: Node): Boolean = node.tpe == "struct" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Top_level_statement.scala b/modules/parser/src/main/scala/playground/generated/nodes/Top_level_statement.scala index 5ed000f8..e93d1399 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Top_level_statement.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Top_level_statement.scala @@ -11,7 +11,7 @@ case class Top_level_statement /* private */(node: Node) extends Node { } object Top_level_statement { - def unapply(node: Node): scala.Boolean = node.tpe == "top_level_statement" + def unapply(node: Node): Boolean = node.tpe == "top_level_statement" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Use_clause.scala b/modules/parser/src/main/scala/playground/generated/nodes/Use_clause.scala index b6db1017..955624a8 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Use_clause.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Use_clause.scala @@ -5,13 +5,15 @@ import org.polyvariant.treesitter4s.Node case class Use_clause /* private */(node: Node) extends Node { - def identifier: Qualified_identifier = Qualified_identifier(node.fields("identifier").head) + def identifier: Qualified_identifier = node.fields("identifier").head match { + case node @ Qualified_identifier() => Qualified_identifier(node) + } export node.* } object Use_clause { - def unapply(node: Node): scala.Boolean = node.tpe == "use_clause" + def unapply(node: Node): Boolean = node.tpe == "use_clause" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/Whitespace.scala b/modules/parser/src/main/scala/playground/generated/nodes/Whitespace.scala index 6c758fe9..5a4ac3c6 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/Whitespace.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/Whitespace.scala @@ -11,7 +11,7 @@ case class Whitespace /* private */(node: Node) extends Node { } object Whitespace { - def unapply(node: Node): scala.Boolean = node.tpe == "whitespace" + def unapply(node: Node): Boolean = node.tpe == "whitespace" } /* diff --git a/modules/parser/src/main/scala/playground/generated/nodes/_Input_node.scala b/modules/parser/src/main/scala/playground/generated/nodes/_Input_node.scala index 96350ad4..9fe55b5a 100644 --- a/modules/parser/src/main/scala/playground/generated/nodes/_Input_node.scala +++ b/modules/parser/src/main/scala/playground/generated/nodes/_Input_node.scala @@ -11,7 +11,7 @@ enum _Input_node { case StringCase(value: String_) case StructCase(value: Struct) - def asNode: Node = this match { + def node: Node = this match { case BooleanCase(value) => value.node case ListCase(value) => value.node case NullCase(value) => value.node @@ -30,6 +30,15 @@ object _Input_node { case node @ String_() => StringCase(String_(node)) case node @ Struct() => StructCase(Struct(node)) } + + def unapply(node: Node): Boolean = node match { + case node @ Boolean_() => true + case node @ List_() => true + case node @ Null_() => true + case node @ Number() => true + case node @ String_() => true + case node @ Struct() => true + } } /* diff --git a/modules/parser/src/main/scala/playground/smithyql/parser/ParserTreeSitterDemo.scala b/modules/parser/src/main/scala/playground/smithyql/parser/ParserTreeSitterDemo.scala index 52deb153..0f7873c5 100644 --- a/modules/parser/src/main/scala/playground/smithyql/parser/ParserTreeSitterDemo.scala +++ b/modules/parser/src/main/scala/playground/smithyql/parser/ParserTreeSitterDemo.scala @@ -22,5 +22,5 @@ object ParserTreeSitterDemo extends App { .collect { case b @ Binding() => Binding(b) } .head - println(bind.key.source + ": " + bind.value.asNode.source) + println(bind.key.source + ": " + bind.value.node.source) } diff --git a/modules/parser/src/main/scala/playground/smithyql/parser/demo.worksheet.sc b/modules/parser/src/main/scala/playground/smithyql/parser/demo.worksheet.sc index b3e8859d..fb5dd854 100644 --- a/modules/parser/src/main/scala/playground/smithyql/parser/demo.worksheet.sc +++ b/modules/parser/src/main/scala/playground/smithyql/parser/demo.worksheet.sc @@ -32,4 +32,6 @@ val bind = bind.key.source -bind.value +bind.value match { + case _Input_node.NumberCase(value) => value.source +}