From b3c38c5f53b15b19451ca1e4d3c9c03984c6ad1d Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Fri, 18 Dec 2015 21:57:13 -0800 Subject: [PATCH] Finally provide totally legit support for structs. --- Decode.cpp | 12 ++++++++++-- Execute.cpp | 43 +++++++++++++++++++++++++++++++++++++++---- List.hpp | 27 ++++++++++++++++++++------- Output.cpp | 15 +++++++++++++++ Parser.ypp.in | 16 ++++++++++++++++ Replace.cpp | 22 ++++++++++++++++++++++ Scanner.lpp.in | 1 + Syntax.hpp | 30 +++++++++++++++++++++++++++++- 8 files changed, 152 insertions(+), 14 deletions(-) diff --git a/Decode.cpp b/Decode.cpp index 95f68ef..e7ea5f9 100644 --- a/Decode.cpp +++ b/Decode.cpp @@ -88,8 +88,16 @@ CYTypedIdentifier *Decode_(CYPool &pool, struct sig::Type *type) { case sig::void_P: return $ CYTypedIdentifier($ CYTypeVoid()); case sig::struct_P: { - _assert(type->name != NULL); - return $ CYTypedIdentifier($ CYTypeVariable(type->name)); + CYTypeStructField *fields(NULL); + for (size_t i(type->data.signature.count); i != 0; --i) { + sig::Element &element(type->data.signature.elements[i - 1]); + CYTypedIdentifier *typed(Decode(pool, element.type)); + if (element.name != NULL) + typed->identifier_ = $I(element.name); + fields = $ CYTypeStructField(typed, fields); + } + CYIdentifier *name(type->name == NULL ? NULL : $I(type->name)); + return $ CYTypedIdentifier($ CYTypeStruct(name, fields)); } break; } diff --git a/Execute.cpp b/Execute.cpp index bb337ba..b450076 100644 --- a/Execute.cpp +++ b/Execute.cpp @@ -1175,11 +1175,46 @@ static JSObjectRef Pointer_new(JSContextRef context, JSObjectRef object, size_t } CYCatch(NULL) } static JSObjectRef Type_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { - if (count != 1) - throw CYJSError(context, "incorrect number of arguments to Type constructor"); CYPool pool; - const char *type(CYPoolCString(pool, context, arguments[0])); - return CYMakeType(context, type); + + if (false) { + } else if (count == 1) { + const char *type(CYPoolCString(pool, context, arguments[0])); + return CYMakeType(context, type); + } else if (count == 2) { + JSObjectRef types(CYCastJSObject(context, arguments[0])); + size_t count(CYArrayLength(context, types)); + + JSObjectRef names(CYCastJSObject(context, arguments[1])); + + sig::Type type; + type.name = NULL; + type.flags = 0; + + type.primitive = sig::struct_P; + type.data.signature.elements = new(pool) sig::Element[count]; + type.data.signature.count = count; + + for (size_t i(0); i != count; ++i) { + sig::Element &element(type.data.signature.elements[i]); + element.offset = _not(size_t); + + JSValueRef name(CYArrayGet(context, names, i)); + if (JSValueIsUndefined(context, name)) + element.name = NULL; + else + element.name = CYPoolCString(pool, context, name); + + JSObjectRef object(CYCastJSObject(context, CYArrayGet(context, types, i))); + _assert(JSValueIsObjectOfClass(context, object, Type_privateData::Class_)); + Type_privateData *internal(reinterpret_cast(JSObjectGetPrivate(object))); + element.type = internal->type_; + } + + return CYMakeType(context, &type); + } else { + throw CYJSError(context, "incorrect number of arguments to Type constructor"); + } } CYCatch(NULL) } static JSValueRef Type_callAsFunction_$With(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], sig::Primitive primitive, JSValueRef *exception) { CYTry { diff --git a/List.hpp b/List.hpp index 4caa536..010f7ae 100644 --- a/List.hpp +++ b/List.hpp @@ -22,6 +22,8 @@ #ifndef CYCRIPT_LIST_HPP #define CYCRIPT_LIST_HPP +#include "Exception.hpp" + template struct CYNext { Type_ *next_; @@ -68,12 +70,24 @@ struct CYList { Type_ *first_; Type_ *last_; - CYList(Type_ *first = NULL) : + CYList() : + first_(NULL), + last_(NULL) + { + } + + CYList(Type_ *first) : first_(first), last_(CYGetLast(first)) { } + CYList(Type_ *first, Type_ *last) : + first_(first), + last_(last) + { + } + operator Type_ *() const { return first_; } @@ -87,12 +101,11 @@ struct CYList { if (first_ == NULL) { first_ = next; last_ = next; - } else for (;; last_ = last_->next_) - if (last_->next_ == NULL) { - last_->next_ = next; - last_ = next; - break; - } + } else { + _assert(last_->next_ == NULL); + last_->next_ = next; + last_ = next; + } return *this; } diff --git a/Output.cpp b/Output.cpp index cbd853f..6610ff2 100644 --- a/Output.cpp +++ b/Output.cpp @@ -920,6 +920,21 @@ void CYTypeSigned::Output(CYOutput &out) const { out << "signed" << specifier_; } +void CYTypeStruct::Output(CYOutput &out) const { + out << "struct" << ' '; + if (name_ != NULL) + out << *name_ << ' '; + out << '{' << '\n'; + ++out.indent_; + CYForEach (field, fields_) { + out << '\t' << *field->typed_; + out.Terminate(); + out << '\n'; + } + --out.indent_; + out << '}'; +} + void CYTypeUnsigned::Output(CYOutput &out) const { out << "unsigned" << specifier_; } diff --git a/Parser.ypp.in b/Parser.ypp.in index f73ccd1..17b42e5 100644 --- a/Parser.ypp.in +++ b/Parser.ypp.in @@ -80,6 +80,7 @@ %union { CYWord *word_; } @begin C +%union { CYTypeStructField *structField_; } %union { CYTypeModifier *modifier_; } %union { CYTypeSpecifier *specifier_; } %union { CYTypedIdentifier *typedIdentifier_; } @@ -330,6 +331,7 @@ type; }) %token _typedef_ "typedef" %token _unsigned_ "unsigned" %token _signed_ "signed" +%token _struct_ "struct" %token _extern_ "extern" @end @@ -543,6 +545,7 @@ type; }) %type IdentifierNoOf %type IdentifierType %type IdentifierTypeNoOf +%type IdentifierTypeOpt %type IdentifierName %type IdentifierReference %type IfStatement @@ -626,6 +629,7 @@ type; }) %type IntegerTypeOpt %type PrefixedType %type PrimitiveType +%type StructFieldListOpt %type SuffixedType %type TypeSignifier %type TypeQualifierLeft @@ -930,6 +934,11 @@ IdentifierType | "of" { $$ = CYNew CYIdentifier("of"); } ; +IdentifierTypeOpt + : IdentifierType[pass] { $$ = $pass; } + | { $$ = NULL; } + ; + IdentifierNoOf : IdentifierTypeNoOf | "char" { $$ = CYNew CYIdentifier("char"); } @@ -940,6 +949,7 @@ IdentifierNoOf | "volatile" { $$ = CYNew CYIdentifier("volatile"); } @begin C | "signed" { $$ = CYNew CYIdentifier("signed"); } + | "struct" { $$ = CYNew CYIdentifier("struct"); } | "unsigned" { $$ = CYNew CYIdentifier("unsigned"); } @end @begin ObjectiveC @@ -1974,6 +1984,11 @@ IntegerTypeOpt | { $$ = CYNew CYTypeVariable("int"); } ; +StructFieldListOpt + : TypedIdentifierMaybe[typed] ";" StructFieldListOpt[next] { $$ = CYNew CYTypeStructField($typed, $next); } + | { $$ = NULL; } + ; + PrimitiveType : IdentifierType[name] { $$ = CYNew CYTypeVariable($name); } | IntegerType[pass] { $$ = $pass; } @@ -1981,6 +1996,7 @@ PrimitiveType | "char" { $$ = CYNew CYTypeVariable("char"); } | "signed" "char" { $$ = CYNew CYTypeSigned(CYNew CYTypeVariable("char")); } | "unsigned" "char" { $$ = CYNew CYTypeUnsigned(CYNew CYTypeVariable("char")); } + | "struct" IdentifierTypeOpt[name] "{" StructFieldListOpt[fields] "}" { $$ = CYNew CYTypeStruct($name, $fields); } ; TypedIdentifierMaybe diff --git a/Replace.cpp b/Replace.cpp index c812c35..307ccec 100644 --- a/Replace.cpp +++ b/Replace.cpp @@ -1187,6 +1187,28 @@ CYTarget *CYTypeSigned::Replace(CYContext &context) { return $ CYCall($ CYDirectMember(specifier_->Replace(context), $ CYString("signed"))); } +CYTarget *CYTypeStruct::Replace(CYContext &context) { + CYList types; + CYList names; + + CYForEach (field, fields_) { + CYTypedIdentifier *typed(field->typed_); + types->*$ CYElementValue(typed->Replace(context)); + + CYExpression *name; + if (typed->identifier_ == NULL) + name = NULL; + else + name = $S(typed->identifier_->Word()); + names->*$ CYElementValue(name); + } + + CYTarget *target($N2($V("Type"), $ CYArray(types), $ CYArray(names))); + if (name_ != NULL) + target = $C1($M(target, $S("withName")), $S(name_->Word())); + return target; +} + CYTarget *CYTypeUnsigned::Replace(CYContext &context) { return $ CYCall($ CYDirectMember(specifier_->Replace(context), $ CYString("unsigned"))); } diff --git a/Scanner.lpp.in b/Scanner.lpp.in index 518b6b4..3459b08 100644 --- a/Scanner.lpp.in +++ b/Scanner.lpp.in @@ -526,6 +526,7 @@ XMLName {XMLNameStart}{XMLNamePart}* @begin C "extern" L F(tk::_extern_, hi::Type); "signed" L F(tk::_signed_, hi::Type); +"struct" L F(tk::_struct_, hi::Meta); "typedef" L F(tk::_typedef_, hi::Meta); "unsigned" L F(tk::_unsigned_, hi::Type); @end diff --git a/Syntax.hpp b/Syntax.hpp index 89bca73..cb39f40 100644 --- a/Syntax.hpp +++ b/Syntax.hpp @@ -1090,7 +1090,7 @@ struct CYElementValue : { CYExpression *value_; - CYElementValue(CYExpression *value, CYElement *next) : + CYElementValue(CYExpression *value, CYElement *next = NULL) : CYNext(next), value_(value) { @@ -2324,6 +2324,34 @@ struct CYTypeFunctionWith : virtual CYTypeFunctionWith *Function() { return this; } }; +struct CYTypeStructField : + CYNext +{ + CYTypedIdentifier *typed_; + + CYTypeStructField(CYTypedIdentifier *typed, CYTypeStructField *next = NULL) : + CYNext(next), + typed_(typed) + { + } +}; + +struct CYTypeStruct : + CYTypeSpecifier +{ + CYIdentifier *name_; + CYTypeStructField *fields_; + + CYTypeStruct(CYIdentifier *name, CYTypeStructField *fields) : + name_(name), + fields_(fields) + { + } + + virtual CYTarget *Replace(CYContext &context); + virtual void Output(CYOutput &out) const; +}; + namespace cy { namespace Syntax { -- 2.47.2