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

Fix FnCall #5363

Merged
merged 6 commits into from
May 9, 2024
Merged
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
24 changes: 12 additions & 12 deletions backend/testfiles/execution/stdlib/parser.dark
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ module TextToTextRoundtripping =
("fun () -> 1L" |> roundtripCliScript) = "(fun () ->\n 1L)"

("fun var -> (Stdlib.String.toUppercase (Stdlib.String.fromChar var))"
|> roundtripCliScript) = "(fun var ->\n PACKAGE.Darklang.Stdlib.String.toUppercase PACKAGE.Darklang.Stdlib.String.fromChar var)"
|> roundtripCliScript) = "(fun var ->\n PACKAGE.Darklang.Stdlib.String.toUppercase (PACKAGE.Darklang.Stdlib.String.fromChar var))"

("fun (str1, str2) -> str1 ++ str2" |> roundtripCliScript) = "(fun (str1, str2) ->\n (str1) ++ (str2))"

Expand Down Expand Up @@ -558,11 +558,11 @@ else
("strVar ++ \"str\"" |> roundtripCliScript) = "(strVar) ++ (\"str\")"
("true && false" |> roundtripCliScript) = "(true) && (false)"
("true || false" |> roundtripCliScript) = "(true) || (false)"
("(and true false)" |> roundtripCliScript) = "and true false"
("(Bool.and true false)" |> roundtripCliScript) = "Bool.and true false"
("(PACKAGE.Darklang.Stdlib.Bool.and true false)" |> roundtripCliScript) = "PACKAGE.Darklang.Stdlib.Bool.and true false"
("(Stdlib.Bool.and true false)" |> roundtripCliScript) = "PACKAGE.Darklang.Stdlib.Bool.and true false"
("(Builtin.int64Add 1L 2L)" |> roundtripCliScript) = "Builtin.int64Add 1L 2L"
("and true false" |> roundtripCliScript) = "and true false"
("Bool.and true false" |> roundtripCliScript) = "Bool.and true false"
("PACKAGE.Darklang.Stdlib.Bool.and true false" |> roundtripCliScript) = "PACKAGE.Darklang.Stdlib.Bool.and true false"
("Stdlib.Bool.and true false" |> roundtripCliScript) = "PACKAGE.Darklang.Stdlib.Bool.and true false"
("Builtin.int64Add 1L 2L" |> roundtripCliScript) = "Builtin.int64Add 1L 2L"

module FunctionDeclaration =
// single 'normal' param
Expand All @@ -576,14 +576,14 @@ else


