Add support for function constants (#37)

pull/844/head
Jonathan Arnett 2022-08-22 14:53:32 +07:00 committed by GitHub
parent 7bfe989c55
commit 81670f48fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 23922 additions and 23064 deletions

@ -52,6 +52,7 @@ There are a few nodes in the generated AST that may be confusing at first:
—there's no way for the parser to know. In this case, it will be parsed to
`(function_call function: (field_access ...) ...)` , as I arbitrarily decided
to always assume the code is accessing a field on a record.
- `constant_field_access` :: Recognizes when a reference to a remote function is used as a constant's value. Generally field accesses are indistinguishable from remote function invocations by the parser so `field_access` is the node name used for both (hence this misnomer).
This is not a comprehensive list. If you find a node confusing, search for it
in `grammar.js`, as it might have an explanatory comment. Either way, feel free

@ -25,6 +25,7 @@ module.exports = grammar({
],
[$.case_subjects],
[$.source_file],
[$._constant_value, $._case_clause_guard_unit],
],
rules: {
/* General rules */
@ -93,7 +94,9 @@ module.exports = grammar({
alias($.constant_tuple, $.tuple),
alias($.constant_list, $.list),
alias($._constant_bit_string, $.bit_string),
alias($.constant_record, $.record)
alias($.constant_record, $.record),
$.identifier,
alias($.constant_field_access, $.field_access)
),
constant_tuple: ($) =>
seq("#", "(", optional(series_of($._constant_value, ",")), ")"),
@ -118,6 +121,12 @@ module.exports = grammar({
optional(seq(field("label", $.label), ":")),
field("value", $._constant_value)
),
// This is definitely a misnomer at this time as field access are actually
// not allowed as constant values (yet). This rule exists to parse remote
// function references which are generally indistinguishable from field
// accesses and so share an AST node.
constant_field_access: ($) =>
seq(field("record", $.identifier), ".", field("field", $.label)),
/* Special constant types */
// Versions of $._type, $._type_annotation, etc, that have constraints
@ -126,11 +135,29 @@ module.exports = grammar({
choice(
$.type_hole,
alias($.constant_tuple_type, $.tuple_type),
alias($.constant_function_type, $.function_type),
alias($.constant_type, $.type)
),
_constant_type_annotation: ($) => seq(":", field("type", $._constant_type)),
constant_tuple_type: ($) =>
seq("#", "(", optional(series_of($._constant_type, ",")), ")"),
constant_function_type: ($) =>
seq(
"fn",
optional(
field(
"parameter_types",
alias(
$.constant_function_parameter_types,
$.function_parameter_types
)
)
),
"->",
field("return_type", $._constant_type)
),
constant_function_parameter_types: ($) =>
seq("(", optional(series_of($._constant_type, ",")), ")"),
constant_type: ($) =>
seq(
field("name", choice($.type_identifier, $.remote_type_identifier)),

151
src/grammar.json generated

@ -481,6 +481,19 @@
},
"named": true,
"value": "record"
},
{
"type": "SYMBOL",
"name": "identifier"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "constant_field_access"
},
"named": true,
"value": "field_access"
}
]
},
@ -953,6 +966,31 @@
}
]
},
"constant_field_access": {
"type": "SEQ",
"members": [
{
"type": "FIELD",
"name": "record",
"content": {
"type": "SYMBOL",
"name": "identifier"
}
},
{
"type": "STRING",
"value": "."
},
{
"type": "FIELD",
"name": "field",
"content": {
"type": "SYMBOL",
"name": "label"
}
}
]
},
"_constant_type": {
"type": "CHOICE",
"members": [
@ -969,6 +1007,15 @@
"named": true,
"value": "tuple_type"
},
{
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "constant_function_type"
},
"named": true,
"value": "function_type"
},
{
"type": "ALIAS",
"content": {
@ -1059,6 +1106,106 @@
}
]
},
"constant_function_type": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "fn"
},
{
"type": "CHOICE",
"members": [
{
"type": "FIELD",
"name": "parameter_types",
"content": {
"type": "ALIAS",
"content": {
"type": "SYMBOL",
"name": "constant_function_parameter_types"
},
"named": true,
"value": "function_parameter_types"
}
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": "->"
},
{
"type": "FIELD",
"name": "return_type",
"content": {
"type": "SYMBOL",
"name": "_constant_type"
}
}
]
},
"constant_function_parameter_types": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "("
},
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "SYMBOL",
"name": "_constant_type"
},
{
"type": "REPEAT",
"content": {
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "SYMBOL",
"name": "_constant_type"
}
]
}
},
{
"type": "CHOICE",
"members": [
{
"type": "STRING",
"value": ","
},
{
"type": "BLANK"
}
]
}
]
},
{
"type": "BLANK"
}
]
},
{
"type": "STRING",
"value": ")"
}
]
},
"constant_type": {
"type": "SEQ",
"members": [
@ -5900,6 +6047,10 @@
],
[
"source_file"
],
[
"_constant_value",
"_case_clause_guard_unit"
]
],
"precedences": [],

