From 5a6c975adbe2588a10190cba75e9152682bedeae Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Tue, 29 Dec 2015 14:10:01 -0800 Subject: [PATCH] Fix Objective-C dictionary/array literal lowering. --- Execute.cpp | 44 +++++++++++++++++++++++++++------------- ObjectiveC/Output.cpp | 8 ++++++++ ObjectiveC/Replace.cpp | 21 +++++++++++++++++++ ObjectiveC/Syntax.hpp | 46 ++++++++++++++++++++++++++++++++++++++++++ Parser.ypp.in | 45 +++++++++++++++++++++++++++++++---------- Replace.cpp | 6 ++---- Syntax.hpp | 12 ++++++++--- 7 files changed, 150 insertions(+), 32 deletions(-) diff --git a/Execute.cpp b/Execute.cpp index 7eb6f65..ced61fc 100644 --- a/Execute.cpp +++ b/Execute.cpp @@ -749,30 +749,46 @@ void Bits::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data _assert(false); } -void Pointer::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const { - *reinterpret_cast(data) = CYCastPointer(context, value); -} - -void Array::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const { - uint8_t *base(reinterpret_cast(data)); - JSObjectRef aggregate(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL); - for (size_t index(0); index != size; ++index) { - ffi_type *field(ffi->elements[index]); - +static void CYArrayCopy(CYPool *pool, JSContextRef context, uint8_t *base, size_t length, const sig::Type &type, ffi_type *ffi, JSValueRef value, JSObjectRef object) { + for (size_t index(0); index != length; ++index) { JSValueRef rhs; - if (aggregate == NULL) + if (object == NULL) rhs = value; else { - rhs = CYGetProperty(context, aggregate, index); + rhs = CYGetProperty(context, object, index); if (JSValueIsUndefined(context, rhs)) throw CYJSError(context, "unable to extract array value"); } - type.PoolFFI(pool, context, field, base, rhs); - base += field->size; + type.PoolFFI(pool, context, ffi, base, rhs); + base += ffi->size; } } +void Pointer::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const { + bool guess(false); + *reinterpret_cast(data) = CYCastPointer(context, value, &guess); + if (!guess || pool == NULL || !JSValueIsObject(context, value)) + return; + JSObjectRef object(CYCastJSObject(context, value)); + if (CYHasProperty(context, object, length_s)) { + size_t length(CYArrayLength(context, object)); + ffi_type *element(type.GetFFI(*pool)); + size_t size(element->size * length); + uint8_t *base(pool->malloc(size, element->alignment)); + CYArrayCopy(pool, context, base, length, type, element, value, object); + *reinterpret_cast(data) = base; + } +} + +void Array::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const { + if (size == 0) + return; + uint8_t *base(reinterpret_cast(data)); + JSObjectRef object(JSValueIsObject(context, value) ? (JSObjectRef) value : NULL); + CYArrayCopy(pool, context, base, size, type, ffi->elements[0], value, object); +} + void Aggregate::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const { _assert(!overlap); diff --git a/ObjectiveC/Output.cpp b/ObjectiveC/Output.cpp index a65e386..37f86b1 100644 --- a/ObjectiveC/Output.cpp +++ b/ObjectiveC/Output.cpp @@ -77,6 +77,14 @@ void CYBox::Output(CYOutput &out, CYFlags flags) const { value_->Output(out, Precedence(), CYRight(flags)); } +void CYObjCArray::Output(CYOutput &out, CYFlags flags) const { + out << '@' << '[' << elements_ << ']'; +} + +void CYObjCDictionary::Output(CYOutput &out, CYFlags flags) const { + out << '@' << '{' << '}'; +} + void CYObjCBlock::Output(CYOutput &out, CYFlags flags) const { out << '^' << ' ' << *typed_ << ' ' << '('; diff --git a/ObjectiveC/Replace.cpp b/ObjectiveC/Replace.cpp index 6dd8e55..ab16675 100644 --- a/ObjectiveC/Replace.cpp +++ b/ObjectiveC/Replace.cpp @@ -132,6 +132,27 @@ CYTarget *CYBox::Replace(CYContext &context) { return $C1($M($V("Instance"), $S("box")), value_); } +CYTarget *CYObjCArray::Replace(CYContext &context) { + size_t count(0); + CYForEach (element, elements_) + ++count; + return $ CYSendDirect($V("NSArray"), $C_($ CYWord("arrayWithObjects"), $ CYArray(elements_), $C_($ CYWord("count"), $D(count)))); +} + +CYTarget *CYObjCDictionary::Replace(CYContext &context) { + CYList keys; + CYList values; + size_t count(0); + + CYForEach (pair, pairs_) { + keys->*$ CYElementValue(pair->key_); + values->*$ CYElementValue(pair->value_); + ++count; + } + + return $ CYSendDirect($V("NSDictionary"), $C_($ CYWord("dictionaryWithObjects"), $ CYArray(values), $C_($ CYWord("forKeys"), $ CYArray(keys), $C_($ CYWord("count"), $D(count))))); +} + CYTarget *CYObjCBlock::Replace(CYContext &context) { return $C1($ CYTypeExpression(($ CYTypedIdentifier(*typed_))->Modify($ CYTypeBlockWith(parameters_))), $ CYFunctionExpression(NULL, parameters_->Parameters(context), code_)); } diff --git a/ObjectiveC/Syntax.hpp b/ObjectiveC/Syntax.hpp index 16927ac..e4b0732 100644 --- a/ObjectiveC/Syntax.hpp +++ b/ObjectiveC/Syntax.hpp @@ -76,6 +76,52 @@ struct CYBox : virtual void Output(CYOutput &out, CYFlags flags) const; }; +struct CYObjCArray : + CYTarget +{ + CYElement *elements_; + + CYObjCArray(CYElement *elements = NULL) : + elements_(elements) + { + } + + CYPrecedence(0) + + virtual CYTarget *Replace(CYContext &context); + virtual void Output(CYOutput &out, CYFlags flags) const; +}; + +struct CYObjCKeyValue : + CYNext +{ + CYExpression *key_; + CYExpression *value_; + + CYObjCKeyValue(CYExpression *key, CYExpression *value, CYObjCKeyValue *next) : + CYNext(next), + key_(key), + value_(value) + { + } +}; + +struct CYObjCDictionary : + CYTarget +{ + CYObjCKeyValue *pairs_; + + CYObjCDictionary(CYObjCKeyValue *pairs) : + pairs_(pairs) + { + } + + CYPrecedence(0) + + virtual CYTarget *Replace(CYContext &context); + virtual void Output(CYOutput &out, CYFlags flags) const; +}; + struct CYSelectorPart : CYNext, CYThing diff --git a/Parser.ypp.in b/Parser.ypp.in index 2a1bf22..acda20a 100644 --- a/Parser.ypp.in +++ b/Parser.ypp.in @@ -90,6 +90,7 @@ @end @begin ObjectiveC +%union { CYObjCKeyValue *keyValue_; } %union { CYImplementationField *implementationField_; } %union { CYMessage *message_; } %union { CYMessageParameter *messageParameter_; } @@ -477,11 +478,11 @@ type; }) %type ArgumentListOpt %type Arguments %type ArrayComprehension +%type ArrayElement %type ArrayLiteral %type ArrowFunction %type ArrowParameters %type AssignmentExpression -%type AssignmentExpressionOpt %type BindingIdentifier %type BindingIdentifierOpt %type BindingList_ @@ -520,6 +521,7 @@ type; }) %type Declaration_ %type Declaration %type DefaultClause +%type ElementList_ %type ElementList %type ElementListOpt %type ElseStatementOpt @@ -693,6 +695,9 @@ type; }) %type ClassProtocolsOpt %type ImplementationFieldListOpt %type ImplementationStatement +%type KeyValuePairList_ +%type KeyValuePairList +%type KeyValuePairListOpt %type MessageExpression %type MessageParameter %type MessageParameters @@ -1050,10 +1055,19 @@ ArrayLiteral : "[" ElementListOpt[elements] "]" { $$ = CYNew CYArray($elements); } ; -ElementList - : AssignmentExpressionOpt[value] "," ElementListOpt[next] { $$ = CYNew CYElementValue($value, $next); } +ArrayElement + : AssignmentExpression[value] { $$ = CYNew CYElementValue($value); } | LexOf "..." AssignmentExpression[values] { $$ = CYNew CYElementSpread($values); } - | AssignmentExpression[value] { $$ = CYNew CYElementValue($value, NULL); } + ; + +ElementList_ + : "," ElementListOpt[elements] { $$ = $elements; } + | { $$ = NULL; } + ; + +ElementList + : ArrayElement[element] ElementList_[next] { $$ = $element; $$->SetNext($next); } + | LexOf "," ElementListOpt[next] { $$ = CYNew CYElementValue(NULL, $next); } ; ElementListOpt @@ -1342,11 +1356,6 @@ AssignmentExpression | ArrowFunction[pass] { $$ = $pass; } | LexOf LeftHandSideAssignment[assignment] AssignmentExpression[rhs] { $assignment->SetRight($rhs); $$ = $assignment; } ; - -AssignmentExpressionOpt - : AssignmentExpression[pass] { $$ = $pass; } - | LexOf { $$ = NULL; } - ; /* }}} */ /* 12.15 Comma Operator ( , ) {{{ */ Expression @@ -2272,15 +2281,29 @@ BoxableExpression | BooleanLiteral[pass] { $$ = $pass; } | NumericLiteral[pass] { $$ = $pass; } | StringLiteral[pass] { $$ = $pass; } - | ArrayLiteral[pass] { $$ = $pass; } - | ObjectLiteral[pass] { $$ = $pass; } | CoverParenthesizedExpressionAndArrowParameterList[pass] { $$ = $pass; } | "YES" { $$ = CYNew CYTrue(); } | "NO" { $$ = CYNew CYFalse(); } ; +KeyValuePairList_ + : "," KeyValuePairListOpt[next] { $$ = $next; } + | { $$ = NULL; } + +KeyValuePairList + : AssignmentExpression[key] ":" AssignmentExpression[value] KeyValuePairList_[next] { $$ = CYNew CYObjCKeyValue($key, $value, $next); } + ; + +KeyValuePairListOpt + : KeyValuePairList[pass] { $$ = $pass; } + | LexOf { $$ = NULL; } + ; + PrimaryExpression : "@" BoxableExpression[expression] { $$ = CYNew CYBox($expression); } + | "@" "[" ElementListOpt[elements] "]" { $$ = CYNew CYObjCArray($elements); } + | "@" "{" KeyValuePairListOpt[pairs] "}" { $$ = CYNew CYObjCDictionary($pairs); } + | "@YES" { $$ = CYNew CYBox(CYNew CYTrue()); } | "@NO" { $$ = CYNew CYBox(CYNew CYFalse()); } | "@true" { $$ = CYNew CYBox(CYNew CYTrue()); } diff --git a/Replace.cpp b/Replace.cpp index 1513c8d..ca05d08 100644 --- a/Replace.cpp +++ b/Replace.cpp @@ -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; } @@ -347,8 +347,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) { diff --git a/Syntax.hpp b/Syntax.hpp index 5599f7e..9786ee7 100644 --- a/Syntax.hpp +++ b/Syntax.hpp @@ -1089,21 +1089,26 @@ struct CYClause : }; struct CYElement : + CYNext, CYThing { + CYElement(CYElement *next) : + CYNext(next) + { + } + virtual bool Elision() const = 0; virtual void Replace(CYContext &context) = 0; }; struct CYElementValue : - CYNext, CYElement { CYExpression *value_; CYElementValue(CYExpression *value, CYElement *next = NULL) : - CYNext(next), + CYElement(next), value_(value) { } @@ -1121,7 +1126,8 @@ struct CYElementSpread : { CYExpression *value_; - CYElementSpread(CYExpression *value) : + CYElementSpread(CYExpression *value, CYElement *next = NULL) : + CYElement(next), value_(value) { } -- 2.47.2