From 5befe15eb839184507218ab3feb9e375edf335c3 Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Thu, 1 Oct 2009 20:10:20 +0000 Subject: [PATCH] Locations, array literal elisions, and fixed prompting. --- Cycript.l | 214 ++++++++++++++++++++++++++++------------------------- Cycript.y | 35 ++++----- Library.mm | 115 +++++++++++++++------------- Output.cpp | 23 +++--- Parser.hpp | 31 ++++++-- 5 files changed, 232 insertions(+), 186 deletions(-) diff --git a/Cycript.l b/Cycript.l index eb0c692..c711e8d 100644 --- a/Cycript.l +++ b/Cycript.l @@ -8,7 +8,21 @@ typedef cy::parser::token tk; #define T yylval->newline_ = yyextra->state_ == CYNewLine; #define C T yyextra->state_ = CYClear; #define R T yyextra->state_ = CYRestricted; -#define N if (yyextra->state_ != CYNewLine) { bool restricted(yyextra->state_ == CYRestricted); if (restricted) { yyextra->state_ = CYClear; return tk::NewLine; } else yyextra->state_ = CYNewLine; } + +#define N \ + if (yyextra->state_ != CYNewLine) { \ + bool restricted(yyextra->state_ == CYRestricted); \ + if (restricted) { \ + yyextra->state_ = CYClear; \ + return tk::NewLine; \ + } else \ + yyextra->state_ = CYNewLine; \ + } + +#define L { \ + yylloc->step(); \ + yylloc->columns(yyleng); \ +} #define YY_INPUT(data, value, size) { \ if (yyextra->size_ == 0) \ @@ -41,104 +55,106 @@ Escape \\['"\\bfnrtv]|\\0|\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4} \/\/[^\n]* ; \/\*(\n|[^\*]|\*[^/])\*\/ if (memchr(yytext, '\n', yyleng) != NULL) N // XXX: supposedly I will be screwed on very very long multi-line comments and need to replace this with a manual lexer. http://websrv.cs.fsu.edu/~engelen/courses/COP5621/Pr2.pdf ; XXX: this rule doesn't work anyway, fucking A :( -"&" C return tk::Ampersand; -"&&" C return tk::AmpersandAmpersand; -"&=" C return tk::AmpersandEqual; -"^" C return tk::Carrot; -"^=" C return tk::CarrotEqual; -"=" C return tk::Equal; -"==" C return tk::EqualEqual; -"===" C return tk::EqualEqualEqual; -"!" C return tk::Exclamation; -"!=" C return tk::ExclamationEqual; -"!==" C return tk::ExclamationEqualEqual; -"-" C return tk::Hyphen; -"-=" C return tk::HyphenEqual; -"--" C return yylval->newline_ ? tk::HyphenHyphen_ : tk::HyphenHyphen; -"->" C return tk::HyphenRight; -"<" C return tk::Left; -"<=" C return tk::LeftEqual; -"<<" C return tk::LeftLeft; -"<<=" C return tk::LeftLeftEqual; -"%" C return tk::Percent; -"%=" C return tk::PercentEqual; -"." C return tk::Period; -"|" C return tk::Pipe; -"|=" C return tk::PipeEqual; -"||" C return tk::PipePipe; -"+" C return tk::Plus; -"+=" C return tk::PlusEqual; -"++" C return yylval->newline_ ? tk::PlusPlus_ : tk::PlusPlus; -">" C return tk::Right; -">=" C return tk::RightEqual; -">>" C return tk::RightRight; -">>=" C return tk::RightRightEqual; -">>>" C return tk::RightRightRight; -">>>=" C return tk::RightRightRightEqual; -"/" C return tk::Slash; -"/=" C return tk::SlashEqual; -"*" C return tk::Star; -"*=" C return tk::StarEqual; -"~" C return tk::Tilde; - -":" C return tk::Colon; -"," C return tk::Comma; -"?" C return tk::Question; -";" C return tk::SemiColon; - -"(" C return tk::OpenParen; -")" C return tk::CloseParen; - -"{" C return tk::OpenBrace; -"}" C return tk::CloseBrace; - -"[" C return tk::OpenBracket; -"]" C return tk::CloseBracket; - -"@selector" C return tk::AtSelector; - -"break" R yylval->word_ = new CYWord("break"); return tk::Break; -"case" C yylval->word_ = new CYWord("case"); return tk::Case; -"catch" C yylval->word_ = new CYWord("catch"); return tk::Catch; -"continue" R yylval->word_ = new CYWord("continue"); return tk::Continue; -"default" C yylval->word_ = new CYWord("default"); return tk::Default; -"delete" C yylval->word_ = new CYWord("delete"); return tk::Delete; -"do" C yylval->word_ = new CYWord("do"); return tk::Do; -"else" C yylval->word_ = new CYWord("else"); return tk::Else; -"false" C yylval->false_ = new CYFalse(); return tk::False; -"finally" C yylval->word_ = new CYWord("finally"); return tk::Finally; -"for" C yylval->word_ = new CYWord("for"); return tk::For; -"function" C yylval->word_ = new CYWord("function"); return tk::Function; -"if" C yylval->word_ = new CYWord("if"); return tk::If; -"in" C yylval->word_ = new CYWord("in"); return tk::In; -"instanceof" C yylval->word_ = new CYWord("instanceof"); return tk::InstanceOf; -"new" C yylval->word_ = new CYWord("new"); return tk::New; -"null" C yylval->null_ = new CYNull(); return tk::Null; -"return" R yylval->word_ = new CYWord("return"); return tk::Return; -"switch" C yylval->word_ = new CYWord("switch"); return tk::Switch; -"this" C yylval->this_ = new CYThis(); return tk::This; -"throw" R yylval->word_ = new CYWord("throw"); return tk::Throw; -"true" C yylval->true_ = new CYTrue(); return tk::True; -"try" C yylval->word_ = new CYWord("try"); return tk::Try; -"typeof" C yylval->word_ = new CYWord("typeof"); return tk::TypeOf; -"var" C yylval->word_ = new CYWord("var"); return tk::Var; -"void" C yylval->word_ = new CYWord("void"); return tk::Void; -"while" C yylval->word_ = new CYWord("while"); return tk::While; -"with" C yylval->word_ = new CYWord("with"); return tk::With; - -[a-zA-Z$_][a-zA-Z$_0-9]* yylval->identifier_ = new CYIdentifier(apr_pstrmemdup(yyextra->pool_, yytext, yyleng)); C return tk::Identifier; - -(\.[0-9]+|(0|[1-9][0-9]*)(\.[0-9]*)?){Exponent}? yylval->number_ = new CYNumber(strtod(yytext, NULL)); C return tk::NumericLiteral; - -0[xX][0-9a-fA-F]+ C yylval->number_ = new CYNumber(strtoull(yytext + 2, NULL, 16)); return tk::NumericLiteral; - -0[bB][0-1]+ C yylval->number_ = new CYNumber(strtoull(yytext + 2, NULL, 2)); return tk::NumericLiteral; - -\"([^"\\\n]|{Escape})*\" C return tk::StringLiteral; -'([^'\\\n]|{Escape})*' C return tk::StringLiteral; - -\n N -[ \t] ; +"&" L C return tk::Ampersand; +"&&" L C return tk::AmpersandAmpersand; +"&=" L C return tk::AmpersandEqual; +"^" L C return tk::Carrot; +"^=" L C return tk::CarrotEqual; +"=" L C return tk::Equal; +"==" L C return tk::EqualEqual; +"===" L C return tk::EqualEqualEqual; +"!" L C return tk::Exclamation; +"!=" L C return tk::ExclamationEqual; +"!==" L C return tk::ExclamationEqualEqual; +"-" L C return tk::Hyphen; +"-=" L C return tk::HyphenEqual; +"--" L C return yylval->newline_ ? tk::HyphenHyphen_ : tk::HyphenHyphen; +"->" L C return tk::HyphenRight; +"<" L C return tk::Left; +"<=" L C return tk::LeftEqual; +"<<" L C return tk::LeftLeft; +"<<=" L C return tk::LeftLeftEqual; +"%" L C return tk::Percent; +"%=" L C return tk::PercentEqual; +"." L C return tk::Period; +"|" L C return tk::Pipe; +"|=" L C return tk::PipeEqual; +"||" L C return tk::PipePipe; +"+" L C return tk::Plus; +"+=" L C return tk::PlusEqual; +"++" L C return yylval->newline_ ? tk::PlusPlus_ : tk::PlusPlus; +">" L C return tk::Right; +">=" L C return tk::RightEqual; +">>" L C return tk::RightRight; +">>=" L C return tk::RightRightEqual; +">>>" L C return tk::RightRightRight; +">>>=" L C return tk::RightRightRightEqual; +"/" L C return tk::Slash; +"/=" L C return tk::SlashEqual; +"*" L C return tk::Star; +"*=" L C return tk::StarEqual; +"~" L C return tk::Tilde; + +":" L C return tk::Colon; +"," L C return tk::Comma; +"?" L C return tk::Question; +";" L C return tk::SemiColon; + +"(" L C return tk::OpenParen; +")" L C return tk::CloseParen; + +"{" L C return tk::OpenBrace; +"}" L C return tk::CloseBrace; + +"[" L C return tk::OpenBracket; +"]" L C return tk::CloseBracket; + +"@selector" L C return tk::AtSelector; + +"break" L R yylval->word_ = new CYWord("break"); return tk::Break; +"case" L C yylval->word_ = new CYWord("case"); return tk::Case; +"catch" L C yylval->word_ = new CYWord("catch"); return tk::Catch; +"continue" L R yylval->word_ = new CYWord("continue"); return tk::Continue; +"default" L C yylval->word_ = new CYWord("default"); return tk::Default; +"delete" L C yylval->word_ = new CYWord("delete"); return tk::Delete; +"do" L C yylval->word_ = new CYWord("do"); return tk::Do; +"else" L C yylval->word_ = new CYWord("else"); return tk::Else; +"false" L C yylval->false_ = new CYFalse(); return tk::False; +"finally" L C yylval->word_ = new CYWord("finally"); return tk::Finally; +"for" L C yylval->word_ = new CYWord("for"); return tk::For; +"function" L C yylval->word_ = new CYWord("function"); return tk::Function; +"if" L C yylval->word_ = new CYWord("if"); return tk::If; +"in" L C yylval->word_ = new CYWord("in"); return tk::In; +"instanceof" L C yylval->word_ = new CYWord("instanceof"); return tk::InstanceOf; +"new" L C yylval->word_ = new CYWord("new"); return tk::New; +"null" L C yylval->null_ = new CYNull(); return tk::Null; +"return" L R yylval->word_ = new CYWord("return"); return tk::Return; +"switch" L C yylval->word_ = new CYWord("switch"); return tk::Switch; +"this" L C yylval->this_ = new CYThis(); return tk::This; +"throw" L R yylval->word_ = new CYWord("throw"); return tk::Throw; +"true" L C yylval->true_ = new CYTrue(); return tk::True; +"try" L C yylval->word_ = new CYWord("try"); return tk::Try; +"typeof" L C yylval->word_ = new CYWord("typeof"); return tk::TypeOf; +"var" L C yylval->word_ = new CYWord("var"); return tk::Var; +"void" L C yylval->word_ = new CYWord("void"); return tk::Void; +"while" L C yylval->word_ = new CYWord("while"); return tk::While; +"with" L C yylval->word_ = new CYWord("with"); return tk::With; + +[a-zA-Z$_][a-zA-Z$_0-9]* yylval->identifier_ = new CYIdentifier(apr_pstrmemdup(yyextra->pool_, yytext, yyleng)); L C return tk::Identifier; + +(\.[0-9]+|(0|[1-9][0-9]*)(\.[0-9]*)?){Exponent}? yylval->number_ = new CYNumber(strtod(yytext, NULL)); L C return tk::NumericLiteral; + +0[xX][0-9a-fA-F]+ L C yylval->number_ = new CYNumber(strtoull(yytext + 2, NULL, 16)); return tk::NumericLiteral; + +0[bB][0-1]+ L C yylval->number_ = new CYNumber(strtoull(yytext + 2, NULL, 2)); return tk::NumericLiteral; + +\"([^"\\\n]|{Escape})*\" L C return tk::StringLiteral; +'([^'\\\n]|{Escape})*' L C return tk::StringLiteral; + +\n yylloc->end.lines(); yylloc->step(); N + +[ \t] L +<> L yyterminate(); %% diff --git a/Cycript.y b/Cycript.y index b7e17eb..46e81a4 100644 --- a/Cycript.y +++ b/Cycript.y @@ -189,8 +189,9 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner); %type DefaultClause %type DoWhileStatement %type Element +%type ElementOpt %type ElementList -%type ElementList_ +%type ElementListOpt %type ElseStatementOpt %type EmptyStatement %type EqualityExpression @@ -300,13 +301,13 @@ int cylex(YYSTYPE *lvalp, cy::location *llocp, void *scanner); TerminatorOpt : ";" | "\n" - | error { yyerrok; } + | error { yyerrok; driver.errors_.pop_back(); } ; Terminator : ";" | "\n" - | error { if (yychar != 0 && yychar != cy::parser::token::CloseBrace && !yylval.newline_) YYABORT; else yyerrok; } + | error { if (yychar != 0 && yychar != cy::parser::token::CloseBrace && !yylval.newline_) YYABORT; else { yyerrok; driver.errors_.pop_back(); } } ; CommaOpt @@ -397,26 +398,31 @@ PrimaryExpressionNoBF /* }}} */ /* 11.1.4 Array Initialiser {{{ */ ArrayLiteral - : "[" ElementList "]" { $$ = $2; } + : "[" ElementList "]" { $$ = new(driver.pool_) CYArray($2); } ; Element : AssignmentExpression { $$ = $1; } + ; + +ElementOpt + : Element { $$ = $1; } | { $$ = NULL; } ; -ElementList_ - : "," ElementList { $$ = $2; } +ElementListOpt + : ElementList { $$ = $1; } | { $$ = NULL; } ; ElementList - : Element ElementList_ { $$ = new(driver.pool_) CYElement($1, $2); } + : ElementOpt "," ElementListOpt { $$ = new(driver.pool_) CYElement($1, $3); } + | Element { $$ = new(driver.pool_) CYElement($1, NULL); } ; /* }}} */ /* 11.1.5 Object Initialiser {{{ */ ObjectLiteral - : "{" PropertyNameAndValueListOpt "}" { $$ = new CYObject($2); } + : "{" PropertyNameAndValueListOpt "}" { $$ = new(driver.pool_) CYObject($2); } ; PropertyNameAndValueList_ @@ -834,8 +840,7 @@ Statement ; Block - : "{" "}" { $$ = new(driver.pool_) CYEmpty(); } - | "{" StatementList "}" { $$ = $2; } + : "{" StatementListOpt "}" { $$ = $2 ?: new(driver.pool_) CYEmpty(); } ; StatementList @@ -1028,7 +1033,7 @@ FunctionBody ; Program - : SourceElements { driver.source_.push_back($1); $$ = $1; } + : SourceElements { driver.source_ = $1; } ; SourceElements @@ -1036,10 +1041,6 @@ SourceElements | { $$ = NULL; } ; -/*Command - : SourceElement { driver.source_.push_back($2); if (driver.filename_.empty() && false) YYACCEPT; $2->Show(std::cout); } - ;*/ - SourceElement : Statement { $$ = $1; } | FunctionDeclaration { $$ = $1; } @@ -1075,12 +1076,12 @@ SelectorExpressionOpt ; SelectorExpression_ - : WordOpt ":" SelectorExpressionOpt { $$ = new CYSelector($1, true, $3); } + : WordOpt ":" SelectorExpressionOpt { $$ = new(driver.pool_) CYSelector($1, true, $3); } ; SelectorExpression : SelectorExpression_ { $$ = $1; } - | Word { $$ = new CYSelector($1, false, NULL); } + | Word { $$ = new(driver.pool_) CYSelector($1, false, NULL); } ; PrimaryExpression_ diff --git a/Library.mm b/Library.mm index 1187375..2dc719e 100644 --- a/Library.mm +++ b/Library.mm @@ -931,16 +931,11 @@ CYDriver::~CYDriver() { ScannerDestroy(); } -void CYDriver::Clear() { - pool_.Clear(); - state_ = CYClear; - data_ = NULL; - size_ = 0; - source_.clear(); -} - -void cy::parser::error(const cy::parser::location_type &loc, const std::string &msg) { - std::cerr << loc << ": " << msg << std::endl; +void cy::parser::error(const cy::parser::location_type &location, const std::string &message) { + CYDriver::Error error; + error.location_ = location; + error.message_ = message; + driver.errors_.push_back(error); } void CYConsole(FILE *fin, FILE *fout, FILE *ferr) { @@ -949,67 +944,85 @@ void CYConsole(FILE *fin, FILE *fout, FILE *ferr) { __gnu_cxx::stdio_filebuf bin(fin, std::ios::in); std::istream sin(&bin); - CYDriver driver(""); - - while (!feof(fin)) { _pooled - driver.Clear(); - + restart: while (!feof(fin)) { _pooled fputs("cy# ", fout); fflush(fout); - cy::parser parser(driver); std::string command; + std::vector lines; + + read: + if (!std::getline(sin, line)) + break; + + lines.push_back(line); + command += line; + + CYDriver driver(""); + cy::parser parser(driver); + + driver.data_ = command.c_str(); + driver.size_ = command.size(); + + if (parser.parse() != 0) { + for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) { + cy::position begin(i->location_.begin); + if (begin.line != lines.size() || begin.column - 1 != lines.back().size()) { + std::cerr << i->message_ << std::endl; + goto restart; + } + } + + driver.errors_.clear(); - for (;;) { - if (!std::getline(sin, line)) - return; - command += line; - driver.data_ = command.c_str(); - driver.size_ = command.size(); - if (parser.parse() == 0) - break; fputs("cy> ", fout); fflush(fout); - } - for (std::vector::const_iterator i(driver.source_.begin()); i != driver.source_.end(); ++i) { - CYSource *source(*i); + command += '\n'; + goto read; + } - std::ostringstream str; - source->Show(str); + if (driver.source_ == NULL) + goto restart; - std::string code(str.str()); - std::cout << code << std::endl; + std::ostringstream str; + driver.source_->Show(str); - JSStringRef script(JSStringCreateWithUTF8CString(code.c_str())); + std::string code(str.str()); + std::cout << code << std::endl; - JSContextRef context(JSGetContext()); + JSStringRef script(JSStringCreateWithUTF8CString(code.c_str())); - JSValueRef exception(NULL); - JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception)); - JSStringRelease(script); + JSContextRef context(JSGetContext()); - if (exception != NULL) - result = exception; + JSValueRef exception(NULL); + JSValueRef result(JSEvaluateScript(context, script, NULL, NULL, 0, &exception)); + JSStringRelease(script); - if (!JSValueIsUndefined(context, result)) { - CFStringRef json; + if (exception != NULL) + result = exception; - @try { json: - json = JSValueToJSONCopy(context, result); - } @catch (id error) { - CYThrow(context, error, &result); - goto json; - } + if (JSValueIsUndefined(context, result)) + goto restart; - fputs([reinterpret_cast(json) UTF8String], fout); - CFRelease(json); + CFStringRef json; - fputs("\n", fout); - fflush(fout); - } + @try { json: + json = JSValueToJSONCopy(context, result); + } @catch (id error) { + CYThrow(context, error, &result); + goto json; } + + fputs([reinterpret_cast(json) UTF8String], fout); + CFRelease(json); + + fputs("\n", fout); + fflush(fout); } + + fputs("\n", fout); + fflush(fout); } MSInitialize { _pooled diff --git a/Output.cpp b/Output.cpp index 4e4040a..2b10d71 100644 --- a/Output.cpp +++ b/Output.cpp @@ -28,6 +28,13 @@ void CYArgument::Output(std::ostream &out, bool send) const { } } +void CYArray::Output(std::ostream &out) const { + out << '['; + if (elements_ != NULL) + elements_->Output(out); + out << ']'; +} + void CYBoolean::Output(std::ostream &out) const { out << (Value() ? "true" : "false"); } @@ -107,21 +114,13 @@ void CYDoWhile::Output(std::ostream &out) const { out << "while" << *test_ << ';'; } -void CYElement::Output(std::ostream &out, bool raw) const { - if (!raw) - out << '['; +void CYElement::Output(std::ostream &out) const { if (value_ != NULL) value_->Output(out, true); - if (next_ != NULL) { + if (next_ != NULL || value_ == NULL) out << ','; - next_->Output(out, true); - } - if (!raw) - out << ']'; -} - -void CYElement::Output(std::ostream &out) const { - Output(out, false); + if (next_ != NULL) + next_->Output(out); } void CYEmpty::Output(std::ostream &out) const { diff --git a/Parser.hpp b/Parser.hpp index 346fb93..2663eb8 100644 --- a/Parser.hpp +++ b/Parser.hpp @@ -5,6 +5,7 @@ #include #include +#include "location.hh" #include "Pooling.hpp" template @@ -117,7 +118,15 @@ class CYDriver { std::string filename_; - std::vector source_; + struct Error { + cy::location location_; + std::string message_; + }; + + typedef std::vector Errors; + + CYSource *source_; + Errors errors_; private: void ScannerInit(); @@ -126,8 +135,6 @@ class CYDriver { public: CYDriver(const std::string &filename); ~CYDriver(); - - void Clear(); }; struct CYForInitialiser : @@ -399,9 +406,7 @@ struct CYClause : virtual void Output(std::ostream &out) const; }; -struct CYElement : - CYLiteral -{ +struct CYElement { CYExpression *value_; CYElement *next_; @@ -411,7 +416,19 @@ struct CYElement : { } - void Output(std::ostream &out, bool raw) const; + void Output(std::ostream &out) const; +}; + +struct CYArray : + CYLiteral +{ + CYElement *elements_; + + CYArray(CYElement *elements) : + elements_(elements) + { + } + virtual void Output(std::ostream &out) const; }; -- 2.47.2