// multiple params
("let isHigher (a: Int64) (b: Int64) : Bool = (Stdlib.Int64.greaterThan a b)"
("let isHigher (a: Int64) (b: Int64) : Bool = Stdlib.Int64.greaterThan a b"
|> roundtripCliScript) = "let isHigher (a: Int64) (b: Int64): Bool =\n PACKAGE.Darklang.Stdlib.Int64.greaterThan a b"



module FnCalls =
//package function call
("let sum (a : Int64) (b : Int64) : Int64 = (PACKAGE.Darklang.Stdlib.Int64.add a b)"
("let sum (a : Int64) (b : Int64) : Int64 = PACKAGE.Darklang.Stdlib.Int64.add a b"
|> roundtripCliScript) = "let sum (a: Int64) (b: Int64): Int64 =\n PACKAGE.Darklang.Stdlib.Int64.add a b"


Expand All @@ -594,11 +594,11 @@ else
type BookID = Int64

let getTitle (bookId: BookID): String =
let book = (Library.getBook bookId)
(getNameFromBook book)
let book = Library.getBook bookId
getNameFromBook book

let curiousGeorgeBookId = 101L
(Builtin.printLine (getTitle curiousGeorgeBookId))
Builtin.printLine (getTitle curiousGeorgeBookId)

0L
"""
Expand All @@ -612,6 +612,6 @@ let getTitle (bookId: BookID): String =

let curiousGeorgeBookId =
101L
Builtin.printLine getTitle curiousGeorgeBookId
Builtin.printLine (getTitle curiousGeorgeBookId)

0L"""
2 changes: 1 addition & 1 deletion backend/tests/Tests/TreeSitter.Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let toStringTest =

Expect.equal
(tree.Root.ToString())
"(source_file (fn_decl keyword_let: (keyword) name: (fn_identifier) params: (fn_decl_params (fn_decl_param symbol_left_paren: (symbol) identifier: (variable_identifier) symbol_colon: (symbol) typ: (type_reference (builtin_type)) symbol_right_paren: (symbol))) symbol_colon: (symbol) return_type: (type_reference (builtin_type)) symbol_equals: (symbol) body: (expression (infix_operation left: (expression (variable_identifier)) operator: (operator) right: (expression (int64_literal digits: (digits (positive_digits)) suffix: (symbol)))))))"
"(source_file (fn_decl keyword_let: (keyword) name: (fn_identifier) params: (fn_decl_params (fn_decl_param symbol_left_paren: (symbol) identifier: (variable_identifier) symbol_colon: (symbol) typ: (type_reference (builtin_type)) symbol_right_paren: (symbol))) symbol_colon: (symbol) return_type: (type_reference (builtin_type)) symbol_equals: (symbol) body: (expression (infix_operation left: (expression (simple_expression (variable_identifier))) operator: (operator) right: (expression (simple_expression (int64_literal digits: (digits (positive_digits)) suffix: (symbol))))))))"
""

let tests = testList "TreeSitter" [ toStringTest ]
25 changes: 12 additions & 13 deletions packages/darklang/languageTools/parser/expr.dark
Original file line number Diff line number Diff line change
Expand Up @@ -903,7 +903,7 @@ module Darklang =
let parseFunctionCall
(node: ParsedNode)
: Stdlib.Result.Result<WrittenTypes.Expr, WrittenTypes.Unparseable> =
if node.typ == "function_call" then
if node.typ == "apply" then
let fnNameNode =
findAndParseRequired node "fn" Identifiers.parseQualifiedFunction

Expand All @@ -916,18 +916,11 @@ module Darklang =
|> Stdlib.List.map Expr.parse
|> Stdlib.Result.collect

let symbolLeftParen = findField node "symbol_left_paren"
let symbolRightParen = findField node "symbol_right_paren"
match fnNameNode, args with
| Ok fnName, Ok args ->
let fnName = WrittenTypes.Expr.EFnName(node.range, fnName)

match fnNameNode, args, symbolLeftParen, args, symbolRightParen with
| Ok fnName, args, Ok symLeftParen, Ok args, Ok symRightParen ->
(WrittenTypes.Expr.EFnCall(
node.range,
fnName,
args,
symLeftParen.range,
symRightParen.range
))
(WrittenTypes.Expr.EApply(node.range, fnName, [], args))
|> Stdlib.Result.Result.Ok

| _ -> createUnparseableError node
Expand All @@ -944,6 +937,10 @@ module Darklang =
match node.typ with
// simple
| "paren_expression" -> findAndParseRequired node "expr" Expr.parse
| "simple_expression" ->
match node.children with
| [ single ] -> parseCase single
| _ -> createUnparseableError node

| "unit" -> (WrittenTypes.Expr.EUnit node.range) |> Stdlib.Result.Result.Ok
| "bool_literal" -> parseBoolLiteral node
Expand Down Expand Up @@ -983,7 +980,7 @@ module Darklang =
// fn calls
| "infix_operation" -> parseInfixOperation node
| "lambda_expression" -> parseLambda node
| "function_call" -> parseFunctionCall node
| "apply" -> parseFunctionCall node

| _ -> createUnparseableError node

Expand All @@ -996,6 +993,8 @@ module Darklang =
match node.children with
| [ single ] -> parseCase single
| _ -> createUnparseableError node
elif node.typ == "simple_expression" then
parseCase node
elif node.typ == "paren_expression" then
findAndParseRequired node "expr" Expr.parse
else
Expand Down
19 changes: 9 additions & 10 deletions packages/darklang/languageTools/semanticTokens.dark
Original file line number Diff line number Diff line change
Expand Up @@ -750,18 +750,17 @@ module Darklang =


// hacky temp. syntax -- see `grammar.js`
// (Int64.add 1L 2L)
| EFnCall(range, fnName, args, symbolLeftParen, symbolRightParen) ->
[ // (
[ makeToken symbolLeftParen TokenType.Symbol ]
// Int64.add
QualifiedFnIdentifier.tokenize fnName
// 1L 2L
// Int64.add (1L) (2L)
| EFnName(_, fnName) -> QualifiedFnIdentifier.tokenize fnName

| EApply(range, lhs, typeArgs, args) ->
[ Expr.tokenize lhs
(typeArgs
|> Stdlib.List.map (fun typeArg -> TypeReference.tokenize typeArg)
|> Stdlib.List.flatten)
(args
|> Stdlib.List.map (fun arg -> Expr.tokenize arg)
|> Stdlib.List.flatten)
// )
[ makeToken symbolRightParen TokenType.Symbol ] ]
|> Stdlib.List.flatten) ]
|> Stdlib.List.flatten


Expand Down
11 changes: 6 additions & 5 deletions packages/darklang/languageTools/writtenTypes.dark
Original file line number Diff line number Diff line change
Expand Up @@ -332,12 +332,13 @@ module Darklang =
// | EApply of Range * lhs: Expr * args: List<Expr>
// | EFnName of QualifiedFnIdentifier

| EFnCall of
| EApply of
Range *
fnName: QualifiedFnIdentifier *
args: List<Expr> *
symbolLeftParen: Range *
symbolRightParen: Range
lhs: Expr *
typeArgs: List<TypeReference.TypeReference> *
args: List<Expr>

| EFnName of Range * name: QualifiedFnIdentifier



Expand Down
14 changes: 6 additions & 8 deletions packages/darklang/languageTools/writtenTypesToProgramTypes.dark
Original file line number Diff line number Diff line change
Expand Up @@ -457,17 +457,15 @@ module Darklang =

ProgramTypes.Expr.ELambda(gid (), pats, body)

| EFnCall(_, fnName, args, _, _) ->
| EFnName(_, fnName) ->
let fnName = Identifiers.QualifiedFn.toPT onMissing fnName
ProgramTypes.Expr.EFnName(gid (), fnName)

let fnNameExpr = ProgramTypes.Expr.EFnName(gid (), fnName)
| EApply(_, fn, typeArgs, args) ->
let fn = toPT onMissing fn
let args = Stdlib.List.map args (fun a -> toPT onMissing a)

ProgramTypes.Expr.EApply(
gid (),
fnNameExpr,
[],
Stdlib.List.map args (fun a -> toPT onMissing a)
)
ProgramTypes.Expr.EApply(gid (), fn, [], args)


module FunctionDeclaration =
Expand Down
5 changes: 4 additions & 1 deletion packages/darklang/prettyPrinter/programTypes.dark
Original file line number Diff line number Diff line change
Expand Up @@ -705,7 +705,10 @@ module Darklang =

let argsPart =
args
|> Stdlib.List.map (fun arg -> PrettyPrinter.ProgramTypes.expr arg)
|> Stdlib.List.map (fun arg ->
match arg with
| EApply(_, _, _, _) -> $"({PrettyPrinter.ProgramTypes.expr arg})"
| _ -> PrettyPrinter.ProgramTypes.expr arg)
|> Stdlib.String.join " "

match typeArgs with
Expand Down
68 changes: 47 additions & 21 deletions tree-sitter-darklang/grammar.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,32 @@ module.exports = grammar({
// ---------------------
// Expressions
// ---------------------
expression: $ =>

/**
* `simple_expression` vs. `expression`:
*
* `simple_expression`:
* includes simple elements that have distinct starting and ending points, typically not requiring parentheses for clarity.
* e.g. literals, variables, etc.
*
* `expression`:
* Enompasses both simple expressions and more complex expressions (e.g. infix operations, function calls, etc.).
* These are elements that may require parentheses to disambiguate the order and grouping of elements.
*
* e.g.
* `myFunction myFunction2 arg arg2`
*
* without parentheses, It's unclear whether `arg2` is supposed to be a second argument to `myFunction2`:
* myFunction (myFunction2 arg arg2)
*
* or a second argument to `myFunction`:
* myFunction (myFunction2 arg) (arg2)
*
*/

// TODO: reconsider having enum_literal as a simple_expression
simple_expression: $ =>
choice(
$.paren_expression,
$.unit,
$.bool_literal,
$.int8_literal,
Expand All @@ -317,14 +340,20 @@ module.exports = grammar({
$.dict_literal,
$.record_literal,
$.enum_literal,
$.variable_identifier,
),

expression: $ =>
choice(
$.paren_expression,
$.simple_expression,
$.if_expression,
$.let_expression,
$.variable_identifier,

$.match_expression,

$.infix_operation,
$.function_call,
$.apply,

$.field_access,
$.lambda_expression,
Expand Down Expand Up @@ -729,23 +758,20 @@ module.exports = grammar({
field("rhs", $.expression),
),

/**
* e.g. `Int64.add 1 2
*
* This is currently a bit hacky, requiring parens around the function call,
* in order to help tree-sitter parse it correctly.
*
* There's certainly a better way to remove ambiguities. TODO
*
* TODO maybe call this "apply" instead
* sometimes the thing we are 'applying' is not directly a function
*/
function_call: $ =>
seq(
field("symbol_left_paren", alias("(", $.symbol)),
field("fn", $.qualified_fn_name),
field("args", repeat1($.expression)),
field("symbol_right_paren", alias(")", $.symbol)),
//
// Function call
// e.g. `Int64.add 1 2
apply: $ =>
prec.right(
seq(
field("fn", $.qualified_fn_name),
field(
"args",
repeat1(choice($.paren_expression, $.simple_expression)),
),
// the new line is used as a delimiter
optional($.newline),
),
),

let_expression: $ =>
Expand Down
Loading