Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tree-sitter grammar: support Enums #5357

Merged
merged 3 commits into from
Apr 25, 2024
Merged
Changes from 2 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
27 changes: 27 additions & 0 deletions backend/testfiles/execution/stdlib/parser.dark
Original file line number Diff line number Diff line change
@@ -257,6 +257,23 @@ module TextToTextRoundtripping =
hasPet: Bool
pet: Pet }"""

// Enum type
("type Color = | Red | Green | Blue" |> roundtripCliScript) = "type Color =\n | Red\n | Green\n | Blue"
("type MyEnum = | A of Int64" |> roundtripCliScript) = "type MyEnum =\n | A of Int64"
("type MyEnum = | A of Int64 * Int64" |> roundtripCliScript) = "type MyEnum =\n | A of Int64 * Int64"
("type MyEnum = | A of Int64 * Bool * String | B of Int64" |> roundtripCliScript) = "type MyEnum =\n | A of Int64 * Bool * String\n | B of Int64"
("type MyEnum = | A of x:Int64 * y:Int64" |> roundtripCliScript) = "type MyEnum =\n | A of x: Int64 * y: Int64"

("type Color =\n | Red\n | Green\n | Blue" |> roundtripCliScript) = "type Color =\n | Red\n | Green\n | Blue"
("type MyEnum =\n | A of Int64\n | B of String" |> roundtripCliScript) = "type MyEnum =\n | A of Int64\n | B of String"
("type MyEnum =\n | A of x: Int64\n | B of y: String" |> roundtripCliScript) = "type MyEnum =\n | A of x: Int64\n | B of y: String"

("type MyEnum =\n | A of x: Int64 * y: Int64\n | B of z: String"
|> roundtripCliScript) = "type MyEnum =\n | A of x: Int64 * y: Int64\n | B of z: String"




module Expr =
// units
("()" |> roundtripCliScript) = "()"
@@ -330,6 +347,16 @@ module TextToTextRoundtripping =
("Person {name =\"John\"; age = 30L; hasPet = true; pet = Pet {name = \"Luna\"}} "
|> roundtripCliScript) = "Person { name = \"John\"; age = 30L; hasPet = true; pet = Pet { name = \"Luna\" } }"

// enum literal
("Color.Red" |> roundtripCliScript) = "Color.Red"
("Stdlib.Option.None" |> roundtripCliScript) = "Stdlib.Option.None"
("PACKAGE.Darklang.Stdlib.Option.Option.None" |> roundtripCliScript) = "PACKAGE.Darklang.Stdlib.Option.Option.None"
("PACKAGE.Darklang.Stdlib.Option.Option.Some(1L)" |> roundtripCliScript) = "PACKAGE.Darklang.Stdlib.Option.Option.Some(1L)"
("MyEnum.A(1L, 2L)" |> roundtripCliScript) = "MyEnum.A(1L, 2L)"




// variables and let bindings
("assumedlyAVariableName" |> roundtripCliScript) = "assumedlyAVariableName"
// TODO: this is ugly
Original file line number Diff line number Diff line change
@@ -26,7 +26,8 @@ module Darklang =
"parameter" // [7] for function parameter identifiers
"variable" // [8] for general identifiers
"function" // [9] for function names/identifiers
"property" ] // [10] for field names
"property" // [10] for field names
"enumCase" ] // [11] for enum case names

let tokenModifiers = []

@@ -53,6 +54,7 @@ module Darklang =
| FunctionName -> 9UL

| Property -> 10UL
| EnumCase -> 11UL

let toRelativeTokens
(tokens: List<LanguageTools.SemanticTokens.SemanticToken>)
123 changes: 123 additions & 0 deletions packages/darklang/languageTools/parser.dark
Original file line number Diff line number Diff line change
@@ -554,6 +554,73 @@ module Darklang =
(WrittenTypes.TypeDeclaration.Definition.Record recordFields)
|> Stdlib.Result.Result.Ok


| [ child ] when child.typ == "type_decl_def_enum" ->
let enumCases =
match findNodeByFieldName child "content" with
| Some contentNode ->
contentNode.children
|> Stdlib.List.map (fun caseNode ->
let caseNameNode = findNodeByFieldName caseNode "case_name"

let keywordOf =
Stdlib.Option.map
(findNodeByFieldName caseNode "keyword_of")
(fun range -> range.sourceRange)

let fields =
caseNode.children
|> Stdlib.List.filter (fun field ->
field.typ == "type_decl_enum_field")
|> Stdlib.List.map (fun field ->
match findNodeByFieldName field "type" with
| Some fieldTypeNode ->
let label =
(findNodeByFieldName field "identifier")
|> Stdlib.Option.map (fun ln ->
(ln.sourceRange, ln.text))

let colonSymbol =
(findNodeByFieldName field "symbol_colon")
|> Stdlib.Option.map (fun ln -> ln.sourceRange)

let fieldType = TypeReference.parse fieldTypeNode

match fieldType with
| Ok fieldType ->
WrittenTypes.TypeDeclaration.EnumField
{ range = field.sourceRange
typ = fieldType
label = label
description = ""
symbolColon = colonSymbol }
| Error _ ->
(WrittenTypes.Unparseable { source = field })
| None -> (WrittenTypes.Unparseable { source = field }))

match caseNameNode with
| Some caseNameNode ->
(WrittenTypes.TypeDeclaration.EnumCase
{ range = caseNode.sourceRange
name = (caseNameNode.sourceRange, caseNameNode.text)
fields = fields
description = ""
keywordOf = keywordOf })
|> Stdlib.Result.Result.Ok
| None ->
(WrittenTypes.Unparseable { source = caseNode })
|> Stdlib.Result.Result.Error)
|> Stdlib.Result.values
| None -> []

match enumCases with
| Ok enumCases ->
(WrittenTypes.TypeDeclaration.Definition.Enum enumCases)
|> Stdlib.Result.Result.Ok
| Error _ ->
(WrittenTypes.Unparseable { source = node })
|> Stdlib.Result.Result.Error

| _ ->
(WrittenTypes.Unparseable { source = node })
|> Stdlib.Result.Result.Error
@@ -562,6 +629,7 @@ module Darklang =
(WrittenTypes.Unparseable { source = node })
|> Stdlib.Result.Result.Error


let parse
(node: ParsedNode)
: Stdlib.Result.Result<WrittenTypes.TypeDeclaration.TypeDeclaration, WrittenTypes.Unparseable> =
@@ -1259,6 +1327,59 @@ module Darklang =
|> Stdlib.Result.Result.Error


let parseEnumLiteral
(node: ParsedNode)
: Stdlib.Result.Result<WrittenTypes.Expr, WrittenTypes.Unparseable> =
if node.typ == "enum_literal" then
let typeNameNode =
(findNodeByFieldName node "type_name")
|> Stdlib.Option.toResult "No type_name node found in enum_literal"

let symbolDotNode =
(findNodeByFieldName node "symbol_dot")
|> Stdlib.Option.toResult "No symbol_dot node found in enum_literal"

let caseNameNode =
(findNodeByFieldName node "case_name")
|> Stdlib.Option.toResult "No case_name node found in enum_literal"

let enumFieldsNode =
(findNodeByFieldName node "enum_fields")
|> Stdlib.Option.map (fun enumFieldsNode ->
enumFieldsNode.children
|> Stdlib.List.chunkBySize 2L
|> Builtin.unwrap
|> Stdlib.List.map (fun chunk ->
match chunk with
| [ fieldNode ] ->
match Expr.parse fieldNode with
| Ok field -> field
| Error _ -> (WrittenTypes.Unparseable { source = fieldNode })

| [ fieldNode; _separator ] ->
match Expr.parse fieldNode with
| Ok field -> field
| Error _ -> (WrittenTypes.Unparseable { source = fieldNode })))

|> Stdlib.Option.withDefault []


match typeNameNode, symbolDotNode, caseNameNode with
| Ok typeNameNode, Ok symbolDotNode, Ok caseNameNode ->

(WrittenTypes.Expr.EEnum(
node.sourceRange,
(typeNameNode.sourceRange, [ typeNameNode.text ]),
(caseNameNode.sourceRange, caseNameNode.text),
enumFieldsNode,
symbolDotNode.sourceRange
))
|> Stdlib.Result.Result.Ok

| _ ->
(WrittenTypes.Unparseable { source = node })
|> Stdlib.Result.Result.Error


let parseLetExpr
(node: ParsedNode)
@@ -1547,6 +1668,8 @@ module Darklang =

| "record_literal" -> parseRecordLiteral node

| "enum_literal" -> parseEnumLiteral node

// assigning and accessing variables
| "let_expression" -> parseLetExpr node
| "variable_identifier" ->
68 changes: 68 additions & 0 deletions packages/darklang/languageTools/semanticTokens.dark
Original file line number Diff line number Diff line change
@@ -180,6 +180,45 @@ module Darklang =
|> Stdlib.List.flatten)
|> Stdlib.List.flatten

| Enum cases ->
cases
|> Stdlib.List.map (fun case ->
let (enumCaseNameRange, _) = case.name

let keywordOf =
match case.keywordOf with
| Some range -> [ makeToken range TokenType.Keyword ]
| None -> []

let labelTokens =
case.fields
|> Stdlib.List.map (fun field ->
let label =
match field.label with
| Some((range, _)) -> [ range ]
| None -> []

let colon =
match field.symbolColon with
| Some range -> [ range ]
| None -> []

Stdlib.List.append label colon)
|> Stdlib.List.flatten
|> Stdlib.List.map (fun range -> makeToken range TokenType.Property)

let typeRange =
case.fields
|> Stdlib.List.map (fun field -> TypeReference.tokenize field.typ)

[ [ makeToken enumCaseNameRange TokenType.EnumCase ]
keywordOf
labelTokens
typeRange |> Stdlib.List.flatten ]
|> Stdlib.List.flatten)
|> Stdlib.List.flatten


// type ID = UInt64
let tokenize
(t: WrittenTypes.TypeDeclaration.TypeDeclaration)
@@ -382,6 +421,35 @@ module Darklang =
[ makeToken symbolCloseBrace TokenType.Symbol ] ]
|> Stdlib.List.flatten


// Option.Option.Some 1L
| EEnum(range, typeName, caseName, fields, symbolDot) ->
let typeName =
match typeName with
| (range, _) -> [ makeToken range TokenType.TypeName ]
| _ -> []

let caseName =
match caseName with
| (range, _) -> [ makeToken range TokenType.EnumCase ]
| _ -> []

let fields =
fields
|> Stdlib.List.map (fun expr -> Expr.tokenize expr)
|> Stdlib.List.flatten

[ // Option.Option.Some
typeName
// .
[ makeToken symbolDot TokenType.Symbol ]
// Some
caseName
// 1L
fields ]
|> Stdlib.List.flatten


// let x = 2
// x + 1
| ELet(range, lp, expr, body, keywordLet, symbolEquals) ->
22 changes: 22 additions & 0 deletions packages/darklang/languageTools/writtenTypes.dark
Original file line number Diff line number Diff line change
@@ -94,9 +94,24 @@ module Darklang =
description: String
symbolColon: SourceRange }

type EnumField =
{ range: SourceRange
typ: TypeReference.TypeReference
label: Stdlib.Option.Option<SourceRange * String>
description: String
symbolColon: Stdlib.Option.Option<SourceRange> }

type EnumCase =
{ range: SourceRange
name: SourceRange * String
fields: List<EnumField>
description: String
keywordOf: Stdlib.Option.Option<SourceRange> }

type Definition =
| Alias of TypeReference.TypeReference
| Record of List<RecordField>
| Enum of List<EnumCase>

type TypeDeclaration =
{ range: SourceRange
@@ -217,6 +232,13 @@ module Darklang =
symbolOpenBrace: SourceRange *
symbolCloseBrace: SourceRange

| EEnum of
SourceRange *
typeName: (SourceRange * List<String>) *
caseName: (SourceRange * String) *
fields: List<Expr> *
symbolDot: SourceRange

| ELet of
SourceRange *
LetPattern *
51 changes: 51 additions & 0 deletions packages/darklang/languageTools/writtenTypesToProgramTypes.dark
Original file line number Diff line number Diff line change
@@ -129,6 +129,38 @@ module Darklang =
typ = TypeReference.toPT resolver f.typ
description = "" }

module EnumField =
let toPT
(resolver: NameResolver.NameResolutionSettings)
(f: WrittenTypes.TypeDeclaration.EnumField)
: ProgramTypes.TypeDeclaration.EnumField =

let label =
match f.label with
| Some l -> Stdlib.Option.Option.Some(l |> Stdlib.Tuple2.second)
| None -> Stdlib.Option.Option.None

ProgramTypes.TypeDeclaration.EnumField
{ typ = TypeReference.toPT resolver f.typ
label = label
description = "" }

module EnumCase =
let toPT
(resolver: NameResolver.NameResolutionSettings)
(c: WrittenTypes.TypeDeclaration.EnumCase)
: ProgramTypes.TypeDeclaration.EnumCase =

let name = c.name |> Stdlib.Tuple2.second

let fields =
Stdlib.List.map c.fields (fun f -> EnumField.toPT resolver f)

ProgramTypes.TypeDeclaration.EnumCase
{ name = name
fields = fields
description = "" }

module Definition =
let toPT
(resolver: NameResolver.NameResolutionSettings)
@@ -147,6 +179,10 @@ module Darklang =

ProgramTypes.TypeDeclaration.Definition.Record fields

| Enum cases ->
let cases = Stdlib.List.map cases (fun c -> EnumCase.toPT resolver c)
ProgramTypes.TypeDeclaration.Definition.Enum cases

let toPT
(resolver: NameResolver.NameResolutionSettings)
(d: WrittenTypes.TypeDeclaration.TypeDeclaration)
@@ -277,6 +313,21 @@ module Darklang =

ProgramTypes.Expr.ERecord(gid (), typeName, fields)

| EEnum(_, typeName, caseName, fields, _) ->
let sr = Stdlib.Tuple2.first typeName
let unresolvedTypeName = Stdlib.Tuple2.second typeName

let typeName =
NameResolver.TypeName.resolve
resolver
[]
(WrittenTypes.Name.Unresolved sr unresolvedTypeName)

let caseName = caseName |> Stdlib.Tuple2.second
let fields = Stdlib.List.map fields (fun expr -> toPT resolver expr)

ProgramTypes.Expr.EEnum(gid (), typeName, caseName, fields)

// declaring and accessing variables
| ELet(_, pat, rhs, body, _, _) ->
ProgramTypes.Expr.ELet(
88 changes: 87 additions & 1 deletion tree-sitter-darklang/grammar.js
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ module.exports = grammar({

externals: $ => [$.indent, $.dedent],

conflicts: $ => [[$.module_identifier, $.type_identifier]],

rules: {
source_file: $ =>
seq(
@@ -65,10 +67,17 @@ module.exports = grammar({
field("typ", $.type_decl_def),
),

type_decl_def: $ => choice($.type_decl_def_alias, $.type_decl_def_record),
type_decl_def: $ =>
choice(
$.type_decl_def_alias,
$.type_decl_def_record,
$.type_decl_def_enum,
),

// Alias
type_decl_def_alias: $ => $.type_reference,

// Record
// e.g. `type Person = { name: String; age: Int }`
type_decl_def_record: $ =>
seq(
@@ -95,6 +104,52 @@ module.exports = grammar({
field("type", $.type_reference),
),

// Enums
// e.g. `type Color = Red | Green | Blue`
type_decl_def_enum: $ =>
field(
"content",
choice($.type_decl_enum_single_line, $.type_decl_enum_multi_line),
),
type_decl_enum_single_line: $ => repeat1($.type_decl_enum_case),
type_decl_enum_multi_line: $ =>
seq($.indent, repeat1($.type_decl_enum_case), $.dedent),
type_decl_enum_case: $ =>
seq(
field("symbol_pipe", alias("|", $.symbol)),
field("case_name", $.identifier_enum_case),
optional(
seq(
field("keyword_of", alias("of", $.keyword)),
seq(
$.type_decl_enum_field,
repeat(
seq(
field("symbol_astrisk", alias("*", $.symbol)),
$.type_decl_enum_field,
),
),
),
),
),
),

type_decl_enum_field: $ =>
seq(
optional(
field(
"type_annotation",
seq(
field("identifier", $.variable_identifier),
field("symbol_colon", alias(":", $.symbol)),
),
),
),
field("type", $.type_reference),
),

newline: $ => /\n/,

//
// Expressions
expression: $ =>
@@ -119,6 +174,7 @@ module.exports = grammar({
$.tuple_literal,
$.dict_literal,
$.record_literal,
$.enum_literal,
$.if_expression,
$.let_expression,
$.variable_identifier,
@@ -398,20 +454,47 @@ module.exports = grammar({
field("content", optional($.record_content)),
field("symbol_close_brace", alias("}", $.symbol)),
),

record_content: $ =>
seq(
$.record_pair,
repeat(
seq(field("record_separator", alias(";", $.symbol)), $.record_pair),
),
),

record_pair: $ =>
seq(
field("field", $.variable_identifier),
field("symbol_equals", alias("=", $.symbol)),
field("value", $.expression),
),

//
// Enum
// TODO: Make parentheses optional when there's only one argument
enum_literal: $ =>
prec.right(
seq(
field("type_name", $.qualified_type_name),
field("symbol_dot", alias(".", $.symbol)),
field("case_name", $.identifier_enum_case),
optional(
seq(
field("symbol_open_paren", alias("(", $.symbol)),
field("enum_fields", $.enum_fields),
field("symbol_close_paren", alias(")", $.symbol)),
),
),
),
),

enum_fields: $ =>
seq(
$.expression,
repeat(seq(field("symbol_comma", alias(",", $.symbol)), $.expression)),
),

//
// If expressions
if_expression: $ =>
@@ -540,6 +623,9 @@ module.exports = grammar({
// e.g. `LanguageTools in `PACKAGE.Darklang.LanguageTools.SomeType`
module_identifier: $ => /[A-Z][a-zA-Z0-9_]*/,

//
identifier_enum_case: $ => /[A-Z][a-zA-Z0-9_]*/,

unit: $ => "()",
},
});
323 changes: 322 additions & 1 deletion tree-sitter-darklang/src/grammar.json
Original file line number Diff line number Diff line change
@@ -238,6 +238,10 @@
{
"type": "SYMBOL",
"name": "type_decl_def_record"
},
{
"type": "SYMBOL",
"name": "type_decl_def_enum"
}
]
},
@@ -360,6 +364,191 @@
}
]
},
"type_decl_def_enum": {
"type": "FIELD",
"name": "content",
"content": {
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "type_decl_enum_single_line"
},
{
"type": "SYMBOL",
"name": "type_decl_enum_multi_line"
}
]
}
},
"type_decl_enum_single_line": {
"type": "REPEAT1",
"content": {
"type": "SYMBOL",
"name": "type_decl_enum_case"
}
},
"type_decl_enum_multi_line": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "indent"
},
{
"type": "REPEAT1",
"content": {
"type": "SYMBOL",
"name": "type_decl_enum_case"
}
},
{
"type": "SYMBOL",
"name": "dedent"
}
]
},
"type_decl_enum_case": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "symbol_pipe",
"content": {
"type": "ALIAS",
"content": {
"type": "STRING",
"value": "|"
},
"named": true,
"value": "symbol"
}
},
{
"type": "FIELD",
"name": "case_name",
"content": {
"type": "SYMBOL",
"name": "identifier_enum_case"
}
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "keyword_of",
"content": {
"type": "ALIAS",
"content": {
"type": "STRING",
"value": "of"
},
"named": true,
"value": "keyword"
}
},
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "type_decl_enum_field"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "symbol_astrisk",
"content": {
"type": "ALIAS",
"content": {
"type": "STRING",
"value": "*"
},
"named": true,
"value": "symbol"
}
},
{
"type": "SYMBOL",
"name": "type_decl_enum_field"
}
]
}
}
]
}
]
},
{
"type": "BLANK"
}
]
}
]
},
"type_decl_enum_field": {
"type": "SEQ",
"members": [
{
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "type_annotation",
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "identifier",
"content": {
"type": "SYMBOL",
"name": "variable_identifier"
}
},
{
"type": "FIELD",
"name": "symbol_colon",
"content": {
"type": "ALIAS",
"content": {
"type": "STRING",
"value": ":"
},
"named": true,
"value": "symbol"
}
}
]
}
},
{
"type": "BLANK"
}
]
},
{
"type": "FIELD",
"name": "type",
"content": {
"type": "SYMBOL",
"name": "type_reference"
}
}
]
},
"newline": {
"type": "PATTERN",
"value": "\\n"
},
"expression": {
"type": "CHOICE",
"members": [
@@ -443,6 +632,10 @@
"type": "SYMBOL",
"name": "record_literal"
},
{
"type": "SYMBOL",
"name": "enum_literal"
},
{
"type": "SYMBOL",
"name": "if_expression"
@@ -1836,6 +2029,125 @@
}
]
},
"enum_literal": {
"type": "PREC_RIGHT",
"value": 0,
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "type_name",
"content": {
"type": "SYMBOL",
"name": "qualified_type_name"
}
},
{
"type": "FIELD",
"name": "symbol_dot",
"content": {
"type": "ALIAS",
"content": {
"type": "STRING",
"value": "."
},
"named": true,
"value": "symbol"
}
},
{
"type": "FIELD",
"name": "case_name",
"content": {
"type": "SYMBOL",
"name": "identifier_enum_case"
}
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "symbol_open_paren",
"content": {
"type": "ALIAS",
"content": {
"type": "STRING",
"value": "("
},
"named": true,
"value": "symbol"
}
},
{
"type": "FIELD",
"name": "enum_fields",
"content": {
"type": "SYMBOL",
"name": "enum_fields"
}
},
{
"type": "FIELD",
"name": "symbol_close_paren",
"content": {
"type": "ALIAS",
"content": {
"type": "STRING",
"value": ")"
},
"named": true,
"value": "symbol"
}
}
]
},
{
"type": "BLANK"
}
]
}
]
}
},
"enum_fields": {
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "expression"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "symbol_comma",
"content": {
"type": "ALIAS",
"content": {
"type": "STRING",
"value": ","
},
"named": true,
"value": "symbol"
}
},
{
"type": "SYMBOL",
"name": "expression"
}
]
}
}
]
},
"if_expression": {
"type": "PREC_RIGHT",
"value": 0,
@@ -2362,6 +2674,10 @@
"type": "PATTERN",
"value": "[A-Z][a-zA-Z0-9_]*"
},
"identifier_enum_case": {
"type": "PATTERN",
"value": "[A-Z][a-zA-Z0-9_]*"
},
"unit": {
"type": "STRING",
"value": "()"
@@ -2373,7 +2689,12 @@
"value": "\\s"
}
],
"conflicts": [],
"conflicts": [
[
"module_identifier",
"type_identifier"
]
],
"precedences": [],
"externals": [
{
255 changes: 255 additions & 0 deletions tree-sitter-darklang/src/node-types.json
Original file line number Diff line number Diff line change
@@ -251,6 +251,98 @@
]
}
},
{
"type": "enum_fields",
"named": true,
"fields": {
"symbol_comma": {
"multiple": true,
"required": false,
"types": [
{
"type": "symbol",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "enum_literal",
"named": true,
"fields": {
"case_name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier_enum_case",
"named": true
}
]
},
"enum_fields": {
"multiple": false,
"required": false,
"types": [
{
"type": "enum_fields",
"named": true
}
]
},
"symbol_close_paren": {
"multiple": false,
"required": false,
"types": [
{
"type": "symbol",
"named": true
}
]
},
"symbol_dot": {
"multiple": false,
"required": true,
"types": [
{
"type": "symbol",
"named": true
}
]
},
"symbol_open_paren": {
"multiple": false,
"required": false,
"types": [
{
"type": "symbol",
"named": true
}
]
},
"type_name": {
"multiple": false,
"required": true,
"types": [
{
"type": "qualified_type_name",
"named": true
}
]
}
}
},
{
"type": "expression",
"named": true,
@@ -271,6 +363,10 @@
"type": "dict_literal",
"named": true
},
{
"type": "enum_literal",
"named": true
},
{
"type": "float_literal",
"named": true
@@ -564,6 +660,11 @@
}
}
},
{
"type": "identifier_enum_case",
"named": true,
"fields": {}
},
{
"type": "if_expression",
"named": true,
@@ -1463,6 +1564,10 @@
"type": "type_decl_def_alias",
"named": true
},
{
"type": "type_decl_def_enum",
"named": true
},
{
"type": "type_decl_def_record",
"named": true
@@ -1485,6 +1590,26 @@
]
}
},
{
"type": "type_decl_def_enum",
"named": true,
"fields": {
"content": {
"multiple": false,
"required": true,
"types": [
{
"type": "type_decl_enum_multi_line",
"named": true
},
{
"type": "type_decl_enum_single_line",
"named": true
}
]
}
}
},
{
"type": "type_decl_def_record",
"named": true,
@@ -1583,6 +1708,136 @@
}
}
},
{
"type": "type_decl_enum_case",
"named": true,
"fields": {
"case_name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier_enum_case",
"named": true
}
]
},
"keyword_of": {
"multiple": false,
"required": false,
"types": [
{
"type": "keyword",
"named": true
}
]
},
"symbol_astrisk": {
"multiple": true,
"required": false,
"types": [
{
"type": "symbol",
"named": true
}
]
},
"symbol_pipe": {
"multiple": false,
"required": true,
"types": [
{
"type": "symbol",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "type_decl_enum_field",
"named": true
}
]
}
},
{
"type": "type_decl_enum_field",
"named": true,
"fields": {
"identifier": {
"multiple": false,
"required": false,
"types": [
{
"type": "variable_identifier",
"named": true
}
]
},
"symbol_colon": {
"multiple": false,
"required": false,
"types": [
{
"type": "symbol",
"named": true
}
]
},
"type": {
"multiple": false,
"required": true,
"types": [
{
"type": "type_reference",
"named": true
}
]
}
}
},
{
"type": "type_decl_enum_multi_line",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "dedent",
"named": true
},
{
"type": "indent",
"named": true
},
{
"type": "type_decl_enum_case",
"named": true
}
]
}
},
{
"type": "type_decl_enum_single_line",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "type_decl_enum_case",
"named": true
}
]
}
},
{
"type": "type_identifier",
"named": true,
130 changes: 130 additions & 0 deletions tree-sitter-darklang/test/corpus/exhaustive/exprs/Enum.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
==================
Enum - no args
==================

MyEnum.NoArgs

---

(source_file
(expression
(enum_literal
(qualified_type_name (type_identifier))
(symbol)
(identifier_enum_case)
)
)
)


==================
Enum - with one arg
==================

MyEnum.OneArg(1L)

---

(source_file
(expression
(enum_literal
(qualified_type_name
(type_identifier))
(symbol)
(identifier_enum_case)
(symbol)
(enum_fields
(expression (int64_literal (digits (positive_digits)) (symbol)))
)
(symbol)
)
)
)


==================
Enum - with two args
==================

MyEnum.TwoArgs(1L, 2L)

---

(source_file
(expression
(enum_literal
(qualified_type_name
(type_identifier))
(symbol)
(identifier_enum_case)
(symbol)
(enum_fields
(expression
(int64_literal
(digits
(positive_digits))
(symbol)))
(symbol)
(expression
(int64_literal
(digits
(positive_digits))
(symbol))))
(symbol))
)
)


==================
Enum - fully qualified
==================

Stdlib.Option.Option.None

---

(source_file
(expression
(enum_literal
(qualified_type_name
(module_identifier)
(symbol)
(module_identifier)
(symbol)
(type_identifier)
)
(symbol)
(identifier_enum_case)
)
)
)


==================
Enum - fully qualified with args
==================

Stdlib.Option.Option.Some(1L)

---

(source_file
(expression
(enum_literal
(qualified_type_name
(module_identifier)
(symbol)
(module_identifier)
(symbol)
(type_identifier)
)
(symbol)
(identifier_enum_case)
(symbol)
(enum_fields
(expression (int64_literal (digits (positive_digits)) (symbol)))
)
(symbol)
)
)
)
16 changes: 4 additions & 12 deletions tree-sitter-darklang/test/corpus/exhaustive/exprs/bools.txt
Original file line number Diff line number Diff line change
@@ -29,9 +29,7 @@ TRUE
---

(source_file
(ERROR
(qualified_type_name
(type_identifier))))
(ERROR (module_identifier)))


==================
@@ -43,9 +41,7 @@ FALSE
---

(source_file
(ERROR
(qualified_type_name
(type_identifier))))
(ERROR (module_identifier)))



@@ -58,9 +54,7 @@ True
---

(source_file
(ERROR
(qualified_type_name
(type_identifier))))
(ERROR (module_identifier)))

==================
False (error)
@@ -71,6 +65,4 @@ False
---

(source_file
(ERROR
(qualified_type_name
(type_identifier))))
(ERROR (module_identifier)))
283 changes: 283 additions & 0 deletions tree-sitter-darklang/test/corpus/exhaustive/type_decls.txt
Original file line number Diff line number Diff line change
@@ -97,4 +97,287 @@ type Cols2 = { col1: Int64; col2: Int64 }
)
)
)
)


==================
type def Record with package type
==================

type Cols2 = { col1: PACKAGE.Darklang.LanguageTools.Test; col2: Int64 }

---

(source_file
(type_decl (keyword) (type_identifier) (symbol)
(type_decl_def
(type_decl_def_record
(symbol)
(type_decl_def_record_content
(type_decl_def_record_field
(variable_identifier) (symbol) (type_reference
(qualified_type_name
(module_identifier) (symbol) (module_identifier) (symbol) (module_identifier) (symbol) (type_identifier)
)
)
)
(symbol)
(type_decl_def_record_field
(variable_identifier) (symbol) (type_reference (builtin_type))
)
)
(symbol)
)
)
)
)


==================
type def Enum - one case, no fields
==================

type MyEnum =
| A

---

(source_file
(type_decl
(keyword) (type_identifier) (symbol)
(type_decl_def
(type_decl_def_enum
(type_decl_enum_multi_line
(indent)
(type_decl_enum_case
(symbol)
(identifier_enum_case))
(dedent)
)
)
)
)
)


==================
type def Enum - multiple cases, no fields
==================

type MyEnum =
| A
| B
| C

---

(source_file
(type_decl
(keyword) (type_identifier) (symbol)
(type_decl_def
(type_decl_def_enum
(type_decl_enum_multi_line
(indent)
(type_decl_enum_case (symbol) (identifier_enum_case))
(type_decl_enum_case (symbol) (identifier_enum_case))
(type_decl_enum_case (symbol) (identifier_enum_case))
(dedent)
)
)
)
)
)




==================
type def Enum - one case, one field
==================

type MyEnum = | A of Int64

---

(source_file
(type_decl (keyword) (type_identifier) (symbol)
(type_decl_def
(type_decl_def_enum
(type_decl_enum_single_line
(type_decl_enum_case
(symbol) (identifier_enum_case) (keyword) (type_decl_enum_field (type_reference (builtin_type)))
)
)
)
)
)
)


==================
type def Enum - multiple cases, one field
==================

type MyEnum =
| A of Int64
| B of String
| C

---

(source_file
(type_decl
(keyword)
(type_identifier)
(symbol)
(type_decl_def
(type_decl_def_enum
(type_decl_enum_multi_line
(indent)
(type_decl_enum_case
(symbol)
(identifier_enum_case)
(keyword)
(type_decl_enum_field
(type_reference (builtin_type))
)
)
(type_decl_enum_case
(symbol)
(identifier_enum_case)
(keyword)
(type_decl_enum_field
(type_reference (builtin_type))
)
)
(type_decl_enum_case (symbol) (identifier_enum_case))
(dedent)
)
)
)
)
)


==================
type def Enum - multiple cases, no fields, single line
==================

type MyEnum = | A | B | C

---

(source_file
(type_decl
(keyword)
(type_identifier)
(symbol)
(type_decl_def
(type_decl_def_enum
(type_decl_enum_single_line
(type_decl_enum_case (symbol) (identifier_enum_case))
(type_decl_enum_case (symbol) (identifier_enum_case))
(type_decl_enum_case (symbol) (identifier_enum_case))
)
)
)
)
)


==================
type def Enum - multiple cases, one field with label
==================

type MyEnum =
| A of x: Int64
| B of y: String
| C of z: (Int64 * Bool)

---

(source_file
(type_decl (keyword) (type_identifier) (symbol)
(type_decl_def
(type_decl_def_enum
(type_decl_enum_multi_line
(indent)

(type_decl_enum_case
(symbol)
(identifier_enum_case)
(keyword)
(type_decl_enum_field
(variable_identifier)
(symbol)
(type_reference (builtin_type))
)
)

(type_decl_enum_case
(symbol)
(identifier_enum_case)
(keyword)
(type_decl_enum_field
(variable_identifier)
(symbol)
(type_reference (builtin_type))
)
)

(type_decl_enum_case
(symbol)
(identifier_enum_case)
(keyword)
(type_decl_enum_field
(variable_identifier)
(symbol)
(type_reference
(builtin_type
(tuple_type_reference
(symbol)
(type_reference (builtin_type))
(symbol)
(type_reference (builtin_type))
(symbol)
)
)
)
)
)
(dedent)
)
)
)
)
)


==================
type def Enum - multiple cases, two field
==================

type MyEnum =
| A of Int64 * Bool

---

(source_file
(type_decl (keyword) (type_identifier) (symbol)
(type_decl_def
(type_decl_def_enum
(type_decl_enum_multi_line
(indent)
(type_decl_enum_case
(symbol)
(identifier_enum_case)
(keyword)
(type_decl_enum_field (type_reference (builtin_type)))
(symbol)
(type_decl_enum_field (type_reference (builtin_type))))
(dedent)
)
)
)
)
)