]> git.saurik.com Git - cycript.git/commitdiff
Implemented initial support for Ruby Blocks.
authorJay Freeman (saurik) <saurik@saurik.com>
Thu, 1 Jul 2010 23:32:29 +0000 (23:32 +0000)
committerJay Freeman (saurik) <saurik@saurik.com>
Thu, 1 Jul 2010 23:32:29 +0000 (23:32 +0000)
Cycript.l.in
Cycript.yy.in
Output.cpp
Parser.hpp
Replace.cpp

index bdd25ed31d661177c039b1f2b215f06b96124d27..7358be7f5a839f36426cbab6199f9ecb1716d728 100644 (file)
@@ -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;
index 103deb70d961c4b15f563395e8ebe974f2763b63..53a6336467debbc178d5c580e589ca95439a7c14 100644 (file)
@@ -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 <expression_> RelationalExpressionNoIn
 %type <infix_> RelationalExpressionNoIn_
 %type <statement_> ReturnStatement
+%type <rubyProc_> RubyProcExpression
+%type <functionParameter_> RubyProcParameterList
+%type <functionParameter_> RubyProcParameterList_
+%type <functionParameter_> RubyProcParametersOpt
 %type <expression_> ShiftExpression
 %type <expression_> ShiftExpressionNoBF
 %type <statement_> 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
+/* }}} */
 
 %%
index 989781ab575380ceff675b6897656c399e9c01cb..c6686587eb87345dedb17cbca06b77f078a20863 100644 (file)
@@ -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_) {
index 1218fe91de27c960c5dcbff465c053c52cdb7e9c..49e072263f13824e6a576f6d8601b45bc204061c 100644 (file)
@@ -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
index f0b09344e300eda52d0f6d5fce834f771ce6799a..1285e8fb567a16b048954c72d0e028e0deb44bb8 100644 (file)
@@ -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));
 }