]> git.saurik.com Git - cycript.git/blobdiff - Replace.cpp
CYInjectRemote should also be in #ifdef CY_ATTACH.
[cycript.git] / Replace.cpp
index d2704cb6b4350209ea611abda6063afad5f978e0..d499dbcc92867a39826e83af39bbda3a8308a2b3 100644 (file)
@@ -1,5 +1,5 @@
-/* Cycript - Optimizing JavaScript Compiler/Runtime
- * Copyright (C) 2009-2015  Jay Freeman (saurik)
+/* Cycript - The Truly Universal Scripting Language
+ * Copyright (C) 2009-2016  Jay Freeman (saurik)
 */
 
 /* GNU Affero General Public License, Version 3 {{{ */
@@ -101,8 +101,8 @@ CYArgument *CYArgument::Replace(CYContext &context) { $T(NULL)
 }
 
 CYTarget *CYArray::Replace(CYContext &context) {
-    if (elements_ != NULL)
-        elements_->Replace(context);
+    CYForEach (element, elements_)
+        element->Replace(context);
     return this;
 }
 
@@ -117,11 +117,22 @@ CYTarget *CYArrayComprehension::Replace(CYContext &context) {
 }
 
 CYExpression *CYAssignment::Replace(CYContext &context) {
+    // XXX: this is a horrible hack but I'm a month over schedule :(
+    if (CYSubscriptMember *subscript = dynamic_cast<CYSubscriptMember *>(lhs_))
+        return $C2($M(subscript->object_, $S("$cys")), subscript->property_, rhs_);
     context.Replace(lhs_);
     context.Replace(rhs_);
     return this;
 }
 
+CYTarget *CYAttemptMember::Replace(CYContext &context) {
+    CYIdentifier *value(context.Unique());
+
+    return $C1($F(NULL, $P1($B(value)), $$
+        ->* $ CYReturn($ CYCondition($V(value), $M($V(value), property_), $V(value)))
+    ), object_);
+}
+
 CYStatement *CYBlock::Return() {
     CYImplicitReturn(code_);
     return this;
@@ -142,6 +153,15 @@ CYStatement *CYBreak::Replace(CYContext &context) {
 }
 
 CYTarget *CYCall::Replace(CYContext &context) {
+    // XXX: this also is a horrible hack but I'm still a month over schedule :(
+    if (CYAttemptMember *member = dynamic_cast<CYAttemptMember *>(function_)) {
+        CYIdentifier *value(context.Unique());
+
+        return $C1($F(NULL, $P1($B(value)), $$
+            ->* $ CYReturn($ CYCondition($V(value), $C($M($V(value), member->property_), arguments_), $V(value)))
+        ), member->object_);
+    }
+
     context.Replace(function_);
     arguments_->Replace(context);
     return this;
@@ -179,6 +199,7 @@ CYTarget *CYClassExpression::Replace(CYContext &context) {
 
     if (tail_->constructor_ == NULL)
         tail_->constructor_ = $ CYFunctionExpression(NULL, NULL, NULL);
+    tail_->constructor_->name_ = name_;
     tail_->constructor_ = CYSuperize(context, tail_->constructor_);
 
     context.super_ = old;
@@ -347,8 +368,6 @@ void CYElementSpread::Replace(CYContext &context) {
 
 void CYElementValue::Replace(CYContext &context) {
     context.Replace(value_);
-    if (next_ != NULL)
-        next_->Replace(context);
 }
 
 CYForInitializer *CYEmpty::Replace(CYContext &context) {
@@ -383,8 +402,19 @@ CYFunctionParameter *CYExpression::Parameter() const {
     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())))));
+CYTarget *CYExtend::Replace(CYContext &context) {
+    return object_.Replace(context, lhs_);
+}
+
+CYStatement *CYExternalDefinition::Replace(CYContext &context) {
+    return $E($ CYAssign($V(name_), $ CYExternalExpression(abi_, type_, name_)));
+}
+
+CYTarget *CYExternalExpression::Replace(CYContext &context) {
+    CYExpression *expression(name_->Number(context));
+    if (expression == NULL)
+        expression = $C2($V("dlsym"), $V("RTLD_DEFAULT"), name_->PropertyName(context));
+    return $C1(type_->Replace(context), expression);
 }
 
 CYNumber *CYFalse::Number(CYContext &context) {
@@ -623,6 +653,27 @@ CYStatement *CYImport::Replace(CYContext &context) {
     return $ CYVar($B1($B($I(module_->part_->Word()), $C1($V("require"), module_->Replace(context, "/")))));
 }
 
+CYStatement *CYImportDeclaration::Replace(CYContext &context) {
+    CYIdentifier *module(context.Unique());
+
+    CYList<CYStatement> statements;
+    CYForEach (specifier, specifiers_)
+        statements->*specifier->Replace(context, module);
+
+    return $ CYBlock($$
+        ->* $ CYLexical(false, $B1($B(module, $C1($V("require"), module_))))
+        ->* statements);
+}
+
+CYStatement *CYImportSpecifier::Replace(CYContext &context, CYIdentifier *module) {
+    binding_ = binding_->Replace(context, CYIdentifierLexical);
+
+    CYExpression *import($V(module));
+    if (name_ != NULL)
+        import = $M(import, $S(name_));
+    return $E($ CYAssign($V(binding_), import));
+}
+
 CYTarget *CYIndirect::Replace(CYContext &context) {
     return $M(rhs_, $S("$cyi"));
 }
@@ -713,21 +764,25 @@ CYExpression *CYNumber::PropertyName(CYContext &context) {
     return String(context);
 }
 
-CYTarget *CYObject::Replace(CYContext &context) {
+CYTarget *CYObject::Replace(CYContext &context, CYTarget *seed) {
     CYBuilder builder;
     if (properties_ != NULL)
-        properties_ = properties_->ReplaceAll(context, builder, $ CYThis(), false);
+        properties_ = properties_->ReplaceAll(context, builder, $ CYThis(), seed != this);
 
     if (builder) {
         return $C1($M($ CYFunctionExpression(NULL, builder.bindings_->Parameter(context),
             builder.statements_
                 ->* $ CYReturn($ CYThis())
-        ), $S("call")), this, builder.bindings_->Argument(context));
+        ), $S("call")), seed, builder.bindings_->Argument(context));
     }
 
     CYForEach (property, properties_)
         property->Replace(context);
-    return this;
+    return seed;
+}
+
+CYTarget *CYObject::Replace(CYContext &context) {
+    return Replace(context, this);
 }
 
 CYTarget *CYParenthetical::Replace(CYContext &context) {
@@ -859,6 +914,10 @@ void CYScript::Replace(CYContext &context) {
     }
 }
 
