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

Null coalescing operator #10428

Merged
merged 9 commits into from
Feb 14, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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: 1 addition & 1 deletion src/codegen/gencommon/dynamicOperators.ml
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ let init com handle_strings (should_change:texpr->bool) (equals_handler:texpr->t
{ e with eexpr = TBinop (op, mk_cast com.basic.tbool (run e1), mk_cast com.basic.tbool (run e2)) }
| OpAnd | OpOr | OpXor | OpShl | OpShr | OpUShr ->
{ e with eexpr = TBinop (op, mk_cast com.basic.tint (run e1), mk_cast com.basic.tint (run e2)) }
| OpAssign | OpAssignOp _ | OpInterval | OpArrow | OpIn ->
| OpAssign | OpAssignOp _ | OpInterval | OpArrow | OpIn | OpNullCoal ->
Globals.die "" __LOC__)

| TUnop (Increment as op, flag, e1)
Expand Down
4 changes: 3 additions & 1 deletion src/core/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type binop =
| OpInterval
| OpArrow
| OpIn
| OpNullCoal

type unop =
| Increment
Expand Down Expand Up @@ -555,6 +556,7 @@ let rec s_binop = function
| OpInterval -> "..."
| OpArrow -> "=>"
| OpIn -> " in "
| OpNullCoal -> "??"

let s_unop = function
| Increment -> "++"
Expand Down Expand Up @@ -1233,4 +1235,4 @@ let get_meta_options metas meta =
| [] ->
[]
in
loop metas
loop metas
3 changes: 2 additions & 1 deletion src/core/json/genjson.ml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ let rec generate_binop ctx op =
| OpInterval -> "OpInterval",None
| OpArrow -> "OpArrow",None
| OpIn -> "OpIn",None
| OpNullCoal -> "OpNullCoal",None
in
generate_adt ctx (Some (["haxe";"macro"],"Binop")) name args

Expand Down Expand Up @@ -732,4 +733,4 @@ let generate types file =
let ch = open_out_bin file in
Json.write_json (output_string ch) json;
close_out ch;
t()
t()
3 changes: 3 additions & 0 deletions src/generators/gencpp.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4218,6 +4218,7 @@ let gen_cpp_ast_expression_tree ctx class_name func_name function_args function_
| OpInterval -> "..."
| OpArrow -> "->"
| OpIn -> " in "
| OpNullCoal -> "??"
| OpAssign | OpAssignOp _ -> abort "Unprocessed OpAssign" pos

and gen_closure closure =
Expand Down Expand Up @@ -7301,6 +7302,7 @@ let cppia_op_info = function
| IaBinOp OpInterval -> ("...", 121)
| IaBinOp OpArrow -> ("=>", 122)
| IaBinOp OpIn -> (" in ", 123)
| IaBinOp OpNullCoal -> ("??", 124)
| IaBinOp OpAssignOp OpAdd -> ("+=", 201)
| IaBinOp OpAssignOp OpMult -> ("*=", 202)
| IaBinOp OpAssignOp OpDiv -> ("/=", 203)
Expand All @@ -7318,6 +7320,7 @@ let cppia_op_info = function
| IaBinOp OpAssignOp OpMod -> ("%=", 220)

| IaBinOp OpAssignOp OpIn
| IaBinOp OpAssignOp OpNullCoal
| IaBinOp OpAssignOp OpInterval
| IaBinOp OpAssignOp OpAssign
| IaBinOp OpAssignOp OpEq
Expand Down
2 changes: 1 addition & 1 deletion src/generators/genhl.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2484,7 +2484,7 @@ and eval_expr ctx e =
free ctx r;
binop r r b;
r))
| OpInterval | OpArrow | OpIn ->
| OpInterval | OpArrow | OpIn | OpNullCoal ->
die "" __LOC__)
| TUnop (Not,_,v) ->
let tmp = alloc_tmp ctx HBool in
Expand Down
2 changes: 1 addition & 1 deletion src/generators/genpy.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1081,7 +1081,7 @@ module Printer = struct
| OpShr -> ">>"
| OpUShr -> ">>"
| OpMod -> "%"
| OpInterval | OpArrow | OpIn | OpAssignOp _ -> die "" __LOC__
| OpInterval | OpArrow | OpIn | OpNullCoal | OpAssignOp _ -> die "" __LOC__

