Permalink
Browse files

Fix the parsing of casting operator

Summary:
as per title

According to http://php.net/manual/en/language.types.type-juggling.php, only few things can be cast. This fixes this behavior.

Goal of this diff is to maintain parity with hphpc, so no new tests are added. In a follow up diff, I'll fix `(f)($x, $y)` which will include new test cases.

Reviewed By: jamesjwu

Differential Revision: D8062988
  • Loading branch information...
oulgen authored and fredemmott committed May 22, 2018
1 parent a4da482 commit 1ef6d97af2cb12c83dedb9aa0aaf21bd53770f9d
@@ -1508,7 +1508,8 @@ module WithStatementAndDeclAndTypeParser
cast-expression:
( cast-type ) unary-expression
cast-type:
array, bool, double, float, int, object, string, unset or a name
array, bool, double, float, real, int, integer, object, string, binary,
unset
TODO: This implies that a cast "(name)" can only be a simple name, but
I would expect that (\Foo\Bar), (:foo), (array<int>), and the like
@@ -1535,14 +1536,11 @@ module WithStatementAndDeclAndTypeParser
let (parser, type_token) = next_token parser in
let type_token_kind = Token.kind type_token in
let (parser, right_paren) = next_token parser in
let is_easy_cast_type_or_at_least_name =
match type_token_kind with
| Array | Bool | Double | Float | Int | Object | String | Unset -> Some true
| Name -> Some false
| _ -> None in
let is_cast = Token.kind right_paren = RightParen &&
Option.value_map ~default:false is_easy_cast_type_or_at_least_name
~f:(fun b -> b || token_implies_cast (peek_token_kind parser)) in
match type_token_kind with
| Array | Bool | Boolean | Double | Float | Real | Int | Integer
| Object | String | Binary | Unset -> true
| _ -> false in
if is_cast then
let (parser, type_token) = Make.token parser type_token in
let (parser, right_paren) = Make.token parser right_paren in
@@ -1390,15 +1390,17 @@ let as_case_insensitive_keyword text =
non-lower versions in our codebase. *)
let lower = String.lowercase_ascii text in
match lower with
| "__halt_compiler" | "abstract" | "and" | "array" | "as" | "bool" | "break" | "callable"
| "__halt_compiler" | "abstract" | "and" | "array" | "as" | "bool" | "boolean" | "break"
| "callable"
| "case" | "catch" | "class" | "clone" | "const" | "continue" | "declare" | "default"
| "die" | "do" | "echo" | "else" | "elseif" | "empty" | "enddeclare" | "endfor"
| "endforeach" | "endif" | "endswitch" | "endwhile" | "eval" | "exit" | "extends" | "false"
| "final" | "finally" | "for" | "foreach" | "function" | "global" | "goto" | "if"
| "implements" | "include" | "include_once" | "inout" | "instanceof" | "insteadof" | "int"
| "integer"
| "interface" | "isset" | "list" | "namespace" | "new" | "null" | "or" | "parent"
| "print" | "private" | "protected" | "public" | "require" | "require_once"
| "return" | "self" | "static" | "switch" | "throw" | "trait"
| "return" | "self" | "static" | "string" | "switch" | "throw" | "trait"
| "try" | "true" | "unset" | "use" | "using" | "var" | "void" | "while"
| "xor" | "yield" -> lower
| _ -> text
@@ -188,7 +188,6 @@ type t =
| ErrorSyntax
| ListItem
let to_string kind =
match kind with
| Token _ -> "token"
@@ -30,7 +30,9 @@ type t =
| Attribute
| Await
| Backslash
| Binary
| Bool
| Boolean
| Break
| Case
| Catch
@@ -82,6 +84,7 @@ type t =
| Instanceof
| Insteadof
| Int
| Integer
| Interface
| Is
| Isset
@@ -100,6 +103,7 @@ type t =
| Private
| Protected
| Public
| Real
| Require
| Require_once
| Required
@@ -229,7 +233,6 @@ type t =
| XHPComment
| Markup
let from_string keyword =
match keyword with
| "true" -> Some BooleanLiteral
@@ -243,7 +246,9 @@ let from_string keyword =
| "attribute" -> Some Attribute
| "await" -> Some Await
| "\\" -> Some Backslash
| "binary" -> Some Binary
| "bool" -> Some Bool
| "boolean" -> Some Boolean
| "break" -> Some Break
| "case" -> Some Case
| "catch" -> Some Catch
@@ -295,6 +300,7 @@ let from_string keyword =
| "instanceof" -> Some Instanceof
| "insteadof" -> Some Insteadof
| "int" -> Some Int
| "integer" -> Some Integer
| "interface" -> Some Interface
| "is" -> Some Is
| "isset" -> Some Isset
@@ -313,6 +319,7 @@ let from_string keyword =
| "private" -> Some Private
| "protected" -> Some Protected
| "public" -> Some Public
| "real" -> Some Real
| "require" -> Some Require
| "require_once" -> Some Require_once
| "required" -> Some Required
@@ -428,7 +435,9 @@ let to_string kind =
| Attribute -> "attribute"
| Await -> "await"
| Backslash -> "\\"
| Binary -> "binary"
| Bool -> "bool"
| Boolean -> "boolean"
| Break -> "break"
| Case -> "case"
| Catch -> "catch"
@@ -480,6 +489,7 @@ let to_string kind =
| Instanceof -> "instanceof"
| Insteadof -> "insteadof"
| Int -> "int"
| Integer -> "integer"
| Interface -> "interface"
| Is -> "is"
| Isset -> "isset"
@@ -498,6 +508,7 @@ let to_string kind =
| Private -> "private"
| Protected -> "protected"
| Public -> "public"
| Real -> "real"
| Require -> "require"
| Require_once -> "require_once"
| Required -> "required"
@@ -81,8 +81,12 @@ let rec parse_type_specifier ?(allow_var=false) parser =
*)
| Double (* TODO: Specification does not mention double; fix it. *)
| Bool
| Boolean
| Binary
| Int
| Integer
| Float
| Real
| Num
| String
| Arraykey
@@ -723,8 +723,12 @@ class EditableToken extends EditableSyntax
return new AwaitToken(leading, trailing);
case '\':
return new BackslashToken(leading, trailing);
case 'binary':
return new BinaryToken(leading, trailing);
case 'bool':
return new BoolToken(leading, trailing);
case 'boolean':
return new BooleanToken(leading, trailing);
case 'break':
return new BreakToken(leading, trailing);
case 'case':
@@ -827,6 +831,8 @@ class EditableToken extends EditableSyntax
return new InsteadofToken(leading, trailing);
case 'int':
return new IntToken(leading, trailing);
case 'integer':
return new IntegerToken(leading, trailing);
case 'interface':
return new InterfaceToken(leading, trailing);
case 'is':
@@ -863,6 +869,8 @@ class EditableToken extends EditableSyntax
return new ProtectedToken(leading, trailing);
case 'public':
return new PublicToken(leading, trailing);
case 'real':
return new RealToken(leading, trailing);
case 'require':
return new RequireToken(leading, trailing);
case 'require_once':
@@ -1245,13 +1253,27 @@ class BackslashToken extends EditableToken
super('\', leading, trailing, '\');
}
}
class BinaryToken extends EditableToken
{
constructor(leading, trailing)
{
super('binary', leading, trailing, 'binary');
}
}
class BoolToken extends EditableToken
{
constructor(leading, trailing)
{
super('bool', leading, trailing, 'bool');
}
}
class BooleanToken extends EditableToken
{
constructor(leading, trailing)
{
super('boolean', leading, trailing, 'boolean');
}
}
class BreakToken extends EditableToken
{
constructor(leading, trailing)
@@ -1609,6 +1631,13 @@ class IntToken extends EditableToken
super('int', leading, trailing, 'int');
}
}
class IntegerToken extends EditableToken
{
constructor(leading, trailing)
{
super('integer', leading, trailing, 'integer');
}
}
class InterfaceToken extends EditableToken
{
constructor(leading, trailing)
@@ -1735,6 +1764,13 @@ class PublicToken extends EditableToken
super('public', leading, trailing, 'public');
}
}
class RealToken extends EditableToken
{
constructor(leading, trailing)
{
super('real', leading, trailing, 'real');
}
}
class RequireToken extends EditableToken
{
constructor(leading, trailing)
@@ -20934,7 +20970,9 @@ exports.AsyncToken = AsyncToken;
exports.AttributeToken = AttributeToken;
exports.AwaitToken = AwaitToken;
exports.BackslashToken = BackslashToken;
exports.BinaryToken = BinaryToken;
exports.BoolToken = BoolToken;
exports.BooleanToken = BooleanToken;
exports.BreakToken = BreakToken;
exports.CaseToken = CaseToken;
exports.CatchToken = CatchToken;
@@ -20986,6 +21024,7 @@ exports.InoutToken = InoutToken;
exports.InstanceofToken = InstanceofToken;
exports.InsteadofToken = InsteadofToken;
exports.IntToken = IntToken;
exports.IntegerToken = IntegerToken;
exports.InterfaceToken = InterfaceToken;
exports.IsToken = IsToken;
exports.IssetToken = IssetToken;
@@ -21004,6 +21043,7 @@ exports.PrintToken = PrintToken;
exports.PrivateToken = PrivateToken;
exports.ProtectedToken = ProtectedToken;
exports.PublicToken = PublicToken;
exports.RealToken = RealToken;
exports.RequireToken = RequireToken;
exports.Require_onceToken = Require_onceToken;
exports.RequiredToken = RequiredToken;
@@ -1,6 +1,6 @@
{ "description" :
"@generated JSON schema of the Hack Full Fidelity Parser AST",
"version" : "2018-03-15-0001",
"version" : "2018-03-15-0002",
"trivia" : [
{ "trivia_kind_name" : "WhiteSpace",
"trivia_type_name" : "whitespace" },
@@ -43,8 +43,12 @@
"token_text" : "await" },
{ "token_kind" : "Backslash",
"token_text" : "\\" },
{ "token_kind" : "Binary",
"token_text" : "binary" },
{ "token_kind" : "Bool",
"token_text" : "bool" },
{ "token_kind" : "Boolean",
"token_text" : "boolean" },
{ "token_kind" : "Break",
"token_text" : "break" },
{ "token_kind" : "Case",
@@ -147,6 +151,8 @@
"token_text" : "insteadof" },
{ "token_kind" : "Int",
"token_text" : "int" },
{ "token_kind" : "Integer",
"token_text" : "integer" },
{ "token_kind" : "Interface",
"token_text" : "interface" },
{ "token_kind" : "Is",
@@ -183,6 +189,8 @@
"token_text" : "protected" },
{ "token_kind" : "Public",
"token_text" : "public" },
{ "token_kind" : "Real",
"token_text" : "real" },
{ "token_kind" : "Require",
"token_text" : "require" },
{ "token_kind" : "Require_once",
@@ -2114,4 +2122,4 @@
"type_name" : "syntax_list",
"description" : "syntax_list",
"prefix" : "",
"fields" : [ ] } ] }
"fields" : [ ] } ] }
@@ -9,7 +9,7 @@
(* If you make changes to the schema that cause it to serialize / deserialize
differently, please update this version number *)
let full_fidelity_schema_version_number = "2018-03-15-0001"
let full_fidelity_schema_version_number = "2018-03-15-0002"
(* TODO: Consider basing the version number on an auto-generated
hash of a file rather than relying on people remembering to update it. *)
(* TODO: It may be worthwhile to investigate how Thrift describes data types
@@ -139,8 +139,10 @@ let given_text_tokens = List.map token_node_from_list [
[ "Async"; "async" ];
[ "Attribute"; "attribute" ];
[ "Await"; "await" ];
[ "Backslash"; "\\"];
[ "Backslash"; "\\" ];
[ "Binary"; "binary" ];
[ "Bool"; "bool" ];
[ "Boolean"; "boolean" ];
[ "Break"; "break" ];
[ "Case"; "case" ];
[ "Catch"; "catch" ];
@@ -192,6 +194,7 @@ let given_text_tokens = List.map token_node_from_list [
[ "Instanceof"; "instanceof" ];
[ "Insteadof"; "insteadof" ];
[ "Int"; "int" ];
[ "Integer"; "integer" ];
[ "Interface"; "interface" ];
[ "Is"; "is"];
[ "Isset"; "isset" ];
@@ -210,6 +213,7 @@ let given_text_tokens = List.map token_node_from_list [
[ "Private"; "private" ];
[ "Protected"; "protected" ];
[ "Public"; "public" ];
[ "Real"; "real" ];
[ "Require"; "require" ];
[ "Require_once"; "require_once" ];
[ "Required"; "required" ];

0 comments on commit 1ef6d97

Please sign in to comment.