Skip to content
Closed
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ _esybuild
_esyinstall
.merlin
_release
**/*.swp
**/*.swo
Binary file added src/reason-parser/.reason_parser.mly.swo
Binary file not shown.
Binary file added src/reason-parser/.reason_parser.mly.swp
Binary file not shown.
2 changes: 2 additions & 0 deletions src/reason-parser/reason_lexer.mll
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,8 @@ rule token = parse
| "#=" { SHARPEQUAL }
| "#" operator_chars+
{ SHARPOP(lexeme_operator lexbuf) }
| "?" operator_chars+
{ OPTIONALACCESS(lexeme_operator lexbuf) }
| "#" [' ' '\t']* (['0'-'9']+ as num) [' ' '\t']*
("\"" ([^ '\010' '\013' '"' ] * as name) "\"")?
[^ '\010' '\013'] * newline
Expand Down
83 changes: 83 additions & 0 deletions src/reason-parser/reason_parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -1239,6 +1239,7 @@ let package_type_of_module_type pmty =
%token SEMISEMI
%token SHARP
%token <string> SHARPOP
%token <string> OPTIONALACCESS
%token SHARPEQUAL
%token SIG
%token STAR
Expand Down Expand Up @@ -1386,6 +1387,8 @@ conflicts.
(* PREFIXOP and BANG precedence *)
%nonassoc below_DOT_AND_SHARP (* practically same as below_SHARP but we convey purpose *)
%nonassoc SHARP (* simple_expr/toplevel_directive *)

%right OPTIONALACCESS
%nonassoc below_DOT

(* We need SHARPEQUAL to have lower precedence than `[` to make e.g.
Expand All @@ -1405,6 +1408,7 @@ conflicts.
(* Entry points *)

%start implementation (* for implementation files *)

%type <Ast_404.Parsetree.structure> implementation
%start interface (* for interface files *)
%type <Ast_404.Parsetree.signature> interface
Expand Down Expand Up @@ -3138,6 +3142,84 @@ parenthesized_expr:
{ mkexp (Pexp_send($1, $3)) }
| E as_loc(SHARPOP) simple_expr_no_call
{ mkinfixop $1 (mkoperator $2) $3 }
(*
* let res = a?.b;
*
* --generates-->
*
* let res = switch a {
* | Some(a) => Some(a.b)
* | None => None
* };
*
* let res = c?.+d;
*
* -generates->
*
* let res = switch c {
* | Some(c) => c.d <-- assuming d is optional
* | None => None
* };
*
* Same goes for ?# and ?#+ for JS objects
*)
| E OPTIONALACCESS simple_expr_no_call
{
let loc_exp = mklocation $startpos($1) $endpos($1) in
let record_name = match $1.pexp_desc with Pexp_ident({txt = Lident(str); loc;}) -> str | _ -> "x" in
let prop_name = match $3.pexp_desc with
| Pexp_ident({txt = Lident(str); loc;}) -> str
| Pexp_match({pexp_desc = Pexp_ident({txt = Lident(str); loc;})}, _) -> str
| _ -> syntax_error ()
in
let access_property = match $2 with
| "?." | "?.+" ->
mkexp (Pexp_field (
mkexp (Pexp_ident({
txt = Lident(record_name);
loc = loc_exp;
})), {
txt = Lident(prop_name);
loc = loc_exp;
}))
| "?#" | "?#+" ->
mkexp (Pexp_apply(
mkexp (Pexp_ident({
txt = Lident("##");
loc = loc_exp;
})), [
Nolabel, mkexp (Pexp_ident({ txt = Lident(record_name); loc = loc_exp}));
Nolabel, mkexp (Pexp_ident({ txt = Lident(prop_name); loc = loc_exp }));
]
))
| _ -> syntax_error ()
in
let access_property_exp = match $2 with
| "?." | "?#" -> mkexp (Pexp_construct ({txt = Lident("Some"); loc = loc_exp}, Some(access_property)))
| "?.+" | "?#+" -> access_property
| _ -> syntax_error ()
in
let some_exp = match $3.pexp_desc with
| Pexp_ident(_) -> access_property_exp
| Pexp_match(_, _) -> mkexp (Pexp_let(Nonrecursive, [{
pvb_pat = mkpat (Ppat_var(mkloc prop_name loc_exp));
pvb_expr = access_property_exp;
pvb_attributes = [];
pvb_loc = loc_exp;
}], $3));
| _ -> syntax_error () in
let some_pat =
Pat.mk ~loc:loc_exp (Ppat_construct({ txt = Lident("Some"); loc = loc_exp}, Some(mkpat (Ppat_var(mkloc record_name loc_exp))))) in
let none_pat =
Pat.mk ~loc:loc_exp (Ppat_construct({ txt = Lident("None"); loc = loc_exp;}, None)) in
let some_case =
Exp.case some_pat some_exp
in
let none_case =
Exp.case none_pat (mkexp (Pexp_construct({ txt = Lident("None"); loc = loc_exp;}, None)));
in
mkexp (Pexp_match ($1, [some_case; none_case]))
}
| E as_loc(SHARPEQUAL) simple_expr
{ let op = { $2 with txt = "#=" } in
mkinfixop $1 (mkoperator op) $3 }
Expand Down Expand Up @@ -3758,6 +3840,7 @@ mark_position_pat

| LPAREN COLONCOLON RPAREN LPAREN pattern_without_or COMMA pattern_without_or RPAREN
{ let loc_coloncolon = mklocation $startpos($2) $endpos($2) in

let loc = mklocation $symbolstartpos $endpos in
mkpat_cons loc_coloncolon (mkpat ~ghost:true ~loc (Ppat_tuple[$5;$7])) loc
}
Expand Down