+CYTarget *CYResolveMember::Replace(CYContext &context) {
+    return $M($M(object_, $S("$cyr")), property_);
+}
+
 CYStatement *CYReturn::Replace(CYContext &context) {
     if (context.nonlocal_ != NULL) {
         CYProperty *value(value_ == NULL ? NULL : $ CYPropertyValue($S("$cyv"), value_));
@@ -872,7 +931,7 @@ CYStatement *CYReturn::Replace(CYContext &context) {
 }
 
 CYTarget *CYRubyBlock::Replace(CYContext &context) {
-    return call_->AddArgument(context, proc_->Replace(context));
+    return lhs_->AddArgument(context, proc_->Replace(context));
 }
 
 CYTarget *CYRubyBlock::AddArgument(CYContext &context, CYExpression *value) {
@@ -928,7 +987,10 @@ CYIdentifierFlags *CYScope::Declare(CYContext &context, CYIdentifier *identifier
     else if (existing->kind_ == CYIdentifierGlobal || existing->kind_ == CYIdentifierMagic)
         existing->kind_ = kind;
     else if (existing->kind_ == CYIdentifierLexical || kind == CYIdentifierLexical)
-        _assert(false); // XXX: throw new SyntaxError()
+        _assert(false);
+    else if (transparent_ && existing->kind_ == CYIdentifierArgument && kind == CYIdentifierVariable)
+        _assert(false);
+    // XXX: throw new SyntaxError() instead of these asserts
 
     return existing;
 }
@@ -966,10 +1028,6 @@ void CYScope::Close(CYContext &context) {
     CYForEach (i, internal_) {
         _assert(i->identifier_->next_ == i->identifier_);
     switch (i->kind_) {
-        case CYIdentifierArgument: {
-            _assert(!transparent_);
-        } break;
-
         case CYIdentifierLexical: {
             if (!damaged_) {
                 CYIdentifier *replace(context.Unique());
@@ -1039,6 +1097,10 @@ void CYScope::Close(CYContext &context) {
     default:; } }
 }
 
+CYTarget *CYSubscriptMember::Replace(CYContext &context) {
+    return $C1($M(object_, $S("$cyg")), property_);
+}
+
 CYElementValue *CYSpan::Replace(CYContext &context) { $T(NULL)
     return $ CYElementValue(expression_, $ CYElementValue(string_, next_->Replace(context)));
 }
@@ -1056,6 +1118,12 @@ CYString *CYString::Concat(CYContext &context, CYString *rhs) const {
     return $S(value, size);
 }
 
+CYIdentifier *CYString::Identifier() const {
+    if (const char *word = Word())
+        return $ CYIdentifier(word);
+    return NULL;
+}
+
 CYNumber *CYString::Number(CYContext &context) {
     // XXX: there is a precise algorithm for this
     return NULL;
@@ -1069,6 +1137,31 @@ CYString *CYString::String(CYContext &context) {
     return this;
 }
 
+CYStatement *CYStructDefinition::Replace(CYContext &context) {
+    CYTarget *target(tail_->Replace(context));
+    if (name_ != NULL)
+        target = $C1($M(target, $S("withName")), $S(name_->Word()));
+    return $ CYLexical(false, $B1($B($I($pool.strcat(name_->Word(), "$cy", NULL)), target)));
+}
+
+CYTarget *CYStructTail::Replace(CYContext &context) {
+    CYList<CYElementValue> types;
+    CYList<CYElementValue> names;
+
+    CYForEach (field, fields_) {
+        types->*$ CYElementValue(field->type_->Replace(context));
+
+        CYExpression *name;
+        if (field->name_ == NULL)
+            name = NULL;
+        else
+            name = field->name_->PropertyName(context);
+        names->*$ CYElementValue(name);
+    }
+
+    return $N2($V("Type"), $ CYArray(types), $ CYArray(names));
+}
+
 CYTarget *CYSuperAccess::Replace(CYContext &context) {
     return $C1($M($M($M($V(context.super_), $S("prototype")), property_), $S("bind")), $ CYThis());
 }
@@ -1077,6 +1170,10 @@ CYTarget *CYSuperCall::Replace(CYContext &context) {
     return $C($C1($M($V(context.super_), $S("bind")), $ CYThis()), arguments_);
 }
 
+CYTarget *CYSymbol::Replace(CYContext &context) {
+    return $C1($M($V("Symbol"), $S("for")), $S(name_));
+}
+
 CYStatement *CYSwitch::Replace(CYContext &context) {
     context.Replace(value_);
     clauses_->Replace(context);
@@ -1093,6 +1190,13 @@ CYTarget *CYTemplate::Replace(CYContext &context) {
     return $C2($M($M($M($V("String"), $S("prototype")), $S("concat")), $S("apply")), $S(""), $ CYArray($ CYElementValue(string_, spans_->Replace(context))));
 }
 
+CYString *CYTemplate::String(CYContext &context) {
+    // XXX: implement this over local concat
+    if (spans_ != NULL)
+        return NULL;
+    return string_;
+}
+
 CYTarget *CYThis::Replace(CYContext &context) {
     if (context.this_ != NULL)
         return $V(context.this_->Identifier(context));
@@ -1144,12 +1248,33 @@ CYTarget *CYTypeBlockWith::Replace_(CYContext &context, CYTarget *type) {
     return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("blockWith")), parameters_->Argument(context)));
 }
 
+CYTarget *CYTypeCharacter::Replace(CYContext &context) {
+    switch (signing_) {
+        case CYTypeNeutral: return $V("char");
+        case CYTypeSigned: return $V("schar");
+        case CYTypeUnsigned: return $V("uchar");
+        default: _assert(false);
+    }
+}
+
 CYTarget *CYTypeConstant::Replace_(CYContext &context, CYTarget *type) {
     return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("constant"))));
 }
 
 CYStatement *CYTypeDefinition::Replace(CYContext &context) {
-    return $E($ CYAssign($V(typed_->identifier_), typed_->Replace(context)));
+    return $ CYLexical(false, $B1($B(name_, $ CYTypeExpression(type_))));
+}
+
+CYTarget *CYTypeEnum::Replace(CYContext &context) {
+    CYList<CYProperty> properties;
+    CYForEach (constant, constants_)
+        properties->*$ CYPropertyValue($S(constant->name_->Word()), constant->value_);
+    CYObject *constants($ CYObject(properties));
+
+    if (specifier_ == NULL)
+        return $N1($V("Type"), constants);
+    else
+        return $C1($M(specifier_->Replace(context), $S("enumFor")), constants);
 }
 
 CYTarget *CYTypeError::Replace(CYContext &context) {
@@ -1157,32 +1282,65 @@ CYTarget *CYTypeError::Replace(CYContext &context) {
     return NULL;
 }
 
+CYTarget *CYTypeExpression::Replace(CYContext &context) {
+    return typed_->Replace(context);
+}
+
+CYTarget *CYTypeFloating::Replace(CYContext &context) {
+    switch (length_) {
+        case 0: return $V("float");
+        case 1: return $V("double");
+        case 2: return $V("longdouble");
+        default: _assert(false);
+    }
+}
+
+CYTarget *CYTypeInt128::Replace(CYContext &context) {
+    return $V(signing_ == CYTypeUnsigned ? "uint128" : "int128");
+}
+
+CYTarget *CYTypeIntegral::Replace(CYContext &context) {
+    bool u(signing_ == CYTypeUnsigned);
+    switch (length_) {
+        case 0: return $V(u ? "ushort" : "short");
+        case 1: return $V(u ? "uint" : "int");
+        case 2: return $V(u ? "ulong" : "long");
+        case 3: return $V(u ? "ulonglong" : "longlong");
+        default: _assert(false);
+    }
+}
+
 CYTarget *CYTypeModifier::Replace(CYContext &context, CYTarget *type) { $T(type)
     return Replace_(context, type);
 }
 
 CYTarget *CYTypeFunctionWith::Replace_(CYContext &context, CYTarget *type) {
-    return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("functionWith")), parameters_->Argument(context)));
-}
-
-CYTarget *CYTypeLong::Replace(CYContext &context) {
-    return $ CYCall($ CYDirectMember(specifier_->Replace(context), $ CYString("long")));
+    CYList<CYArgument> arguments(parameters_->Argument(context));
+    if (variadic_)
+        arguments->*$C_($ CYNull());
+    return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("functionWith")), arguments));
 }
 
 CYTarget *CYTypePointerTo::Replace_(CYContext &context, CYTarget *type) {
     return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("pointerTo"))));
 }
 