let print_string s =
Printf.sprintf "\"%s\"" (StringHelper.s_escape s)
Expand Down
2 changes: 1 addition & 1 deletion src/generators/genswf9.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1829,7 +1829,7 @@ and gen_binop ctx retval op e1 e2 t p =
gen_op A3OLt
| OpLte ->
gen_op A3OLte
| OpInterval | OpArrow | OpIn ->
| OpInterval | OpArrow | OpIn | OpNullCoal ->
die "" __LOC__

and gen_expr ctx retval e =
Expand Down
4 changes: 2 additions & 2 deletions src/macro/eval/evalDebugMisc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ let rec expr_to_value ctx env e =
| OpBoolOr ->
if is_true (loop e1) then VTrue
else loop e2
| OpInterval | OpArrow | OpIn ->
| OpInterval | OpArrow | OpIn | OpNullCoal ->
raise NoValueExpr
| _ ->
let v1 = loop e1 in
Expand Down Expand Up @@ -417,4 +417,4 @@ and write_expr ctx env expr value =

let expr_to_value_safe ctx env e =
try expr_to_value ctx env e
with NoValueExpr -> VNull
with NoValueExpr -> VNull
2 changes: 1 addition & 1 deletion src/macro/eval/evalMisc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ let get_binop_fun op p = match op with
| OpShr -> op_shr p
| OpUShr -> op_ushr p
| OpMod -> op_mod p
| OpAssign | OpBoolAnd | OpBoolOr | OpAssignOp _ | OpInterval | OpArrow | OpIn -> die ~p "" __LOC__
| OpAssign | OpBoolAnd | OpBoolOr | OpAssignOp _ | OpInterval | OpArrow | OpIn | OpNullCoal -> die ~p "" __LOC__

let prepare_callback v n =
match v with
Expand Down
2 changes: 2 additions & 0 deletions src/macro/macroApi.ml
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ let rec encode_binop op =
| OpInterval -> 21, []
| OpArrow -> 22, []
| OpIn -> 23, []
| OpNullCoal -> 24, []
in
encode_enum IBinop tag pl

Expand Down Expand Up @@ -581,6 +582,7 @@ let rec decode_op op =
| 21, [] -> OpInterval
| 22,[] -> OpArrow
| 23,[] -> OpIn
| 24,[] -> OpNullCoal
| _ -> raise Invalid_expr

let decode_unop op =
Expand Down
1 change: 1 addition & 0 deletions src/optimization/analyzerTexpr.ml
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ module Fusion = struct
| OpAssignOp _
| OpInterval
| OpIn
| OpNullCoal
| OpArrow ->
false

Expand Down
4 changes: 2 additions & 2 deletions src/optimization/analyzerTexprTransformer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ and func ctx i =
| OpAdd | OpMult | OpDiv | OpSub | OpAnd
| OpOr | OpXor | OpShl | OpShr | OpUShr | OpMod ->
true
| OpAssignOp _ | OpInterval | OpArrow | OpIn | OpAssign | OpEq
| OpAssignOp _ | OpInterval | OpArrow | OpIn | OpNullCoal | OpAssign | OpEq
| OpNotEq | OpGt | OpGte | OpLt | OpLte | OpBoolAnd | OpBoolOr ->
false
in
Expand Down Expand Up @@ -777,4 +777,4 @@ and func ctx i =
mk (TFunction {tf with tf_expr = e}) t p

let to_texpr ctx =
func ctx ctx.entry.bb_id
func ctx ctx.entry.bb_id
3 changes: 2 additions & 1 deletion src/optimization/optimizer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ let standard_precedence op =
| OpBoolAnd -> 14, left
| OpBoolOr -> 15, left
| OpArrow -> 16, left
| OpNullCoal -> 17, right
| OpAssignOp OpAssign -> 18, right (* mimics ?: *)
| OpAssign | OpAssignOp _ -> 19, right

