From 6c093cce11bcc8875e4459b3670811227e8dafa7 Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Thu, 1 Jul 2010 23:32:29 +0000 Subject: [PATCH] Implemented initial support for Ruby Blocks. --- Cycript.l.in | 2 +- Cycript.yy.in | 61 ++++++++++++++++++++++++++++++++++++++++++++------- Output.cpp | 13 ++++++++++- Parser.hpp | 43 ++++++++++++++++++++++++++++++++++++ Replace.cpp | 32 ++++++++++++++++++++++++++- 5 files changed, 140 insertions(+), 11 deletions(-) diff --git a/Cycript.l.in b/Cycript.l.in index bdd25ed..7358be7 100644 --- a/Cycript.l.in +++ b/Cycript.l.in @@ -250,7 +250,7 @@ XMLName {XMLNameStart}{XMLNamePart}* "(" L C return tk::OpenParen; ")" L C return tk::CloseParen; -"{" L C return tk::OpenBrace; +"{" L C return yylval->newline_ ? tk::OpenBrace_ : tk::OpenBrace; "}" L C return tk::CloseBrace; "[" L C return tk::OpenBracket; diff --git a/Cycript.yy.in b/Cycript.yy.in index 103deb7..53a6336 100644 --- a/Cycript.yy.in +++ b/Cycript.yy.in @@ -90,6 +90,7 @@ typedef struct { CYProgram *program_; CYProperty *property_; CYPropertyName *propertyName_; + CYRubyProc *rubyProc_; CYStatement *statement_; CYString *string_; CYThis *this_; @@ -223,6 +224,7 @@ int cylex(YYSTYPE *, cy::location *, void *); %token CloseParen ")" %token OpenBrace "{" +%token OpenBrace_ "\n{" %token CloseBrace "}" %token OpenBracket "[" @@ -444,6 +446,10 @@ int cylex(YYSTYPE *, cy::location *, void *); %type RelationalExpressionNoIn %type RelationalExpressionNoIn_ %type ReturnStatement +%type RubyProcExpression +%type RubyProcParameterList +%type RubyProcParameterList_ +%type RubyProcParametersOpt %type ShiftExpression %type ShiftExpressionNoBF %type SourceElement @@ -564,6 +570,11 @@ LexSetRegExp ; /* }}} */ +Brace + : "{" + | "\n{" + ; + StrictSemi : { driver.Warning(yylloc, "warning, automatic semi-colon insertion required"); } ; @@ -758,7 +769,7 @@ ElementList /* }}} */ /* 11.1.5 Object Initialiser {{{ */ ObjectLiteral - : "{" PropertyNameAndValueListOpt "}" { $$ = new(driver.pool_) CYObject($2); } + : OpenBrace PropertyNameAndValueListOpt "}" { $$ = new(driver.pool_) CYObject($2); } ; PropertyNameAndValueList_ @@ -1259,7 +1270,7 @@ Statement /* }}} */ /* 12.1 Block {{{ */ Block_ - : "{" StatementListOpt "}" { $$ = $2; } + : Brace StatementListOpt "}" { $$ = $2; } ; Block @@ -1411,7 +1422,7 @@ SwitchStatement ; CaseBlock - : "{" CaseClausesOpt "}" { $$ = $2; } + : Brace CaseClausesOpt "}" { $$ = $2; } ; CaseClausesOpt @@ -1456,11 +1467,11 @@ FinallyOpt /* 13 Function Definition {{{ */ FunctionDeclaration - : "function" Identifier "(" FormalParameterList ")" "{" FunctionBody "}" { $$ = new(driver.pool_) CYFunctionStatement($2, $4, $7); } + : "function" Identifier "(" FormalParameterList ")" Brace FunctionBody "}" { $$ = new(driver.pool_) CYFunctionStatement($2, $4, $7); } ; FunctionExpression - : "function" IdentifierOpt "(" FormalParameterList ")" "{" FunctionBody "}" { $$ = new(driver.pool_) CYFunctionExpression($2, $4, $7); } + : "function" IdentifierOpt "(" FormalParameterList ")" Brace FunctionBody "}" { $$ = new(driver.pool_) CYFunctionExpression($2, $4, $7); } ; FormalParameterList_ @@ -1506,7 +1517,7 @@ ClassSuperOpt ; ClassFieldList - : "{" "}" { $$ = NULL; } + : Brace "}" { $$ = NULL; } ; MessageScope @@ -1538,7 +1549,7 @@ MessageParameters ; ClassMessageDeclaration - : MessageScope TypeOpt MessageParameters "{" FunctionBody "}" { $$ = new(driver.pool_) CYMessage($1, $2, $3, $5); } + : MessageScope TypeOpt MessageParameters Brace FunctionBody "}" { $$ = new(driver.pool_) CYMessage($1, $2, $3, $5); } ; ClassMessageDeclarationListOpt @@ -1771,7 +1782,7 @@ XMLTagContent ; XMLExpression - : "{" LexPushRegExp Expression "}" LexPop + : Brace LexPushRegExp Expression "}" LexPop ; XMLTagName @@ -1893,5 +1904,39 @@ FormalParameterList : Identifier "=" AssignmentExpression FormalParameterList_ { $$ = new(driver.pool_) CYOptionalFunctionParameter($1, $3, $4); } ; /* }}} */ +/* JavaScript FTW: Ruby Blocks {{{ */ +RubyProcParameterList_ + : "," RubyProcParameterList { $$ = $2; } + | { $$ = NULL; } + ; + +RubyProcParameterList + : Identifier RubyProcParameterList_ { $$ = new(driver.pool_) CYFunctionParameter($1, $2); } + | { $$ = NULL; } + ; + +RubyProcParametersOpt + : "|" RubyProcParameterList "|" { $$ = $2; } + | { $$ = NULL; } + ; + +RubyProcExpression + : "{" RubyProcParametersOpt StatementListOpt "}" { $$ = new(driver.pool_) CYRubyProc($2, $3); } + ; + +LeftHandSideExpression + : LeftHandSideExpression RubyProcExpression { $$ = new(driver.pool_) CYRubyBlock($1, $2); } + ; + +LeftHandSideExpressionNoBF + : LeftHandSideExpressionNoBF RubyProcExpression { $$ = new(driver.pool_) CYRubyBlock($1, $2); } + ; + +@begin C +LeftHandSideExpressionNoRE + : LeftHandSideExpressionNoRE RubyProcExpression { $$ = new(driver.pool_) CYRubyBlock($1, $2); } + ; +@end +/* }}} */ %% diff --git a/Output.cpp b/Output.cpp index 989781a..c668658 100644 --- a/Output.cpp +++ b/Output.cpp @@ -561,7 +561,7 @@ void CYObject::Output(CYOutput &out, CYFlags flags) const { } void CYOptionalFunctionParameter::Output(CYOutput &out) const { - out << *name_ << ' ' << '=' << ' '; + out << *name_ << '='; initializer_->Output(out, CYPA, CYNoFlags); if (next_ != NULL) out << ',' << ' ' << *next_; @@ -607,6 +607,17 @@ void CYReturn::Output(CYOutput &out, CYFlags flags) const { out << ';'; } +void CYRubyBlock::Output(CYOutput &out, CYFlags flags) const { + call_->Output(out, CYLeft(flags)); + out << ' '; + proc_->Output(out, CYRight(flags)); +} + +void CYRubyProc::Output(CYOutput &out, CYFlags flags) const { + // XXX: this is not outputting the parameters + out << code_; +} + void CYStatement::Multiple(CYOutput &out, CYFlags flags) const { bool first(true); for (const CYStatement *next(this); next != NULL; next = next->next_) { diff --git a/Parser.hpp b/Parser.hpp index 1218fe9..49e0722 100644 --- a/Parser.hpp +++ b/Parser.hpp @@ -537,6 +537,8 @@ struct CYExpression : virtual const char *ForEachIn() const; virtual CYExpression *ForEachIn(CYContext &out); + virtual CYExpression *AddArgument(CYContext &context, CYExpression *value); + virtual void Output(CYOutput &out) const; virtual void Output(CYOutput &out, CYFlags flags) const = 0; void Output(CYOutput &out, unsigned precedence, CYFlags flags) const; @@ -1337,6 +1339,8 @@ struct CYNew : virtual CYExpression *Replace(CYContext &context); virtual void Output(CYOutput &out, CYFlags flags) const; + + virtual CYExpression *AddArgument(CYContext &context, CYExpression *value); }; struct CYCall : @@ -1356,6 +1360,29 @@ struct CYCall : virtual CYExpression *Replace(CYContext &context); virtual void Output(CYOutput &out, CYFlags flags) const; + + virtual CYExpression *AddArgument(CYContext &context, CYExpression *value); +}; + +struct CYRubyProc; + +struct CYRubyBlock : + CYExpression +{ + CYExpression *call_; + CYRubyProc *proc_; + + CYRubyBlock(CYExpression *call, CYRubyProc *proc) : + call_(call), + proc_(proc) + { + } + + CYPrecedence(1) + CYRightHand(false) + + virtual CYExpression *Replace(CYContext &context); + virtual void Output(CYOutput &out, CYFlags flags) const; }; struct CYIf : @@ -1408,6 +1435,7 @@ struct CYWhile : virtual void Output(CYOutput &out, CYFlags flags) const; }; +// XXX: this should be split up into CYAnonymousFunction and CYNamedFunction (subclass) struct CYFunction { CYIdentifier *name_; CYFunctionParameter *parameters_; @@ -1428,6 +1456,7 @@ struct CYFunction { virtual void Output(CYOutput &out, CYFlags flags) const; }; +// XXX: this should be split up into CYAnonymousFunctionExpression and CYNamedFunctionExpression struct CYFunctionExpression : CYFunction, CYExpression @@ -1444,6 +1473,20 @@ struct CYFunctionExpression : virtual void Output(CYOutput &out, CYFlags flags) const; }; +// XXX: this should derive from CYAnonymousFunctionExpression +struct CYRubyProc : + CYFunctionExpression +{ + CYRubyProc(CYFunctionParameter *parameters, CYStatement *statements) : + CYFunctionExpression(NULL, parameters, statements) + { + } + + virtual CYExpression *Replace(CYContext &context); + virtual void Output(CYOutput &out, CYFlags flags) const; +}; + +// XXX: this should derive from CYNamedFunction struct CYFunctionStatement : CYFunction, CYStatement diff --git a/Replace.cpp b/Replace.cpp index f0b0934..1285e8f 100644 --- a/Replace.cpp +++ b/Replace.cpp @@ -114,6 +114,14 @@ CYStatement *CYBreak::Replace(CYContext &context) { return this; } +CYExpression *CYCall::AddArgument(CYContext &context, CYExpression *value) { + CYArgument **argument(&arguments_); + while (*argument != NULL) + argument = &(*argument)->next_; + *argument = $ CYArgument(value); + return this; +} + CYExpression *CYCall::Replace(CYContext &context) { context.Replace(function_); arguments_->Replace(context); @@ -246,6 +254,10 @@ CYStatement *CYExpress::Replace(CYContext &context) { return this; } +CYExpression *CYExpression::AddArgument(CYContext &context, CYExpression *value) { + return $C1(this, value); +} + CYExpression *CYExpression::ClassName(CYContext &context, bool object) { return this; } @@ -345,7 +357,8 @@ void CYFunction::Replace_(CYContext &context, bool outer) { if (!outer && name_ != NULL) Inject(context); - parameters_ = parameters_->Replace(context, code_); + if (parameters_ != NULL) + parameters_ = parameters_->Replace(context, code_); code_.Replace(context); context.scope_ = scope.parent_; @@ -422,6 +435,14 @@ void CYMember::Replace_(CYContext &context) { context.Replace(property_); } +CYExpression *CYNew::AddArgument(CYContext &context, CYExpression *value) { + CYArgument **argument(&arguments_); + while (*argument != NULL) + argument = &(*argument)->next_; + *argument = $ CYArgument(value); + return this; +} + CYExpression *CYNew::Replace(CYContext &context) { context.Replace(constructor_); arguments_->Replace(context); @@ -555,6 +576,15 @@ CYStatement *CYReturn::Replace(CYContext &context) { return this; } +CYExpression *CYRubyBlock::Replace(CYContext &context) { + // XXX: this needs to do something much more epic to handle return + return call_->AddArgument(context, proc_->Replace(context)); +} + +CYExpression *CYRubyProc::Replace(CYContext &context) { + return $ CYFunctionExpression(NULL, parameters_, code_); +} + void CYScope::Declare(CYContext &context, CYIdentifier *identifier, CYIdentifierFlags flags) { internal_.insert(CYIdentifierAddressFlagsMap::value_type(identifier, flags)); } -- 2.47.2