-CYTarget *CYTypeShort::Replace(CYContext &context) {
-    return $ CYCall($ CYDirectMember(specifier_->Replace(context), $ CYString("short")));
-}
+CYTarget *CYTypeReference::Replace(CYContext &context) {
+    const char *prefix;
+    switch (kind_) {
+        case CYTypeReferenceStruct: prefix = "$cys"; break;
+        case CYTypeReferenceEnum: prefix = "$cye"; break;
+        default: _assert(false);
+    }
 
-CYTarget *CYTypeSigned::Replace(CYContext &context) {
-    return $ CYCall($ CYDirectMember(specifier_->Replace(context), $ CYString("signed")));
+    return $V($pool.strcat(prefix, name_->Word(), NULL));
 }
 
-CYTarget *CYTypeUnsigned::Replace(CYContext &context) {
-    return $ CYCall($ CYDirectMember(specifier_->Replace(context), $ CYString("unsigned")));
+CYTarget *CYTypeStruct::Replace(CYContext &context) {
+    CYTarget *target(tail_->Replace(context));
+    if (name_ != NULL)
+        target = $C1($M(target, $S("withName")), $S(name_->Word()));
+    return target;
 }
 
 CYTarget *CYTypeVariable::Replace(CYContext &context) {
@@ -1197,33 +1355,33 @@ CYTarget *CYTypeVolatile::Replace_(CYContext &context, CYTarget *type) {
     return next_->Replace(context, $ CYCall($ CYDirectMember(type, $ CYString("volatile"))));
 }
 
-CYTarget *CYTypedIdentifier::Replace(CYContext &context) {
+CYTarget *CYType::Replace(CYContext &context) {
     return modifier_->Replace(context, specifier_->Replace(context));
 }
 
-CYTypeFunctionWith *CYTypedIdentifier::Function() {
-    CYTypeModifier **modifier(&modifier_);
-    if (*modifier == NULL)
+CYTypeFunctionWith *CYType::Function() {
+    CYTypeModifier *&modifier(CYGetLast(modifier_));
+    if (modifier == NULL)
         return NULL;
-    while ((*modifier)->next_ != NULL)
-        modifier = &(*modifier)->next_;
-    CYTypeFunctionWith *function((*modifier)->Function());
+
+    CYTypeFunctionWith *function(modifier->Function());
     if (function == NULL)
         return NULL;
-    *modifier = NULL;
+
+    modifier = NULL;
     return function;
 }
 
 CYArgument *CYTypedParameter::Argument(CYContext &context) { $T(NULL)
-    return $ CYArgument(typed_->Replace(context), next_->Argument(context));
+    return $ CYArgument(type_->Replace(context), next_->Argument(context));
 }
 
 CYFunctionParameter *CYTypedParameter::Parameters(CYContext &context) { $T(NULL)
-    return $ CYFunctionParameter($ CYBinding(typed_->identifier_ ?: context.Unique()), next_->Parameters(context));
+    return $ CYFunctionParameter($ CYBinding(name_ ?: context.Unique()), next_->Parameters(context));
 }
 
 CYExpression *CYTypedParameter::TypeSignature(CYContext &context, CYExpression *prefix) { $T(prefix)
-    return next_->TypeSignature(context, $ CYAdd(prefix, typed_->Replace(context)));
+    return next_->TypeSignature(context, $ CYAdd(prefix, type_->Replace(context)));
 }
 
 CYForInitializer *CYVar::Replace(CYContext &context) {