16
src/node-types.json generated

@ -1072,6 +1072,10 @@
"type": "bit_string",
"named": true
},
{
"type": "field_access",
"named": true
},
{
"type": "float",
"named": true
@ -1308,6 +1312,10 @@
"multiple": false,
"required": false,
"types": [
{
"type": "function_type",
"named": true
},
{
"type": "tuple_type",
"named": true
@ -1330,10 +1338,18 @@
"type": "bit_string",
"named": true
},
{
"type": "field_access",
"named": true
},
{
"type": "float",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "integer",
"named": true

46720
src/parser.c generated

File diff suppressed because it is too large Load Diff

@ -26,6 +26,9 @@ const a = Cat("Ginny", 1950)
const a = Person(name: "Billy", age: 52)
const a = uri.Uri(host: "github.com")
const a: option.Option(String) = option.Some("Hello, World!")
const var_alias = b
const int_identity_alias: fn(Int) -> Int = int_identity
const fun_tuple: #(fn(Float) -> String, fn(Int) -> String) = #(float.to_string, int.to_string)
--------------------------------------------------------------------------------
@ -206,7 +209,41 @@ const a: option.Option(String) = option.Some("Hello, World!")
arguments: (arguments
(argument
value: (string
(quoted_content)))))))
(quoted_content))))))
(constant
name: (identifier)
value: (identifier))
(constant
name: (identifier)
type: (function_type
parameter_types: (function_parameter_types
(type
name: (type_identifier)))
return_type: (type
name: (type_identifier)))
value: (identifier))
(constant
name: (identifier)
type: (tuple_type
(function_type
parameter_types: (function_parameter_types
(type
name: (type_identifier)))
return_type: (type
name: (type_identifier)))
(function_type
parameter_types: (function_parameter_types
(type
name: (type_identifier)))
return_type: (type
name: (type_identifier))))
value: (tuple
(field_access
record: (identifier)
field: (label))
(field_access
record: (identifier)
field: (label)))))
================================================================================
Public constants

@ -780,6 +780,36 @@ fn try_try_again(x, y) -> Int {
(identifier))
value: (todo)))))
================================================================================
Let expressions
================================================================================
let foo: fn(Int) -> Int = fn(x) { x }
let fun_ref = float.to_string
--------------------------------------------------------------------------------
(source_file
(let
pattern: (identifier)
type: (function_type
parameter_types: (function_parameter_types
(type
name: (type_identifier)))
return_type: (type
name: (type_identifier)))
value: (anonymous_function
parameters: (function_parameters
(function_parameter
name: (identifier)))
body: (function_body
(identifier))))
(let
pattern: (identifier)
value: (field_access
record: (identifier)
field: (label))))
================================================================================
Complex binary expressions
================================================================================