From b10bd496b85e6ef23d311e5caec6cf1c954a63ce Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Tue, 20 Oct 2009 04:44:44 +0000 Subject: [PATCH] Got jQuery parsing (empty finally block, function statements, carriage return) and added strict mode with cool warnings. --- Console.cpp | 25 ++++++++++++++-------- Cycript.l | 2 +- Cycript.y | 55 +++++++++++++++++++++++++++++++----------------- Library.mm | 17 +++++++++++++-- Output.cpp | 39 +++++++++++++++++++--------------- Parser.hpp | 60 +++++++++++++++++++++++++++++++---------------------- 6 files changed, 125 insertions(+), 73 deletions(-) diff --git a/Console.cpp b/Console.cpp index 6ed69e6..77ee9f9 100644 --- a/Console.cpp +++ b/Console.cpp @@ -94,12 +94,15 @@ static void sigint(int) { #if YYDEBUG static bool bison_; #endif +static bool strict_; -void Setup(cy::parser &parser) { +void Setup(CYDriver &driver, cy::parser &parser) { #if YYDEBUG if (bison_) parser.set_debug_level(1); #endif + if (strict_) + driver.strict_ = true; } void Run(int socket, const char *data, size_t size, FILE *fout = NULL, bool expand = false) { @@ -229,7 +232,7 @@ static void Console(int socket) { else { CYDriver driver(""); cy::parser parser(driver); - Setup(parser); + Setup(driver, parser); driver.data_ = command.c_str(); driver.size_ = command.size(); @@ -237,7 +240,7 @@ static void Console(int socket) { if (parser.parse() != 0 || !driver.errors_.empty()) { for (CYDriver::Errors::const_iterator error(driver.errors_.begin()); error != driver.errors_.end(); ++error) { cy::position begin(error->location_.begin); - if (begin.line != lines.size() || begin.column - 1 != lines.back().size()) { + if (begin.line != lines.size() || begin.column - 1 != lines.back().size() || error->warning_) { cy::position end(error->location_.end); if (begin.line != lines.size()) { @@ -269,7 +272,7 @@ static void Console(int socket) { goto read; } - if (driver.source_ == NULL) + if (driver.program_ == NULL) goto restart; if (socket != -1) @@ -277,7 +280,7 @@ static void Console(int socket) { else { std::ostringstream str; CYOutput out(str); - driver.source_->Show(out); + driver.program_->Show(out); code = str.str(); } } @@ -316,7 +319,7 @@ int main(int argc, char *argv[]) { pid_t pid(_not(pid_t)); bool compile(false); - for (;;) switch (getopt(argc, argv, "cg:p:")) { + for (;;) switch (getopt(argc, argv, "cg:p:s")) { case -1: goto getopt; case '?': @@ -348,6 +351,10 @@ int main(int argc, char *argv[]) { return 1; } } break; + + case 's': + strict_ = true; + break; } getopt:; const char *script; @@ -397,7 +404,7 @@ int main(int argc, char *argv[]) { else { CYDriver driver(script ?: ""); cy::parser parser(driver); - Setup(parser); + Setup(driver, parser); char *start, *end; @@ -427,13 +434,13 @@ int main(int argc, char *argv[]) { if (parser.parse() != 0 || !driver.errors_.empty()) { for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) std::cerr << i->location_.begin << ": " << i->message_ << std::endl; - } else if (driver.source_ != NULL) + } else if (driver.program_ != NULL) if (socket != -1) Run(socket, start, end - start, stdout); else { std::ostringstream str; CYOutput out(str); - driver.source_->Show(out); + driver.program_->Show(out); std::string code(str.str()); if (compile) std::cout << code; diff --git a/Cycript.l b/Cycript.l index 115e1de..d62a14b 100644 --- a/Cycript.l +++ b/Cycript.l @@ -289,7 +289,7 @@ RegularExpressionStart_ {RegularExpressionBody}{RegularExpressionEnd_} return tk::StringLiteral; } -\n yylloc->end.lines(); yylloc->step(); N +\r?\n yylloc->end.lines(); yylloc->step(); N [ \t] L <> L yyterminate(); diff --git a/Cycript.y b/Cycript.y index c83562c..42402f3 100644 --- a/Cycript.y +++ b/Cycript.y @@ -69,6 +69,7 @@ typedef struct { CYExpression *expression_; CYFalse *false_; CYField *field_; + CYFinally *finally_; CYForInitialiser *for_; CYForInInitialiser *forin_; CYFunctionParameter *functionParameter_; @@ -83,7 +84,6 @@ typedef struct { CYProperty *property_; CYPropertyName *propertyName_; CYSelectorPart *selector_; - CYSource *source_; CYStatement *statement_; CYString *string_; CYThis *this_; @@ -328,7 +328,7 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner); %type ExpressionNoIn_ %type ExpressionNoInOpt %type ExpressionStatement -%type FinallyOpt +%type FinallyOpt %type ForComprehension %type ForStatement %type ForStatementInitialiser @@ -336,8 +336,8 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner); %type ForInStatementInitialiser %type FormalParameterList %type FormalParameterList_ -%type FunctionBody -%type FunctionDeclaration +%type FunctionBody +%type FunctionDeclaration %type FunctionExpression %type Identifier %type IdentifierOpt @@ -380,7 +380,7 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner); %type PrimaryExpression %type PrimaryExpression_ %type PrimaryExpressionNoBF -%type Program +%type Program %type PropertyName %type PropertyNameAndValueList %type PropertyNameAndValueList_ @@ -398,9 +398,10 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner); %type SelectorExpressionOpt %type ShiftExpression %type ShiftExpressionNoBF -%type SourceElement -%type SourceElements +%type SourceElement +%type SourceElements %type Statement +%type Statement_ %type StatementList %type StatementListOpt %type SwitchStatement @@ -448,16 +449,23 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner); %% -TerminatorOpt +StrictSemi + : { driver.Warning(yylloc, "warning, automatic semi-colon insertion required"); } + ; + +Terminator_ : ";" - | "\n" - | error { yyerrok; driver.errors_.pop_back(); } + | "\n" StrictSemi + ; + +TerminatorOpt + : Terminator_ + | error { yyerrok; driver.errors_.pop_back(); } StrictSemi ; Terminator - : ";" - | "\n" - | error { if (yychar != 0 && yychar != cy::parser::token::CloseBrace && !yylval.newline_) YYABORT; else { yyerrok; driver.errors_.pop_back(); } } + : Terminator_ + | error { if (yychar != 0 && yychar != cy::parser::token::CloseBrace && !yylval.newline_) YYABORT; else { yyerrok; driver.errors_.pop_back(); } } StrictSemi ; /*CommaOpt @@ -1040,7 +1048,7 @@ ExpressionNoBF /* }}} */ /* 12 Statements {{{ */ -Statement +Statement_ : Block { $$ = $1; } | VariableStatement { $$ = $1; } | EmptyStatement { $$ = $1; } @@ -1056,6 +1064,10 @@ Statement | ThrowStatement { $$ = $1; } | TryStatement { $$ = $1; } ; + +Statement + : Statement_ { $$ = $1; } + ; /* }}} */ /* 12.1 Block {{{ */ Block_ @@ -1249,7 +1261,7 @@ CatchOpt ; FinallyOpt - : "finally" Block_ { $$ = $2; } + : "finally" Block_ { $$ = new(driver.pool_) CYFinally($2); } | { $$ = NULL; } ; /* }}} */ @@ -1279,7 +1291,7 @@ FunctionBody /* }}} */ /* 14 Program {{{ */ Program - : SourceElements { driver.source_ = $1; } + : SourceElements { driver.program_ = $1; } ; SourceElements @@ -1288,7 +1300,7 @@ SourceElements ; SourceElement - : Statement { $$ = $1; } + : Statement_ { $$ = $1; } | FunctionDeclaration { $$ = $1; } ; /* }}} */ @@ -1362,7 +1374,7 @@ PrimaryExpression : ClassDefinition { $$ = $1; } ; -Statement +Statement_ : ClassDefinition { $$ = $1; } | CategoryStatement { $$ = $1; } ; @@ -1457,7 +1469,7 @@ ForInStatement : "for" "each" "(" ForInStatementInitialiser "in" Expression ")" Statement { $$ = new(driver.pool_) CYForEachIn($4, $6, $8); } ; /* }}} */ -/* JavaScript 1.7: Let Statements {{{ *//* +/* JavaScript 1.7: let Statements {{{ *//* LetStatement : "let" "(" VariableDeclarationList ")" Block_ { $$ = new(driver.pool_) CYLet($3, $5); } ; @@ -1466,5 +1478,10 @@ Statement : LetStatement ; *//* }}} */ +/* JavaScript FTW: Function Statements {{{ */ +Statement + : FunctionDeclaration { driver.Warning(yylloc, "warning, FunctionDeclaration is a SourceElement, not a Statement"); } { $$ = $1; } + ; +/* }}} */ %% diff --git a/Library.mm b/Library.mm index 1b4a198..a7da81e 100644 --- a/Library.mm +++ b/Library.mm @@ -3300,8 +3300,9 @@ CYDriver::CYDriver(const std::string &filename) : data_(NULL), size_(0), file_(NULL), + strict_(false), filename_(filename), - source_(NULL) + program_(NULL) { ScannerInit(); } @@ -3310,8 +3311,20 @@ CYDriver::~CYDriver() { ScannerDestroy(); } +void CYDriver::Warning(const cy::location &location, const char *message) { + if (!strict_) + return; + + CYDriver::Error error; + error.warning_ = true; + error.location_ = location; + error.message_ = message; + errors_.push_back(error); +} + void cy::parser::error(const cy::parser::location_type &location, const std::string &message) { CYDriver::Error error; + error.warning_ = false; error.location_ = location; error.message_ = message; driver.errors_.push_back(error); @@ -3451,7 +3464,7 @@ struct CYClient : } else { std::ostringstream str; CYOutput out(str); - driver.source_->Show(out); + driver.program_->Show(out); std::string code(str.str()); CYExecute_ execute = {pool, code.c_str()}; [client performSelectorOnMainThread:@selector(execute:) withObject:[NSValue valueWithPointer:&execute] waitUntilDone:YES]; diff --git a/Output.cpp b/Output.cpp index e6bedf4..09ee163 100644 --- a/Output.cpp +++ b/Output.cpp @@ -98,7 +98,7 @@ void CYAssignment::Output(CYOutput &out, CYFlags flags) const { } void CYBlock::Output(CYOutput &out) const { - for (CYSource *statement(statements_); statement != NULL; statement = statement->next_) + for (CYStatement *statement(statements_); statement != NULL; statement = statement->next_) statement->Output(out); } @@ -126,8 +126,10 @@ void CYCall::Output(CYOutput &out, CYFlags flags) const { } void CYCatch::Output(CYOutput &out) const { - out << "catch(" << *name_ << ')'; - code_->Output(out, true); + out << "catch(" << *name_ << "){"; + if (code_ != NULL) + code_->Show(out); + out << "}"; } void CYCategory::Output(CYOutput &out) const { @@ -300,7 +302,7 @@ void CYEmpty::Output(CYOutput &out) const { void CYEmpty::Output(CYOutput &out, bool block) const { if (next_ != NULL) - CYSource::Output(out, block); + CYStatement::Output(out, block); else out << "{}"; } @@ -345,6 +347,13 @@ void CYField::Output(CYOutput &out) const { // XXX: implement! } +void CYFinally::Output(CYOutput &out) const { + out << "finally{"; + if (code_ != NULL) + code_->Show(out); + out << "}"; +} + void CYFor::Output(CYOutput &out) const { out << "for("; if (initialiser_ != NULL) @@ -651,12 +660,12 @@ void CYSend::Output(CYOutput &out, CYFlags flags) const { out << ')'; } -void CYSource::Show(CYOutput &out) const { - for (const CYSource *next(this); next != NULL; next = next->next_) +void CYStatement::Show(CYOutput &out) const { + for (const CYStatement *next(this); next != NULL; next = next->next_) next->Output_(out); } -void CYSource::Output(CYOutput &out, bool block) const { +void CYStatement::Output(CYOutput &out, bool block) const { if (!block && !IsBlock()) Output(out); else { @@ -666,10 +675,6 @@ void CYSource::Output(CYOutput &out, bool block) const { } } -void CYSource::Output_(CYOutput &out) const { - Output(out); -} - void CYStatement::Output_(CYOutput &out) const { for (CYLabel *label(labels_); label != NULL; label = label->next_) out << *label->name_ << ':'; @@ -750,14 +755,14 @@ void CYThrow::Output(CYOutput &out) const { } void CYTry::Output(CYOutput &out) const { - out << "try"; - try_->Output(out, true); + out << "try{"; + if (code_ != NULL) + code_->Show(out); + out << "}"; if (catch_ != NULL) catch_->Output(out); - if (finally_ != NULL) { - out << "finally"; - finally_->Output(out, true); - } + if (finally_ != NULL) + finally_->Output(out); } void CYVar::Output(CYOutput &out) const { diff --git a/Parser.hpp b/Parser.hpp index f8b8b6e..6fde458 100644 --- a/Parser.hpp +++ b/Parser.hpp @@ -94,19 +94,6 @@ struct CYOutput { } }; -struct CYSource : - CYNext -{ - virtual bool IsBlock() const { - return next_ != NULL; - } - - virtual void Show(CYOutput &out) const; - virtual void Output(CYOutput &out) const = 0; - virtual void Output(CYOutput &out, bool block) const; - virtual void Output_(CYOutput &out) const; -}; - struct CYPropertyName { virtual void PropertyName(CYOutput &out) const = 0; }; @@ -163,7 +150,7 @@ struct CYLabel : }; struct CYStatement : - CYSource + CYNext { CYLabel *labels_; @@ -176,6 +163,13 @@ struct CYStatement : labels_ = new CYLabel(identifier, labels_); } + virtual bool IsBlock() const { + return next_ != NULL; + } + + virtual void Show(CYOutput &out) const; + virtual void Output(CYOutput &out) const = 0; + virtual void Output(CYOutput &out, bool block) const; virtual void Output_(CYOutput &out) const; }; @@ -213,6 +207,8 @@ class CYDriver { size_t size_; FILE *file_; + bool strict_; + enum Condition { RegExStart, RegExRest @@ -221,13 +217,14 @@ class CYDriver { std::string filename_; struct Error { + bool warning_; cy::location location_; std::string message_; }; typedef std::vector Errors; - CYSource *source_; + CYStatement *program_; Errors errors_; private: @@ -239,6 +236,8 @@ class CYDriver { ~CYDriver(); void SetCondition(Condition condition); + + void Warning(const cy::location &location, const char *message); }; enum CYFlags { @@ -854,9 +853,9 @@ struct CYMessage : bool instance_; CYExpression *type_; CYMessageParameter *parameter_; - CYSource *body_; + CYStatement *body_; - CYMessage(bool instance, CYExpression *type, CYMessageParameter *parameter, CYSource *body) : + CYMessage(bool instance, CYExpression *type, CYMessageParameter *parameter, CYStatement *body) : instance_(instance), type_(type), parameter_(parameter), @@ -1163,9 +1162,9 @@ struct CYLambda : { CYIdentifier *name_; CYFunctionParameter *parameters_; - CYSource *body_; + CYStatement *body_; - CYLambda(CYIdentifier *name, CYFunctionParameter *parameters, CYSource *body) : + CYLambda(CYIdentifier *name, CYFunctionParameter *parameters, CYStatement *body) : name_(name), parameters_(parameters), body_(body) @@ -1179,9 +1178,9 @@ struct CYLambda : struct CYFunction : CYLambda, - CYSource + CYStatement { - CYFunction(CYIdentifier *name, CYFunctionParameter *parameters, CYSource *body) : + CYFunction(CYIdentifier *name, CYFunctionParameter *parameters, CYStatement *body) : CYLambda(name, parameters, body) { } @@ -1248,15 +1247,26 @@ struct CYEmpty : virtual void Output(CYOutput &out, bool block) const; }; +struct CYFinally { + CYStatement *code_; + + CYFinally(CYStatement *code) : + code_(code) + { + } + + virtual void Output(CYOutput &out) const; +}; + struct CYTry : CYStatement { - CYStatement *try_; + CYStatement *code_; CYCatch *catch_; - CYStatement *finally_; + CYFinally *finally_; - CYTry(CYStatement *_try, CYCatch *_catch, CYStatement *finally) : - try_(_try), + CYTry(CYStatement *code, CYCatch *_catch, CYFinally *finally) : + code_(code), catch_(_catch), finally_(finally) { -- 2.45.2