Skip to content

Commit

Permalink
feat(compiler): Partial function application
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-snezhko committed Apr 7, 2024
1 parent dac76f2 commit 4b29cba
Show file tree
Hide file tree
Showing 14 changed files with 869 additions and 178 deletions.
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,
"To use partial application, prefix the function call with `partial`.",
),
)
},
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

0 comments on commit 4b29cba

Please sign in to comment.