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

feat(compiler)!: Partial function application #2091

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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
92 changes: 92 additions & 0 deletions compiler/src/formatting/fmt.re
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ type formatter = {
print_attribute: (formatter, attribute) => Doc.t,
print_application_argument:
(formatter, ~infix_wrap: t => t=?, application_argument) => Doc.t,
print_partial_application_argument:
(formatter, ~infix_wrap: t => t=?, partial_application_argument) => Doc.t,
print_if:
(
formatter,
Expand Down Expand Up @@ -1157,6 +1159,32 @@ let print_application_argument = (fmt, ~infix_wrap=?, arg) => {
++ fmt.print_expression(fmt, ~infix_wrap?, arg.paa_expr);
};

let print_partial_application_argument = (fmt, ~infix_wrap=?, arg) => {
(
switch (arg.ppaa_label) {
| Unlabeled => empty
| Labeled({txt: label, loc: label_loc})
| Default({txt: label, loc: label_loc}) =>
string(label)
++ string("=")
++ fmt.print_comment_range(
fmt,
label_loc,
switch (arg.ppaa_expr) {
| ArgumentGiven(expr) => expr.pexp_loc
| ArgumentHole(loc) => loc
},
)
}
)
++ (
switch (arg.ppaa_expr) {
| ArgumentGiven(expr) => fmt.print_expression(fmt, ~infix_wrap?, expr)
| ArgumentHole(_) => string("_")
}
);
};

let print_if =
(fmt, ~force_blocks=false, ~loc, condition, true_branch, false_branch) =>
if (force_blocks) {
Expand Down Expand Up @@ -1743,6 +1771,69 @@ let print_expression = (fmt, ~infix_wrap=d => group(indent(d)), expr) => {
++ break,
),
)
| PExpPartial(fn, args) =>
string("partial")
++ fmt.print_comment_range(
fmt,
~allow_breaks=false,
~none=space,
~lead=space,
~trail=space,
enclosing_start_location(expr.pexp_loc),
fn.pexp_loc,
)
++ group(
fmt.print_grouped_access_expression(fmt, fn)
++ parens(
indent(
concat_map(
~lead=
next =>
fmt.print_comment_range(
fmt,
~none=break,
~lead=if_broken(space, empty),
~trail=breakable_space,
fn.pexp_loc,
next.ppaa_loc,
),
~sep=
(prev, next) =>
fmt.print_comment_range(
fmt,
~none=breakable_space,
~lead=space,
~trail=breakable_space,
prev.ppaa_loc,
next.ppaa_loc,
),
~trail=
prev =>
fmt.print_comment_range(
fmt,
~block_end=true,
~lead=space,
prev.ppaa_loc,
enclosing_end_location(expr.pexp_loc),
),
~f=
(~final, a) =>
if (final) {
group(
fmt.print_partial_application_argument(fmt, a),
);
} else {
group(
fmt.print_partial_application_argument(fmt, a)
++ comma,
);
},
args,
),
)
++ break,
),
)
| PExpLambda(
[
{
Expand Down Expand Up @@ -4119,6 +4210,7 @@ let default_formatter: formatter = {
print_match_branch,
print_attribute,
print_application_argument,
print_partial_application_argument,
print_if,
print_assignment,
print_expression,
Expand Down
25 changes: 25 additions & 0 deletions compiler/src/parsing/ast_helper.re
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,31 @@ module Expression = {
mk(~loc, ~core_loc, ~attributes?, PExpLambda(a, b));
let apply = (~loc, ~core_loc, ~attributes=?, a, b) =>
mk(~loc, ~core_loc, ~attributes?, PExpApp(a, b));
let partial_apply = (~loc, ~core_loc, ~attributes=?, a, b) =>
mk(~loc, ~core_loc, ~attributes?, PExpPartial(a, b));
let total_apply_args = (~loc, ~core_loc, ~attributes=?, a, b) => {
let args =
List.map(
arg =>
{
paa_loc: arg.ppaa_loc,
paa_expr:
switch (arg.ppaa_expr) {
| ArgumentGiven(expr) => expr
| ArgumentHole(_) =>
raise(
SyntaxError(
loc,
Copy link
Member

@spotandjake spotandjake Nov 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we point to the arg.ppaa_loc? I feel like this error might be a little annoying as it isn't immediately clear that the _ hole is specific to partial application, at least that way the position would be telling you hey this argument is the issue specifically, an alternate here would be Hole patterns are only allowed under partial application, prefix the function call with partial. which is a bit more specific and searchable.

"To use partial application, prefix the function call with `partial`.",
Copy link
Member Author

@alex-snezhko alex-snezhko Apr 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was kind of a bandaid fix around me being a noob with LR(1) parsers and not being able to figure out how to create separate rules for partial and total applications without reduce/reduce conflicts. If anyone has insight on how to do this please let me know

),
)
},
paa_label: arg.ppaa_label,
},
b,
);
mk(~loc, ~core_loc, ~attributes?, PExpApp(a, args));
};
let construct = (~loc, ~core_loc, ~attributes=?, a, b) =>
mk(~loc, ~core_loc, ~attributes?, PExpConstruct(a, b));
let singleton_construct = (~loc, ~core_loc, ~attributes=?, a) =>
Expand Down
18 changes: 18 additions & 0 deletions compiler/src/parsing/ast_helper.rei
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,24 @@ module Expression: {
list(application_argument)
) =>
expression;
let partial_apply:
(
~loc: loc,
~core_loc: loc,
~attributes: attributes=?,
expression,
list(partial_application_argument)
) =>
expression;
let total_apply_args:
(
~loc: loc,
~core_loc: loc,
~attributes: attributes=?,
expression,
list(partial_application_argument)
) =>
expression;
let construct:
(
~loc: loc,
Expand Down
20 changes: 20 additions & 0 deletions compiler/src/parsing/ast_mapper.re
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,26 @@ module E = {
el,
),
)
| PExpPartial(e, el) =>
partial_apply(
~loc,
~core_loc,
~attributes,
sub.expr(sub, e),
List.map(
arg =>
{
ppaa_label: arg.ppaa_label,
ppaa_expr:
switch (arg.ppaa_expr) {
| ArgumentGiven(expr) => ArgumentGiven(sub.expr(sub, expr))
| ArgumentHole(loc) => ArgumentHole(sub.location(sub, loc))
},
ppaa_loc: sub.location(sub, arg.ppaa_loc),
},
el,
),
)
| PExpConstruct(id, e) =>
construct(
~loc,
Expand Down
1 change: 1 addition & 0 deletions compiler/src/parsing/lexer.re
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ let rec token = lexbuf => {
| "catch" => positioned(CATCH)
| "macro" => positioned(MACRO)
| "yield" => positioned(YIELD)
| "partial" => positioned(PARTIAL)
| "..." => positioned(ELLIPSIS)
| "." => positioned(DOT)
| "::" => positioned(COLONCOLON)
Expand Down
139 changes: 133 additions & 6 deletions compiler/src/parsing/parser.messages
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,26 @@ program: MODULE UIDENT EOL EOL WASMI64 THICKARROW
## In state 826, spurious reduction of production toplevel_stmt -> expr
## In state 819, spurious reduction of production lseparated_nonempty_list_inner(eos,toplevel_stmt) -> toplevel_stmt
##
program: MODULE UIDENT EOL PARTIAL LIDENT LPAREN RPAREN YIELD
##
## Ends in an error in state: 743.
##
## app_expr -> left_accessor_expr lparen option(comma) rparen . [ LPAREN LBRACK DOT ]
## partial_app_expr -> PARTIAL left_accessor_expr lparen option(comma) rparen . [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LCARET INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 EOL EOF ELSE DASH COMMA COLON AND ]
##
## The known suffix of the stack is as follows:
## PARTIAL left_accessor_expr lparen option(comma) rparen
##
program: MODULE UIDENT EOL PARTIAL LIDENT LPAREN UIDENT RPAREN YIELD
##
## Ends in an error in state: 746.
##
## app_expr -> left_accessor_expr lparen lseparated_nonempty_list_inner(comma,app_arg) option(comma) rparen . [ LPAREN LBRACK DOT ]
## partial_app_expr -> PARTIAL left_accessor_expr lparen lseparated_nonempty_list_inner(comma,app_arg) option(comma) rparen . [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LCARET INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 EOL EOF ELSE DASH COMMA COLON AND ]
##
## The known suffix of the stack is as follows:
## PARTIAL left_accessor_expr lparen lseparated_nonempty_list_inner(comma,app_arg) option(comma) rparen
##

Expected a newline character to terminate the statement.

Expand Down Expand Up @@ -1840,6 +1860,16 @@ program: MODULE UIDENT EOL WHILE LPAREN UIDENT RPAREN EOL YIELD
## In state 1, spurious reduction of production nonempty_list(eol) -> EOL
## In state 5, spurious reduction of production eols -> nonempty_list(eol)
##
program: MODULE UIDENT EOL PARTIAL YIELD
##
## Ends in an error in state: 124.
##
## partial_app_expr -> PARTIAL . left_accessor_expr lparen option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LCARET INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 EOL EOF ELSE DASH COMMA COLON AND ]
## partial_app_expr -> PARTIAL . left_accessor_expr lparen lseparated_nonempty_list_inner(comma,app_arg) option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LCARET INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 EOL EOF ELSE DASH COMMA COLON AND ]
##
## The known suffix of the stack is as follows:
## PARTIAL
##

Expected an expression.

Expand Down Expand Up @@ -3504,6 +3534,102 @@ program: MODULE UIDENT EOL IF WHILE

Expected `(` followed by a condition expression.

program: MODULE UIDENT EOL PARTIAL UIDENT YIELD
##
## Ends in an error in state: 740.
##
## app_expr -> left_accessor_expr . lparen option(comma) rparen [ LPAREN LBRACK DOT ]
## app_expr -> left_accessor_expr . lparen lseparated_nonempty_list_inner(comma,app_arg) option(comma) rparen [ LPAREN LBRACK DOT ]
## array_get -> left_accessor_expr . lbrack expr rbrack [ LPAREN LBRACK DOT ]
## partial_app_expr -> PARTIAL left_accessor_expr . lparen option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LCARET INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 EOL EOF ELSE DASH COMMA COLON AND ]
## partial_app_expr -> PARTIAL left_accessor_expr . lparen lseparated_nonempty_list_inner(comma,app_arg) option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LCARET INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 EOL EOF ELSE DASH COMMA COLON AND ]
## record_get -> left_accessor_expr . DOT lid [ LPAREN LBRACK DOT ]
## record_get -> left_accessor_expr . DOT eols lid [ LPAREN LBRACK DOT ]
##
## The known suffix of the stack is as follows:
## PARTIAL left_accessor_expr
##
## WARNING: This example involves spurious reductions.
## This implies that, although the LR(1) items shown above provide an
## accurate view of the past (what has been recognized so far), they
## may provide an INCOMPLETE view of the future (what was expected next).
## In state 265, spurious reduction of production qualified_uid -> lseparated_nonempty_list_inner(dot,type_id_str)
## In state 162, spurious reduction of production construct_expr -> qualified_uid
## In state 312, spurious reduction of production left_accessor_expr -> construct_expr
##

Expected `(` followed by partial application arguments.

program: MODULE UIDENT EOL PARTIAL LIDENT LPAREN YIELD
##
## Ends in an error in state: 741.
##
## app_expr -> left_accessor_expr lparen . option(comma) rparen [ LPAREN LBRACK DOT ]
## app_expr -> left_accessor_expr lparen . lseparated_nonempty_list_inner(comma,app_arg) option(comma) rparen [ LPAREN LBRACK DOT ]
## partial_app_expr -> PARTIAL left_accessor_expr lparen . option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LCARET INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 EOL EOF ELSE DASH COMMA COLON AND ]
## partial_app_expr -> PARTIAL left_accessor_expr lparen . lseparated_nonempty_list_inner(comma,app_arg) option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LCARET INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 EOL EOF ELSE DASH COMMA COLON AND ]
##
## The known suffix of the stack is as follows:
## PARTIAL left_accessor_expr lparen
##
## WARNING: This example involves spurious reductions.
## This implies that, although the LR(1) items shown above provide an
## accurate view of the past (what has been recognized so far), they
## may provide an INCOMPLETE view of the future (what was expected next).
## In state 4, spurious reduction of production lparen -> LPAREN
##

Expected an expression or `_`.

program: MODULE UIDENT EOL PARTIAL LIDENT LPAREN COMMA YIELD
##
## Ends in an error in state: 742.
##
## app_expr -> left_accessor_expr lparen option(comma) . rparen [ LPAREN LBRACK DOT ]
## partial_app_expr -> PARTIAL left_accessor_expr lparen option(comma) . rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LCARET INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 EOL EOF ELSE DASH COMMA COLON AND ]
##
## The known suffix of the stack is as follows:
## PARTIAL left_accessor_expr lparen option(comma)
##
## WARNING: This example involves spurious reductions.
## This implies that, although the LR(1) items shown above provide an
## accurate view of the past (what has been recognized so far), they
## may provide an INCOMPLETE view of the future (what was expected next).
## In state 39, spurious reduction of production comma -> COMMA
## In state 516, spurious reduction of production option(comma) -> comma
##

Expected a comma-separated list of partial application arguments or `)` to complete the partial application.

program: MODULE UIDENT EOL PARTIAL LIDENT LPAREN UIDENT YIELD
##
## Ends in an error in state: 744.
##
## app_expr -> left_accessor_expr lparen lseparated_nonempty_list_inner(comma,app_arg) . option(comma) rparen [ LPAREN LBRACK DOT ]
## lseparated_nonempty_list_inner(comma,app_arg) -> lseparated_nonempty_list_inner(comma,app_arg) . comma app_arg [ RPAREN EOL COMMA ]
## partial_app_expr -> PARTIAL left_accessor_expr lparen lseparated_nonempty_list_inner(comma,app_arg) . option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LCARET INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 EOL EOF ELSE DASH COMMA COLON AND ]
##
## The known suffix of the stack is as follows:
## PARTIAL left_accessor_expr lparen lseparated_nonempty_list_inner(comma,app_arg)
##
## WARNING: This example involves spurious reductions.
## This implies that, although the LR(1) items shown above provide an
## accurate view of the past (what has been recognized so far), they
## may provide an INCOMPLETE view of the future (what was expected next).
## In state 265, spurious reduction of production qualified_uid -> lseparated_nonempty_list_inner(dot,type_id_str)
## In state 162, spurious reduction of production construct_expr -> qualified_uid
## In state 312, spurious reduction of production left_accessor_expr -> construct_expr
## In state 287, spurious reduction of production non_assign_expr -> left_accessor_expr
## In state 263, spurious reduction of production non_binop_expr -> non_assign_expr
## In state 194, spurious reduction of production annotated_expr -> non_binop_expr
## In state 321, spurious reduction of production non_stmt_expr -> annotated_expr
## In state 187, spurious reduction of production expr -> non_stmt_expr
## In state 514, spurious reduction of production app_arg -> expr
## In state 517, spurious reduction of production lseparated_nonempty_list_inner(comma,app_arg) -> app_arg
##

Expected a comma or `)` to complete the partial application.

program: MODULE UIDENT EOL FOREIGN WASM LIDENT COLON UIDENT FROM YIELD
##
## Ends in an error in state: 753.
Expand Down Expand Up @@ -6617,21 +6743,22 @@ program: MODULE UIDENT EOL WASMI64 COLON UIDENT LCARET UIDENT RPAREN

Expected `>` to complete the type.

program: MODULE UIDENT EOL WASMI64 DOT LIDENT LPAREN UNDERSCORE
program: MODULE UIDENT EOL BIGINT LPAREN YIELD
##
## Ends in an error in state: 468.
## Ends in an error in state: 279.
##
## app_expr -> record_get lparen . option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LPAREN LCARET LBRACK INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 GETS EOL EOF ELSE DOT DASH COMMA COLON ]
## app_expr -> record_get lparen . lseparated_nonempty_list_inner(comma,expr) option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LPAREN LCARET LBRACK INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 GETS EOL EOF ELSE DOT DASH COMMA COLON ]
## app_expr -> left_accessor_expr lparen . option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LPAREN LCARET LBRACK INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 GETS EOL EOF ELSE DOT DASH COMMA COLON AND ]
## app_expr -> left_accessor_expr lparen . lseparated_nonempty_list_inner(comma,app_arg) option(comma) rparen [ THICKARROW STAR SLASH SEMI RPAREN RCARET RBRACK RBRACE PIPE LPAREN LCARET LBRACK INFIX_90 INFIX_80 INFIX_70 INFIX_60 INFIX_50 INFIX_40 INFIX_30 INFIX_120 INFIX_110 INFIX_100 GETS EOL EOF ELSE DOT DASH COMMA COLON AND ]
##
## The known suffix of the stack is as follows:
## record_get lparen
## left_accessor_expr lparen
##
## WARNING: This example involves spurious reductions.
## This implies that, although the LR(1) items shown above provide an
## accurate view of the past (what has been recognized so far), they
## may provide an INCOMPLETE view of the future (what was expected next).
## In state 2, spurious reduction of production lparen -> LPAREN
## In state 1, spurious reduction of production nonempty_list(eol) -> EOL
## In state 5, spurious reduction of production eols -> nonempty_list(eol)
##
program: MODULE UIDENT EOL LBRACKRCARET RBRACK LPAREN COMMA WHILE
##
Expand Down
Loading
Loading