Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Support for typehints and object literal elisons

Summary:
Included in this diff is support for type declarations as made popular by ActionScript. While not part of ECMAScript, if typing ever does make it into the language it will most likely look similar to this. By default type declarations will still yield a syntax error, however you may elect to tell the parser to allow these declarations by passing PARSE_TYPEHINT to the second parameter of NodeProgram.

Additionally this adds support for trailing commas in object literals. While expressly allowed by ECMA-262, trailing commas in object literals have become defacto forbidden in most client-side JavaScript applications due to poor browser option.

Test Plan:
Compiles

Reviewed By: epriestley
  • Loading branch information...
commit bd9ed38d7b0890fe4ed1723855af190d8953e5d9 1 parent 6ea3afb
@laverdet laverdet authored
View
14 node.cpp
@@ -1095,6 +1095,20 @@ Node* NodeVarDeclaration::setIterator(bool iterator) {
}
//
+// NodeTypehint: a variable declaration with a typehint
+NodeTypehint::NodeTypehint(const unsigned int lineno /* = 0 */) : Node(lineno) {}
+Node* NodeTypehint::clone(Node* node) const {
+ return Node::clone(new NodeTypehint());
+}
+
+rope_t NodeTypehint::render(render_guts_t* guts, int indentation) const {
+ rope_t ret =
+ this->_childNodes.front()->render(guts, indentation) + ":" +
+ this->_childNodes.back()->render(guts, indentation);
+ return ret;
+}
+
+//
// NodeObjectLiteral
NodeObjectLiteral::NodeObjectLiteral(const unsigned int lineno /* = 0 */) : NodeExpression(lineno) {}
Node* NodeObjectLiteral::clone(Node* node) const {
View
19 node.hpp
@@ -38,6 +38,11 @@ namespace fbjs {
RENDER_PRETTY = 1,
RENDER_MAINTAIN_LINENO = 2,
};
+ enum node_parse_enum {
+ PARSE_NONE = 0,
+ PARSE_TYPEHINT = 1,
+ PARSE_OBJECT_LITERAL_ELISON = 2,
+ };
struct render_guts_t {
unsigned int lineno;
bool pretty;
@@ -86,8 +91,8 @@ namespace fbjs {
public:
NODE_WALKER_ACCEPT_DECL;
NodeProgram();
- NodeProgram(const char* code);
- NodeProgram(FILE* file);
+ NodeProgram(const char* code, node_parse_enum opts = PARSE_NONE);
+ NodeProgram(FILE* file, node_parse_enum opts = PARSE_NONE);
virtual Node* clone(Node* node = NULL) const;
};
@@ -429,6 +434,16 @@ namespace fbjs {
};
//
+ // NodeTypehint
+ class NodeTypehint: public Node {
+ public:
+ NODE_WALKER_ACCEPT_DECL;
+ NodeTypehint(const unsigned int lineno = 0);
+ virtual Node* clone(Node* node = NULL) const;
+ virtual rope_t render(render_guts_t* guts, int indentation) const;
+ };
+
+ //
// NodeFunctionDeclaration
class NodeFunctionDeclaration: public Node {
public:
View
6 parser.cpp
@@ -60,9 +60,10 @@ void fbjs_cleanup_parser(fbjs_parse_extra* extra, void* scanner) {
//
// Parse from a file
-NodeProgram::NodeProgram(FILE* file) : Node(1) {
+NodeProgram::NodeProgram(FILE* file, node_parse_enum opts /* = PARSE_NONE */) : Node(1) {
fbjs_parse_extra extra;
void* scanner = fbjs_init_parser(&extra);
+ extra.opts = opts;
yyrestart(file, scanner); // read from file
yyparse(scanner, this);
fbjs_cleanup_parser(&extra, scanner);
@@ -70,9 +71,10 @@ NodeProgram::NodeProgram(FILE* file) : Node(1) {
//
// Parser from a string
-NodeProgram::NodeProgram(const char* str) : Node(1) {
+NodeProgram::NodeProgram(const char* str, node_parse_enum opts /* = PARSE_NONE */) : Node(1) {
fbjs_parse_extra extra;
void* scanner = fbjs_init_parser(&extra);
+ extra.opts = opts;
yy_scan_string(str, scanner); // read from string
yyparse(scanner, this);
fbjs_cleanup_parser(&extra, scanner);
View
1  parser.hpp
@@ -48,6 +48,7 @@ struct fbjs_parse_extra {
int last_paren_tok;
int last_curly_tok;
int lineno;
+ fbjs::node_parse_enum opts;
};
// Why the hell doesn't flex provide a header file?
View
9 parser.ll
@@ -98,11 +98,9 @@ FBJSBEGIN(IDENTIFIER);
yyless(0);
}
}
-<IDENTIFIER,DOT,VIRTUAL_SEMICOLON,NO_LINEBREAK>{
+<INITIAL,IDENTIFIER,DOT,VIRTUAL_SEMICOLON,NO_LINEBREAK>{
/* start conditon is all, minus REGEX */
"<!--".* /* om nom nom */
-}
-<*>{
"//".* |
[ \t\x0b\x0c\xa0\r]+ /* om nom nom */
"/*" {
@@ -242,7 +240,10 @@ FBJSBEGIN(IDENTIFIER);
}
<DOT>{
\n ++yylloc->first_line;
- [^a-zA-Z$_]+ /* om nom nom */
+ . {
+ FBJSBEGIN(INITIAL);
+ yyless(0);
+ }
}
'|\" {
std::string str = yytext;
View
28 parser.yy
@@ -42,6 +42,11 @@
using namespace fbjs;
#define yylineno (unsigned int)(yylloc.first_line)
#define parsererror(str) yyerror(&yylloc, yyscanner, NULL, str)
+ #define require_support(flag, error) \
+ if (!(yyget_extra(yyscanner)->opts & flag)) { \
+ terminate(yyscanner, error); \
+ break; \
+ }
void terminate(void* yyscanner, const char* str) {
fbjs_parse_extra* extra = yyget_extra(yyscanner);
@@ -117,7 +122,7 @@
// Statements
%type<node> statement block statement_list source_element
-%type<node> variable_statement variable_declaration_list variable_declaration initializer
+%type<node> variable_statement variable_declaration_list variable_declaration identifier_typehint_permitted initializer
%type<node> variable_declaration_list_no_in variable_declaration_no_in initializer_no_in
%type<node> empty_statement expression_statement if_statement iteration_statement continue_statement break_statement return_statement with_statement switch_statement
%type<node> case_block case_clauses_opt case_clauses labelled_statement
@@ -268,6 +273,11 @@ object_literal:
| t_LCURLY property_name_and_value_list t_VIRTUAL_SEMICOLON t_RCURLY { /* note the t_VIRTUAL_SEMICOLON hack */
$$ = $2;
}
+| t_LCURLY property_name_and_value_list t_COMMA t_VIRTUAL_SEMICOLON t_RCURLY {
+ require_support(PARSE_OBJECT_LITERAL_ELISON, "object literal elisons not supported");
+ $$ = $2;
+ }
+
;
property_name:
@@ -879,10 +889,18 @@ variable_declaration_list:
;
variable_declaration:
- identifier initializer {
+ identifier_typehint_permitted initializer {
$$ = (new NodeAssignment(ASSIGN, yylineno))->appendChild($1)->appendChild($2);
}
-| identifier
+| identifier_typehint_permitted
+;
+
+identifier_typehint_permitted:
+ identifier
+| identifier t_COLON identifier {
+ require_support(PARSE_TYPEHINT, "typehints not supported");
+ $$ = (new NodeTypehint(yylineno))->appendChild($1)->appendChild($3);
+ }
;
initializer:
@@ -1117,10 +1135,10 @@ function_expression:
;
formal_parameter_list:
- identifier {
+ identifier_typehint_permitted {
$$ = (new NodeArgList(yylineno))->appendChild($1);
}
-| formal_parameter_list t_COMMA identifier {
+| formal_parameter_list t_COMMA identifier_typehint_permitted {
$$ = $1->appendChild($3);
}
;
View
1  walker.cpp
@@ -50,6 +50,7 @@ NODE_WALKER_ACCEPT_IMPL(NodeDynamicMemberExpression, NodeExpression);
NODE_WALKER_ACCEPT_IMPL(NodeStatement, Node);
NODE_WALKER_ACCEPT_IMPL(NodeStatementWithExpression, NodeStatement);
NODE_WALKER_ACCEPT_IMPL(NodeVarDeclaration, NodeStatement);
+NODE_WALKER_ACCEPT_IMPL(NodeTypehint, Node);
NODE_WALKER_ACCEPT_IMPL(NodeFunctionDeclaration, Node);
NODE_WALKER_ACCEPT_IMPL(NodeFunctionExpression, NodeExpression);
NODE_WALKER_ACCEPT_IMPL(NodeArgList, Node);
View
1  walker.hpp
@@ -134,6 +134,7 @@ namespace fbjs {
NODE_WALKER_VISIT_IMPL(NodeStatement, Node);
NODE_WALKER_VISIT_IMPL(NodeStatementWithExpression, NodeStatement);
NODE_WALKER_VISIT_IMPL(NodeVarDeclaration, NodeStatement);
+ NODE_WALKER_VISIT_IMPL(NodeTypehint, Node);
NODE_WALKER_VISIT_IMPL(NodeFunctionDeclaration, Node);
NODE_WALKER_VISIT_IMPL(NodeFunctionExpression, NodeExpression);
NODE_WALKER_VISIT_IMPL(NodeArgList, Node);
Please sign in to comment.
Something went wrong with that request. Please try again.