#include <CoreLocation/CoreLocation.h>
#include <Security/Security.h>
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <mach/vm_map.h>
+
+#include <mach-o/dyld.h>
+#include <mach-o/dyld_images.h>
+
#if TARGET_OS_IPHONE
#include <UIKit/UIKit.h>
+extern "C" UIApplication *UIApp;
#else
#include <AppKit/AppKit.h>
#endif
return typed;
}
+static void CYParseEnumeration(CXCursor cursor, CYTypedIdentifier *typed) {
+ CYList<CYEnumConstant> constants;
+
+ CYForChild(cursor, fun([&](CXCursor child) {
+ if (clang_getCursorKind(child) == CXCursor_EnumConstantDecl)
+ constants->*$ CYEnumConstant($I($pool.strdup(CYCXString(child))), $D(clang_getEnumConstantDeclValue(child)));
+ }));
+
+ CYTypedIdentifier *integer(CYDecodeType(clang_getEnumDeclIntegerType(cursor)));
+ typed->specifier_ = $ CYTypeEnum(NULL, integer->specifier_, constants);
+}
+
static void CYParseStructure(CXCursor cursor, CYTypedIdentifier *typed) {
CYList<CYTypeStructField> fields;
CYForChild(cursor, fun([&](CXCursor child) {
switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
case CXCursor_EnumDecl:
if (spelling[0] != '\0')
- // XXX: should we have a special enum keyword?
- typed->specifier_ = $ CYTypeVariable($I(spelling.Pool($pool)));
+ typed->specifier_ = $ CYTypeReference(CYTypeReferenceEnum, $I(spelling.Pool($pool)));
else
- // XXX: maybe replace with "enum : int" instead of "int"
- CYParseType(clang_getEnumDeclIntegerType(cursor), typed);
+ CYParseEnumeration(cursor, typed);
break;
case CXCursor_StructDecl: {
if (spelling[0] != '\0')
- typed->specifier_ = $ CYTypeReference($I(spelling.Pool($pool)));
+ typed->specifier_ = $ CYTypeReference(CYTypeReferenceStruct, $I(spelling.Pool($pool)));
else
CYParseStructure(cursor, typed);
} break;
break;
case CXType_IncompleteArray:
- // XXX: I should support these :/
- _assert(false);
+ // XXX: I probably should not decay to Pointer
+ CYParseType(clang_getArrayElementType(type), typed);
+ typed = typed->Modify($ CYTypePointerTo());
break;
case CXType_ObjCClass:
break;
case CXType_Record:
- typed->specifier_ = $ CYTypeReference($I($pool.strdup(CYCXString(clang_getTypeSpelling(type)))));
+ typed->specifier_ = $ CYTypeReference(CYTypeReferenceStruct, $I($pool.strdup(CYCXString(clang_getTypeSpelling(type)))));
break;
case CXType_Typedef:
CYChildBaton &baton(*static_cast<CYChildBaton *>(arg));
CXTranslationUnit &unit(baton.unit);
+ CXChildVisitResult result(CXChildVisit_Continue);
CYCXString spelling(cursor);
std::string name(spelling);
std::ostringstream value;
value << clang_getEnumConstantDeclValue(cursor);
} break;
+ case CXCursor_EnumDecl: {
+ if (spelling[0] == '\0')
+ goto skip;
+ // XXX: this was blindly copied from StructDecl
+ if (!clang_isCursorDefinition(cursor))
+ priority = 1;
+
+ CYLocalPool pool;
+
+ CYTypedIdentifier typed(NULL);
+ CYParseEnumeration(cursor, &typed);
+
+ CYOptions options;
+ CYOutput out(*value.rdbuf(), options);
+ CYTypeExpression(&typed).Output(out, CYNoBFC);
+
+ value << ".withName(\"" << name << "\")";
+ name += "$cye";
+ flags = CYBridgeType;
+
+ // the enum constants are implemented separately *also*
+ // XXX: maybe move output logic to function we can call
+ result = CXChildVisit_Recurse;
+ } break;
+
case CXCursor_MacroDefinition: {
CXSourceRange range(clang_getCursorExtent(cursor));
CYTokens tokens(unit, range);
CYTypeExpression(&typed).Output(out, CYNoBFC);
value << ".withName(\"" << name << "\")";
- name += "$cy";
+ name += "$cys";
flags = CYBridgeType;
} break;
}
} break;
- default: {
- return CXChildVisit_Recurse;
- } break;
+ default:
+ result = CXChildVisit_Recurse;
+ goto skip;
+ break;
} {
CYKey &key(baton.keys[name]);
if (key.priority_ <= priority) {
}
skip:
- return CXChildVisit_Continue;
+ return result;
}
int main(int argc, const char *argv[]) {
}
#endif
+CYTypedIdentifier *Enum::Decode(CYPool &pool) const {
+ CYEnumConstant *values(NULL);
+ for (size_t i(count); i != 0; --i)
+ values = $ CYEnumConstant($I(pool.strdup(constants[i - 1].name)), $D(constants[i - 1].value), values);
+ CYIdentifier *identifier(name == NULL ? NULL : $I(name));
+ CYTypedIdentifier *typed(type.Decode(pool));
+ _assert(typed->modifier_ == NULL);
+ return $ CYTypedIdentifier($ CYTypeEnum(identifier, typed->specifier_, values));
+}
+
CYTypedIdentifier *Aggregate::Decode(CYPool &pool) const {
_assert(!overlap);
CYArrayCopy(pool, context, base, size, type, ffi->elements[0], value, object);
}
+void Enum::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
+ return type.PoolFFI(pool, context, ffi, data, value);
+}
+
void Aggregate::PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const {
_assert(!overlap);
return CArray::Make(context, data, size, type, ffi->elements[0], context, owner);
}
+JSValueRef Enum::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
+ return type.FromFFI(context, ffi, data, initialize, owner);
+}
+
JSValueRef Aggregate::FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const {
return Struct_privateData::Make(context, data, *this, ffi, context, owner);
}
if (false) {
} else if (count == 1) {
- const char *encoding(CYPoolCString(pool, context, arguments[0]));
- sig::Signature signature;
- sig::Parse(pool, &signature, encoding, &Structor_);
- return CYMakeType(context, *signature.elements[0].type);
+ switch (JSValueGetType(context, arguments[0])) {
+ case kJSTypeString: {
+ const char *encoding(CYPoolCString(pool, context, arguments[0]));
+ sig::Signature signature;
+ sig::Parse(pool, &signature, encoding, &Structor_);
+ return CYMakeType(context, *signature.elements[0].type);
+ } break;
+
+ case kJSTypeObject: {
+ // XXX: accept a set of enum constants and /guess/ at their size
+ _assert(false);
+ } break;
+
+ default:
+ throw CYJSError(context, "incorrect kind of argument to new Type");
+ }
} else if (count == 2) {
JSObjectRef types(CYCastJSObject(context, arguments[0]));
size_t count(CYArrayLength(context, types));
return CYMakeType(context, *type);
} CYCatch(NULL) }
+static JSValueRef Type_callAsFunction_enumFor(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+ if (count != 1)
+ throw CYJSError(context, "incorrect number of arguments to Type.enumFor");
+ Type_privateData *internal(reinterpret_cast<Type_privateData *>(JSObjectGetPrivate(_this)));
+
+ CYPool pool;
+
+ JSObjectRef constants(CYCastJSObject(context, arguments[0]));
+
+ // XXX: this is, sadly, going to leak
+ JSPropertyNameArrayRef names(JSObjectCopyPropertyNames(context, constants));
+
+ size_t count(JSPropertyNameArrayGetCount(names));
+
+ sig::Enum type(*internal->type_, count);
+ type.constants = new(pool) sig::Constant[count];
+
+ for (size_t index(0); index != count; ++index) {
+ JSStringRef name(JSPropertyNameArrayGetNameAtIndex(names, index));
+ JSValueRef value(CYGetProperty(context, constants, name));
+ _assert(JSValueGetType(context, value) == kJSTypeNumber);
+ CYUTF8String string(CYPoolUTF8String(pool, context, name));
+ type.constants[index].name = string.data;
+ type.constants[index].value = CYCastDouble(context, value);
+ }
+
+ JSPropertyNameArrayRelease(names);
+
+ return CYMakeType(context, type);
+} CYCatch(NULL) }
+
static JSValueRef Type_callAsFunction_functionWith(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) {
bool variadic(count != 0 && JSValueIsNull(context, arguments[count - 1]));
sig::Function type(variadic);
{NULL, NULL, NULL, 0}
};
-static JSStaticFunction Type_staticFunctions[9] = {
+static JSStaticFunction Type_staticFunctions[10] = {
{"arrayOf", &Type_callAsFunction_arrayOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"blockWith", &Type_callAsFunction_blockWith, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"constant", &Type_callAsFunction_constant, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
+ {"enumFor", &Type_callAsFunction_enumFor, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"functionWith", &Type_callAsFunction_functionWith, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"pointerTo", &Type_callAsFunction_pointerTo, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"withName", &Type_callAsFunction_withName, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
}
void CYTypedIdentifier::Output(CYOutput &out) const {
- specifier_->Output(out);
+ out << *specifier_;
modifier_->Output(out, 0, identifier_, true);
}
out << "char";
}
+void CYTypeEnum::Output(CYOutput &out) const {
+ out << "enum" << ' ';
+ if (name_ != NULL)
+ out << *name_;
+ else {
+ if (specifier_ != NULL)
+ out << ':' << ' ' << *specifier_ << ' ';
+
+ out << '{' << '\n';
+ ++out.indent_;
+ bool comma(false);
+
+ CYForEach (constant, constants_) {
+ if (comma)
+ out << ',' << '\n';
+ else
+ comma = true;
+ out << '\t' << constant->name_;
+ out << ' ' << '=' << ' ' << constant->value_;
+ }
+
+ if (out.pretty_)
+ out << ',';
+ out << '\n';
+ --out.indent_;
+ out << '\t' << '}';
+ }
+}
+
void CYTypeError::Output(CYOutput &out) const {
out << "@error";
}
}
void CYTypeReference::Output(CYOutput &out) const {
- out << "struct" << ' ' << *name_;
+ switch (kind_) {
+ case CYTypeReferenceStruct: out << "struct"; break;
+ case CYTypeReferenceEnum: out << "enum"; break;
+ default: _assert(false);
+ }
+
+ out << ' ' << *name_;
}
void CYTypeVariable::Output(CYOutput &out) const {
%union { CYClassTail *classTail_; }
%union { CYComprehension *comprehension_; }
%union { CYElement *element_; }
+%union { CYEnumConstant *constant_; }
%union { CYExpression *expression_; }
%union { CYFalse *false_; }
%union { CYVariable *variable_; }
%type <expression_> YieldExpression
@begin C
+%type <constant_> EnumConstantListOpt_
+%type <constant_> EnumConstantListOpt
+%type <number_> IntegerNumber
%type <integral_> IntegerType
%type <integral_> IntegerTypeOpt
%type <typedIdentifier_> PrefixedType
+%type <specifier_> PrimitiveReference
%type <specifier_> PrimitiveType
%type <structField_> StructFieldListOpt
%type <typedIdentifier_> SuffixedType
%type <typedIdentifier_> TypedIdentifierField
%type <typedIdentifier_> TypedIdentifierMaybe
%type <typedIdentifier_> TypedIdentifierNo
+%type <typedIdentifier_> TypedIdentifierTagged
%type <typedIdentifier_> TypedIdentifierYes
%type <typedFormal_> TypedParameterList_
%type <typedFormal_> TypedParameterList
| { $$ = NULL; }
;
+IntegerNumber
+ : NumericLiteral[pass] { $$ = $pass; }
+ | "-" NumericLiteral[positive] { $$ = $positive; $$->value_ = -$$->value_; }
+ ;
+
+EnumConstantListOpt_
+ : "," EnumConstantListOpt[pass] { $$ = $pass; }
+ | { $$ = NULL; }
+ ;
+
+EnumConstantListOpt
+ : IdentifierType[name] "=" IntegerNumber[value] EnumConstantListOpt_[next] { $$ = CYNew CYEnumConstant($name, $value, $next); }
+ | { $$ = NULL; }
+ ;
+
TypeSigning
: { $$ = CYTypeNeutral; }
| "signed" { $$ = CYTypeSigned; }
| IntegerType[pass] { $$ = $pass; }
| TypeSigning[signing] "char" { $$ = CYNew CYTypeCharacter($signing); }
| TypeSigning[signing] "__int128" { $$ = CYNew CYTypeInt128($signing); }
- | "struct" IdentifierType[name] { $$ = CYNew CYTypeReference($name); }
+ ;
+
+PrimitiveReference
+ : PrimitiveType[pass] { $$ = $pass; }
+ | "struct" IdentifierType[name] { $$ = CYNew CYTypeReference(CYTypeReferenceStruct, $name); }
+ | "enum" IdentifierType[name] { $$ = CYNew CYTypeReference(CYTypeReferenceEnum, $name); }
;
TypedIdentifierMaybe
: TypeQualifierLeft[modifier] "void" TypeQualifierRight[typed] { $$ = $typed; $$->specifier_ = CYNew CYTypeVoid(); CYSetLast($modifier) = $$->modifier_; $$->modifier_ = $modifier; }
| "void" TypeQualifierRight[typed] { $$ = $typed; $$->specifier_ = CYNew CYTypeVoid(); }
- | TypeQualifierLeftOpt[modifier] PrimitiveType[specifier] TypeQualifierRightOpt[typed] { $$ = $typed; $$->specifier_ = $specifier; CYSetLast($modifier) = $$->modifier_; $$->modifier_ = $modifier; }
+ | TypeQualifierLeftOpt[modifier] PrimitiveReference[specifier] TypeQualifierRightOpt[typed] { $$ = $typed; $$->specifier_ = $specifier; CYSetLast($modifier) = $$->modifier_; $$->modifier_ = $modifier; }
;
TypedIdentifierYes
: TypedIdentifierMaybe[typed] { if ($typed->identifier_ != NULL) CYERR($typed->location_, "unexpected identifier"); $$ = $typed; }
;
+TypedIdentifierTagged
+ : TypeQualifierLeftOpt[modifier] "struct" "{" StructFieldListOpt[fields] "}" TypeQualifierRightOpt[typed] { $$ = $typed; $$->specifier_ = CYNew CYTypeStruct(NULL, CYNew CYStructTail($fields)); CYSetLast($modifier) = $$->modifier_; $$->modifier_ = $modifier; }
+ | TypeQualifierLeftOpt[modifier] "enum" ":" PrimitiveType[specifier] "{" EnumConstantListOpt[constants] "}" TypeQualifierRightOpt[typed] { $$ = $typed; $$->specifier_ = CYNew CYTypeEnum(NULL, $specifier, $constants); CYSetLast($modifier) = $$->modifier_; $$->modifier_ = $modifier; }
+ ;
+
TypedIdentifierField
: TypedIdentifierYes[pass] { $$ = $pass; }
- | TypeQualifierLeftOpt[modifier] "struct" "{" StructFieldListOpt[fields] "}" TypeQualifierRightOpt[typed] { if ($typed->identifier_ == NULL) CYERR($typed->location_, "expected identifier"); $$ = $typed; $$->specifier_ = CYNew CYTypeStruct(NULL, CYNew CYStructTail($fields)); CYSetLast($modifier) = $$->modifier_; $$->modifier_ = $modifier; }
+ | TypedIdentifierTagged[typed] { if ($typed->identifier_ == NULL) CYERR($typed->location_, "expected identifier"); $$ = $typed; }
;
TypedIdentifierEncoding
: TypedIdentifierNo[pass] { $$ = $pass; }
- | TypeQualifierLeftOpt[modifier] "struct" "{" StructFieldListOpt[fields] "}" TypeQualifierRightOpt[typed] { if ($typed->identifier_ != NULL) CYERR($typed->location_, "unexpected identifier"); $$ = $typed; $$->specifier_ = CYNew CYTypeStruct(NULL, CYNew CYStructTail($fields)); CYSetLast($modifier) = $$->modifier_; $$->modifier_ = $modifier; }
+ | TypedIdentifierTagged[typed] { if ($typed->identifier_ != NULL) CYERR($typed->location_, "unexpected identifier"); $$ = $typed; }
| "void" TypeSignifierNone[typed] { $$ = $typed; $$->specifier_ = CYNew CYTypeVoid(); }
;
;
PrimaryExpression
- : "(" LexOf "struct" NewLineOpt IdentifierType[name] TypeQualifierRightOpt[typed] ")" { $typed->specifier_ = CYNew CYTypeReference($name); $$ = CYNew CYTypeExpression($typed); }
+ : "(" LexOf "struct" NewLineOpt IdentifierType[name] TypeQualifierRightOpt[typed] ")" { $typed->specifier_ = CYNew CYTypeReference(CYTypeReferenceStruct, $name); $$ = CYNew CYTypeExpression($typed); }
;
/* }}} */
/* Cycript (C): Type Definitions {{{ */
return $ CYLexical(false, $B1($B(identifier, $ CYTypeExpression(typed_))));
}
+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) {
_assert(false);
return NULL;
}
CYTarget *CYTypeReference::Replace(CYContext &context) {
- return $V($pool.strcat(name_->Word(), "$cy", NULL));
+ const char *suffix;
+ switch (kind_) {
+ case CYTypeReferenceStruct: suffix = "$cys"; break;
+ case CYTypeReferenceEnum: suffix = "$cye"; break;
+ default: _assert(false);
+ }
+
+ return $V($pool.strcat(name_->Word(), suffix, NULL));
}
CYTarget *CYTypeStruct::Replace(CYContext &context) {
virtual void Output(CYOutput &out) const;
};
+enum CYTypeReferenceKind {
+ CYTypeReferenceStruct,
+ CYTypeReferenceEnum,
+};
+
struct CYTypeReference :
CYTypeSpecifier
{
+ CYTypeReferenceKind kind_;
CYIdentifier *name_;
- CYTypeReference(CYIdentifier *name) :
+ CYTypeReference(CYTypeReferenceKind kind, CYIdentifier *name) :
+ kind_(kind),
name_(name)
{
}
virtual void Output(CYOutput &out, CYFlags flags) const;
};
+struct CYEnumConstant :
+ CYNext<CYEnumConstant>
+{
+ CYIdentifier *name_;
+ CYNumber *value_;
+
+ CYEnumConstant(CYIdentifier *name, CYNumber *value, CYEnumConstant *next = NULL) :
+ CYNext<CYEnumConstant>(next),
+ name_(name),
+ value_(value)
+ {
+ }
+};
+
+struct CYTypeEnum :
+ CYTypeSpecifier
+{
+ CYIdentifier *name_;
+ CYTypeSpecifier *specifier_;
+ CYEnumConstant *constants_;
+
+ CYTypeEnum(CYIdentifier *name, CYTypeSpecifier *specifier, CYEnumConstant *constants) :
+ name_(name),
+ specifier_(specifier),
+ constants_(constants)
+ {
+ }
+
+ virtual CYTarget *Replace(CYContext &context);
+ virtual void Output(CYOutput &out) const;
+};
+
namespace cy {
namespace Syntax {
}
#endif
+Enum *Enum::Copy(CYPool &pool, const char *rename) const {
+ if (rename == NULL)
+ rename = pool.strdup(name);
+ else if (rename[0] == '\0')
+ rename = NULL;
+ Enum *copy(new(pool) Enum(*type.Copy(pool), count, rename));
+ copy->constants = new(pool) Constant[count];
+ for (size_t i(0); i != count; ++i) {
+ copy->constants[i].name = pool.strdup(constants[i].name);
+ copy->constants[i].value = constants[i].value;
+ }
+ return copy;
+}
+
Aggregate *Aggregate::Copy(CYPool &pool, const char *rename) const {
if (rename == NULL)
rename = pool.strdup(name);
return NULL;
}
+const char *Enum::GetName() const {
+ return name;
+}
+
const char *Aggregate::GetName() const {
return name;
}
}
#endif
+ffi_type *Enum::GetFFI(CYPool &pool) const {
+ return type.GetFFI(pool);
+}
+
ffi_type *Aggregate::GetFFI(CYPool &pool) const {
// XXX: we can totally make overlap work
_assert(!overlap);
}
#endif
+const char *Enum::Encode(CYPool &pool) const {
+ return type.Encode(pool);
+}
+
const char *Aggregate::Encode(CYPool &pool) const {
return pool.strcat(overlap ? "(" : "{", name == NULL ? "?" : name, "=", Unparse(pool, &signature), overlap ? ")" : "}", NULL);
}
};
#endif
+struct Constant {
+ const char *name;
+ double value;
+};
+
+struct Enum :
+ Type
+{
+ Type &type;
+ unsigned count;
+ const char *name;
+
+ Constant *constants;
+
+ Enum(Type &type, unsigned count, const char *name = NULL) :
+ type(type),
+ count(count),
+ name(name),
+ constants(NULL)
+ {
+ }
+
+ Enum *Copy(CYPool &pool, const char *rename = NULL) const override;
+ const char *GetName() const override;
+
+ const char *Encode(CYPool &pool) const override;
+ CYTypedIdentifier *Decode(CYPool &pool) const override;
+
+ ffi_type *GetFFI(CYPool &pool) const override;
+ void PoolFFI(CYPool *pool, JSContextRef context, ffi_type *ffi, void *data, JSValueRef value) const override;
+ JSValueRef FromFFI(JSContextRef context, ffi_type *ffi, void *data, bool initialize, JSObjectRef owner) const override;
+};
+
struct Aggregate :
Type
{