From c5587ed74e6cf565bf30da661579e80d78f96e80 Mon Sep 17 00:00:00 2001
From: "Jay Freeman (saurik)" <saurik@saurik.com>
Date: Fri, 31 Oct 2014 02:50:48 -0700
Subject: [PATCH] Support extern "C" syntax to FFI via C prototypes.

---
 Cycript.l.in  |  1 +
 Cycript.yy.in | 11 ++++++++++-
 Output.cpp    |  4 ++++
 Parser.hpp    | 16 ++++++++++++++++
 Replace.cpp   |  4 ++++
 5 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/Cycript.l.in b/Cycript.l.in
index 7ee7d60..ab5d0b3 100644
--- a/Cycript.l.in
+++ b/Cycript.l.in
@@ -272,6 +272,7 @@ XMLName {XMLNameStart}{XMLNamePart}*
 "typedef"         L C I(identifier, Identifier("typedef"), tk::Typedef, hi::Meta);
 "unsigned"        L C I(identifier, Identifier("unsigned"), tk::Unsigned, hi::Type);
 "signed"          L C I(identifier, Identifier("signed"), tk::Signed, hi::Type);
+"extern"          L C I(identifier, Identifier("extern"), tk::Extern, hi::Type);
 @end
 
 @begin C
diff --git a/Cycript.yy.in b/Cycript.yy.in
index 3ad89f8..b2f5629 100644
--- a/Cycript.yy.in
+++ b/Cycript.yy.in
@@ -245,6 +245,7 @@ int cylex(YYSTYPE *, cy::location *, void *);
 %token <identifier_> Typedef "typedef"
 %token <identifier_> Unsigned "unsigned"
 %token <identifier_> Signed "signed"
+%token <identifier_> Extern "extern"
 @end
 
 @begin C
@@ -718,6 +719,7 @@ Identifier
     | "typedef" { $$ = $1; }
     | "unsigned" { $$ = $1; }
     | "signed" { $$ = $1; }
+    | "extern" { $$ = $1; }
 @end
 @begin ObjectiveC
     | "YES" { $$ = $1; }
@@ -1434,6 +1436,7 @@ SuffixedType
     : ArrayedType { $$ = $1; }
     | "(" LexPushInOff "^" TypeQualifierRight ")" LexPopIn "(" LexPushInOff TypedParameterListOpt ")" LexPopIn { $$ = $4; $$->modifier_ = CYNew CYTypeBlockWith($9, $$->modifier_); }
     | TypeParenthetical FunctionedType { $$ = $1; CYSetLast($2) = $$->modifier_; $$->modifier_ = $2; }
+    | IdentifierType FunctionedType { $$ = CYNew CYTypedIdentifier($1); CYSetLast($2) = $$->modifier_; $$->modifier_ = $2; }
     | FunctionedType { $$ = CYNew CYTypedIdentifier(); CYSetLast($1) = $$->modifier_; $$->modifier_ = $1; }
     ;
 
@@ -1730,9 +1733,15 @@ PrimaryExpression
 /* }}} */
 /* Cycript (C): Type Definitions {{{ */
 Statement__
-    : "typedef" TypedIdentifier Terminator { $$ = CYNew CYTypeDefinition($2); }
+    : "typedef" TypedIdentifier { if ($2->identifier_ == NULL) YYABORT; } Terminator { $$ = CYNew CYTypeDefinition($2); }
     ;
 /* }}} */
+/* Cycript (C): extern "C" {{{ */
+Statement__
+    : "extern" StringLiteral { if (strcmp($2->Value(), "C") != 0) YYABORT; } TypedIdentifier Terminator { $$ = CYNew CYExternal($2, $4); }
+    ;
+/* }}} */
+
 @end
 
 /* YUI: Documentation Comments {{{ */
diff --git a/Output.cpp b/Output.cpp
index 4c4376a..467825c 100644
--- a/Output.cpp
+++ b/Output.cpp
@@ -329,6 +329,10 @@ void CYExpression::Output(CYOutput &out, int precedence, CYFlags flags) const {
         Output(out, flags);
 }
 
+void CYExternal::Output(CYOutput &out, CYFlags flags) const {
+    out << "extern" << abi_ << typed_ << ';';
+}
+
 void CYFatArrow::Output(CYOutput &out, CYFlags flags) const {
     out << '(' << parameters_ << ')' << ' ' << "=>" << ' ' << code_;
 }
diff --git a/Parser.hpp b/Parser.hpp
index 697fbea..63270a1 100644
--- a/Parser.hpp
+++ b/Parser.hpp
@@ -1881,6 +1881,22 @@ struct CYImport :
     virtual void Output(CYOutput &out, CYFlags flags) const;
 };
 
+struct CYExternal :
+    CYStatement
+{
+    CYString *abi_;
+    CYTypedIdentifier *typed_;
+
+    CYExternal(CYString *abi, CYTypedIdentifier *typed) :
+        abi_(abi),
+        typed_(typed)
+    {
+    }
+
+    virtual CYStatement *Replace(CYContext &context);
+    virtual void Output(CYOutput &out, CYFlags flags) const;
+};
+
 struct CYTypeDefinition :
     CYStatement
 {
diff --git a/Replace.cpp b/Replace.cpp
index b3d1c82..f6d904c 100644
--- a/Replace.cpp
+++ b/Replace.cpp
@@ -327,6 +327,10 @@ CYAssignment *CYExpression::Assignment(CYContext &context) {
     return NULL;
 }
 
+CYStatement *CYExternal::Replace(CYContext &context) {
+    return $E($ CYAssign($V(typed_->identifier_), $C1(typed_->Replace(context), $C2($V("dlsym"), $V("RTLD_DEFAULT"), $S(typed_->identifier_->Word())))));
+}
+
 CYNumber *CYFalse::Number(CYContext &context) {
     return $D(0);
 }
-- 
2.47.2