Expand Down Expand Up @@ -385,4 +386,4 @@ let rec make_constant_expression ctx ?(concat_strings=false) e =
| None -> None
| Some e -> make_constant_expression ctx e)
with Not_found -> None) *)
| _ -> None
| _ -> None
4 changes: 3 additions & 1 deletion src/syntax/lexer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ let rec token lexbuf =
| "<<=" -> mk lexbuf (Binop (OpAssignOp OpShl))
| "||=" -> mk lexbuf (Binop (OpAssignOp OpBoolOr))
| "&&=" -> mk lexbuf (Binop (OpAssignOp OpBoolAnd))
| "??=" -> mk lexbuf (Binop (OpAssignOp OpNullCoal))
(*//| ">>=" -> mk lexbuf (Binop (OpAssignOp OpShr)) *)
(*//| ">>>=" -> mk lexbuf (Binop (OpAssignOp OpUShr)) *)
| "==" -> mk lexbuf (Binop OpEq)
Expand Down Expand Up @@ -379,6 +380,7 @@ let rec token lexbuf =
| "}" -> mk lexbuf BrClose
| "(" -> mk lexbuf POpen
| ")" -> mk lexbuf PClose
| "??" -> mk lexbuf (Binop OpNullCoal)
| "?" -> mk lexbuf Question
| "@" -> mk lexbuf At

Expand Down Expand Up @@ -636,4 +638,4 @@ let lex_xml p lexbuf =
try
not_xml ctx 0 (name <> "") (* don't allow self-closing fragments *)
with Exit ->
error Unterminated_markup p
error Unterminated_markup p
4 changes: 2 additions & 2 deletions src/syntax/parser.ml
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ let precedence op =
| OpInterval -> 7, left
| OpBoolAnd -> 8, left
| OpBoolOr -> 9, left
| OpArrow -> 10, right
| OpArrow | OpNullCoal -> 10, right
| OpAssign | OpAssignOp _ -> 11, right

let is_higher_than_ternary = function
Expand Down Expand Up @@ -425,4 +425,4 @@ let convert_abstract_flags flags =
let no_keyword what s =
match Stream.peek s with
| Some (Kwd kwd,p) -> error (Custom ("Keyword " ^ (s_keyword kwd) ^ " cannot be used as " ^ what)) p
| _ -> raise Stream.Failure
| _ -> raise Stream.Failure
1 change: 1 addition & 0 deletions src/syntax/reification.ml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ let reify in_macro =
| OpInterval -> op "OpInterval"
| OpArrow -> op "OpArrow"
| OpIn -> op "OpIn"
| OpNullCoal -> op "OpNullCoal"
in
let to_string s p =
let len = String.length s in
Expand Down
3 changes: 2 additions & 1 deletion src/typing/operators.ml
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ let make_binop ctx op e1 e2 is_assign_op with_type p =
typing_error "Unexpected =>" p
| OpIn ->
typing_error "Unexpected in" p
| OpNullCoal
| OpAssign
| OpAssignOp _ ->
die "" __LOC__
Expand Down Expand Up @@ -952,4 +953,4 @@ let type_unop ctx op flag e with_type p =
find_overload_or_make e
end
| AKUsingField _ | AKResolve _ ->
typing_error "Invalid operation" p
typing_error "Invalid operation" p
3 changes: 3 additions & 0 deletions src/typing/typeloadFields.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,9 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p =
allow_no_expr();
| (Meta.Op,[EBinop(OpAssign,_,_),_],_) :: _ ->
typing_error (cf.cf_name ^ ": Assignment overloading is not supported") p;
| (Meta.Op,[EBinop(OpAssignOp OpNullCoal,_,_),_],_) :: _
| (Meta.Op,[EBinop(OpNullCoal,_,_),_],_) :: _ ->
typing_error (cf.cf_name ^ ": Null coalescing overloading is not supported") p;
| (Meta.Op,[ETernary(_,_,_),_],_) :: _ ->
typing_error (cf.cf_name ^ ": Ternary overloading is not supported") p;
| (Meta.Op,[EBinop(op,_,_),_],_) :: _ ->
Expand Down
41 changes: 29 additions & 12 deletions src/typing/typer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1444,6 +1444,19 @@ and type_cast ctx e t p =
let texpr = loop t in
mk (TCast (type_expr ctx e WithType.value,Some texpr)) t p

and make_if_then_else ctx e0 e1 e2 with_type p =
let e1,e2,t = match with_type with
| WithType.NoValue -> e1,e2,ctx.t.tvoid
| WithType.Value _ -> e1,e2,unify_min ctx [e1; e2]
| WithType.WithType(t,src) when (match follow t with TMono _ -> true | t -> ExtType.is_void t) ->
e1,e2,unify_min_for_type_source ctx [e1; e2] src
| WithType.WithType(t,_) ->
let e1 = AbstractCast.cast_or_unify ctx t e1 e1.epos in
let e2 = AbstractCast.cast_or_unify ctx t e2 e2.epos in
e1,e2,t
in
mk (TIf (e0,e1,Some e2)) t p

and type_if ctx e e1 e2 with_type is_ternary p =
let e = type_expr ctx e WithType.value in
if is_ternary then begin match e.eexpr with
Expand All @@ -1452,22 +1465,12 @@ and type_if ctx e e1 e2 with_type is_ternary p =
end;
let e = AbstractCast.cast_or_unify ctx ctx.t.tbool e p in
let e1 = type_expr ctx (Expr.ensure_block e1) with_type in
(match e2 with
match e2 with
| None ->
mk (TIf (e,e1,None)) ctx.t.tvoid p
| Some e2 ->
let e2 = type_expr ctx (Expr.ensure_block e2) with_type in
let e1,e2,t = match with_type with
| WithType.NoValue -> e1,e2,ctx.t.tvoid
| WithType.Value _ -> e1,e2,unify_min ctx [e1; e2]
| WithType.WithType(t,src) when (match follow t with TMono _ -> true | t -> ExtType.is_void t) ->
e1,e2,unify_min_for_type_source ctx [e1; e2] src
| WithType.WithType(t,_) ->
let e1 = AbstractCast.cast_or_unify ctx t e1 e1.epos in
let e2 = AbstractCast.cast_or_unify ctx t e2 e2.epos in
e1,e2,t
in
mk (TIf (e,e1,Some e2)) t p)
make_if_then_else ctx e e1 e2 with_type p

and type_meta ?(mode=MGet) ctx m e1 with_type p =
if ctx.is_display_file then DisplayEmitter.check_display_metadata ctx [m];
Expand Down Expand Up @@ -1675,6 +1678,20 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
type_expr ctx (format_string ctx s p) with_type
| EConst c ->
Texpr.type_constant ctx.com.basic c p
| EBinop (OpNullCoal,e1,e2) ->
let vr = new value_reference ctx in
let e1 = type_expr ctx (Expr.ensure_block e1) with_type in
let e2 = type_expr ctx (Expr.ensure_block e2) with_type in
let e1 = vr#as_var "tmp" {e1 with etype = ctx.t.tnull e1.etype} in
let e_null = Builder.make_null e1.etype e1.epos in
let e_cond = mk (TBinop(OpNotEq,e1,e_null)) ctx.t.tbool e1.epos in
let iftype = WithType.WithType(e2.etype,None) in
let e_if = make_if_then_else ctx e_cond e1 e2 iftype p in
vr#to_texpr e_if
| EBinop (OpAssignOp OpNullCoal,e1,e2) ->
let e_cond = EBinop(OpNotEq,e1,(EConst(Ident "null"), p)) in
let e_if = EIf ((e_cond, p),e1,Some e2) in
type_assign ctx e1 (e_if, p) with_type p
| EBinop (op,e1,e2) ->
type_binop ctx op e1 e2 false with_type p
| EBlock [] when (match with_type with
Expand Down
1 change: 1 addition & 0 deletions std/haxe/display/JsonModuleTypes.hx
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ enum abstract JsonBinopKind<T>(String) {
var OpInterval;
var OpArrow;
var OpIn;
var OpNullCoal;
}

typedef JsonBinop<T> = {
Expand Down
5 changes: 5 additions & 0 deletions std/haxe/macro/Expr.hx
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ enum Binop {
`in`
**/
OpIn;

/**
`??`
**/
OpNullCoal;
}

/**
Expand Down
1 change: 1 addition & 0 deletions std/haxe/macro/Printer.hx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class Printer {
case OpInterval: "...";
case OpArrow: "=>";
case OpIn: "in";
case OpNullCoal: "??";
case OpAssignOp(op):
printBinop(op) + "=";
}
Expand Down
Loading