Programim dhe zhvillim, javascript, python, php, html

Konvertoni konstantet e numrit të Objektivit-C në emra vargjesh

Më parë, kjo ishte e pamundur (duhet t'i shkruani të gjitha me dorë / të krijoni një grup statik / t'i vendosni të gjitha vlerat në një fjalor dhe t'i lexoni përsëri ... etj)

Por kam vënë re se lldb-ja e fundit e Xcode (4.6, ndoshta edhe versionet e mëparshme) po konverton automatikisht konstantet enum në vargje.

Problemi im është se ne përdorim shumë biblioteka - duke përfshirë bibliotekat e Apple! - të cilat përdorin numërime publike të bezdisshme pa asnjë metodë "vlerë-në-string" të ofruar. Kështu që më duhet (shumë, shumë herë) të bëj "mirë, meqenëse z. Autori i Bibliotekës nuk e bëri këtë, tani më duhet të bëj grupin statik për ta...".

Vazhdova të shpresoja se Apple do të siguronte një rrugëdalje nga kjo - a është më në fund këtu? Apo është ky një truk që vetëm korrigjuesi mund ta bëjë - thjesht kodi i kohës së funksionimit nuk ka akses në të?

06.08.2013

  • Po, vetëm korrigjuesi mund ta bëjë këtë - përpiluesi gjeneron simbole korrigjimi dhe krijon vargje nga enum në mënyrë automatike. Një alternativë është makroja e paraprocesorit #define TO_STR(m) #m, e cila mund të jetë ose jo e kënaqshme për rastin tuaj të përdorimit. 06.08.2013

Përgjigjet:


1

lldb nuk ka ndonjë aftësi të veçantë në lidhje me printimin e emrave të numrit. Unë mendoj se ajo që po shihni është rezultat i vlerave enum që janë regjistruar në informacionin e korrigjimit (ose jo). Për shembull,

enum myenums {a = 0, b, c};
int main ()
{
 enum myenums var = b;
 return (int) var;  // break here
}

% xcrun clang -g a.c
% xcrun lldb a.out
(lldb) br s -p break
Breakpoint 1: where = a.out`main + 18 at a.c:5, address = 0x0000000100000f92
(lldb) r
[...]
-> 5     return (int) var;  // break here
   6    }
(lldb) p var
(myenums) $0 = b
(lldb) p (myenums) 0
(myenums) $1 = a
(lldb) 

Nëse shikoni informacionin e korrigjimit për këtë binar (dwarfdump a.out.dSYM), do të shihni se lloji i ndryshores var është myenums dhe informacioni i korrigjimit përfshin vlerat e atyre llojeve të numëruara:

0x0000005a:     TAG_enumeration_type [5] *
                 AT_name( "myenums" )
                 AT_byte_size( 0x04 )
                 AT_decl_file( "/private/tmp/a.c" )
                 AT_decl_line( 1 )

0x00000062:         TAG_enumerator [6]  
                     AT_name( "a" )
                     AT_const_value( 0x0000000000000000 )

0x00000068:         TAG_enumerator [6]  
                     AT_name( "b" )
                     AT_const_value( 0x0000000000000001 )

0x0000006e:         TAG_enumerator [6]  
                     AT_name( "c" )
                     AT_const_value( 0x0000000000000002 )

Nëse shtoj një numër tjetër në skedarin tim të mostrës që nuk përdoret askund,

enum myenums {a = 0, b, c};
enum otherenums {d = 0, e, f}; // unused in this CU
int main ()
{
 enum myenums var = b;
 return (int) var;  // break here
}

ri-përpiloni dhe shikoni Xhuxhin përsëri përmes dwarfdump, nuk do të gjej asnjë informacion korrigjimi që përshkruan otherenums - ai është i papërdorur (në këtë njësi përpilimi) dhe kështu është eliminuar.

07.08.2013

2

Siç është vënë re, emrat e konstantës nuk janë të aksesueshëm pas kompilimit, përveç në korrigjuesin. Sugjerimi i H2CO3 për makro TO_STR() duhet t'ju kalojë në shumicën e përdorimeve, mendoj.

Kohët e fundit po shqyrtoja libclang dhe vendosa ta ushtroja atë duke adresuar ankesën tuaj në lidhje me vështirësinë e përkthimit nga vlera enum në varg "(duhet t'i shkruani të gjitha me dorë / të krijoni një grup statik / t'i vendosni të gjitha vlerat në një fjalor dhe lexojini ato përsëri ... etj)".

Këtu është një skrip Python që do të analizojë një skedar Kakao, do të gjejë numrat (përfshirë ato të përcaktuara me NS_OPTIONS dhe NS_ENUM) dhe do të nxjerrë një grup ose një funksion (duke përdorur një switch) për të bërë hartën. Opsioni i grupit përfiton nga një veçori C e quajtur "designated ( array) inicializuesit", ku anëtarët e grupit mund të çiftohen në mënyrë eksplicite me një indeks të caktuar:

int arr[] = { [1] = 2, [3] = 8, [7] = 12 };

Vini re se ky nuk është një grup i rrallë -- çdo indeks i paspecifikuar përpara këtij të fundit është ende i krijuar dhe i inicializuar me 0. Implikimi është se enums synohen të përdoren si maska ​​bit, vlerat e të cilave janë 1 << 2 , 1 << 3, 1 << 4, e kështu me radhë, do të krijojnë vargje mjaft të mëdha për relativisht pak vlera të përdorura. Një funksion është ndoshta zgjidhja më e mirë në ato raste.

Anonimi enums (që mendoj se janë të gjitha me një anëtarë, të paktën në Foundation) konvertohen drejtpërdrejt në një NSString të vetme duke përdorur emrin e konstantës. Unë kam vënë pikë në trajtimin automatik të konstantave që kanë vlerë negative, si NSOrderedAscending -- një indeks negativ në iniciatorin e grupit nuk do të përpilohet, por alternativa e funksionit/switch do të funksionojë mirë; ju vetëm duhet ta zgjidhni atë manualisht për ato pak raste.

Skripti është në GitHub dhe ja ku është në tërësi. Licenca MIT, kështu që bëni me të çfarë të doni. Do të jem i lumtur të dëgjoj për çdo modifikim.

#!/usr/bin/env python

"""
CocoaEnumToString

Parse a specified Cocoa header file and emit ObjC code to translate the values
of any enums found within into their names as NSStrings.
"""
# Copyright 2013 Joshua Caswell.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

import itertools
import argparse
import sys
import re
from os import path

from clang import cindex
from clang.cindex import CursorKind

def all_children(node):
    return itertools.chain(iter([node]), *map(all_children, 
                                              node.get_children()))

def all_constant_decls(enum):
    return iter(child for child in all_children(enum) if 
                    child.kind == CursorKind.ENUM_CONSTANT_DECL)

def indent_all_lines(s, indent):
    return '\n'.join(indent + line for line in s.split('\n'))

def format_anonymous(enum, title):
    const_str = 'NSString * const {} = @"{}";\n'
    constants = [const_str.format(title.replace('%e', constant.spelling),
                                  constant.spelling)
                            for constant in all_constant_decls(enum)]
    return "".join(constants)


def format_as_array(enum, title, indent):
    all_members = ['[{0}] = @"{0}"'.format(constant.spelling) 
                        for constant in all_constant_decls(enum)]
    all_members = ",\n".join(all_members)

    title = title.replace('%e', enum.spelling)
    array_str = "NSString * const {}[] = {{\n{}\n}};"
    return array_str.format(title, indent_all_lines(all_members, indent))

def format_as_func(enum, title, indent):
    case_str = 'case {0}:\n{1}return @"{0}";'
    all_cases = [case_str.format(constant.spelling, indent)
                        for constant in all_constant_decls(enum)]
    all_cases.append('default:\n{}@"";'.format(indent))
    all_cases = "\n".join(all_cases)

    switch = "switch( val ){{\n{}\n}}".format(indent_all_lines(all_cases, 
                                                               indent))
    title = title.replace('%e', enum.spelling)
    func_str = "NSString * {}({} val){{\n{}\n}}"
    return func_str.format(title, enum.spelling, 
                           indent_all_lines(switch, indent))


parser = argparse.ArgumentParser(description="Use libclang to find enums in "
                                  "the specified Objective-C file and emit a "
                                  "construct (array or function) that "
                                  "maps between the constant values and "
                                  "their names.")
# This argument must be added to the parser first for its default to override
# that of --arr and --fun
parser.add_argument("-c", "--construct", default="array",
                    help="Specify 'function' or any prefix ('f', 'fun', etc.) "
                         "to emit a function that uses a switch statement for "
                         "the mapping; specify 'array' or any prefix for "
                         "an array (this is the default). Whichever of -c, "
                         "--arr, or --fun occurs last in the argument list "
                         "will dictate the output.")
parser.add_argument("--arr", "--array", action="store_const", const="array",
                    dest="construct", help="Emit an array for the mapping.")
parser.add_argument("-e", "--enums", action="append",
                    help="Specify particular enums to capture; by default "
                    "all enums in the given file are used. This argument may "
                    "be present multiple times. Names which are not found in "
                    "the input file are ignored.")
parser.add_argument("--fun", "--func", "--function", action="store_const", 
                    const="function", dest="construct", 
                    help="Emit a function for the mapping.")
parser.add_argument("-i", "--indent", default="4s",
                    help="Number and type of character to use for indentation."
                    " Digits plus either 't' (for tabs) or 's' (for spaces), "
                    "e.g., '4s', which is the default.")
parser.add_argument("-n", "--name", default="StringFor%e",
                    help="Name for the construct; the prefix will "
# Escape percent sign because argparse is doing some formatting of its own.
                    "be added. Any appearances of '%%e' in this argument will "
                    "be replaced with each enum name. The default is "
                    "'StringFor%%e'.")
parser.add_argument("-o", "--output",
                    help="If this argument is present, output should go to a "
                    "file which will be created at the specified path. An "
                    "error will be raised if the file already exists.")
parser.add_argument("-p", "--prefix", default="",
                    help="Cocoa-style prefix to add to the name of emitted "
                    "construct, e.g. 'NS'")
parser.add_argument("file", help="Path to the file which should be parsed.")


arguments = parser.parse_args()

if "array".startswith(arguments.construct):
    format_enum = format_as_array 
elif "function".startswith(arguments.construct):
    format_enum = format_as_func
else:
   parser.error("Neither 'function' nor 'array' specified for construct.")

match = re.match(r"(\d*)([st])", arguments.indent)
if not match.group(2):
    parser.error("Neither tabs nor spaces specified for indentation.")
else:
    indent_char = '\t' if match.group(2) == 't' else ' '
    indent = indent_char * int(match.group(1) or 1)

if arguments.output:
    if path.exists(arguments.output):
        sys.stderr.write("Error: Requested output file exists: "
                         "{}\n".format(arguments.output))
        sys.exit(1)
    else:
        out_f = open(arguments.output, 'w')
else:
    out_f = sys.stdout

target_file_name = arguments.file


# Ignore the fact that system libclang probably doesn't match the version
# of the Python bindings.
cindex.Config.set_compatibility_check(False)
# Use what's likely to be a newer version than that found in /usr/lib
cindex.Config.set_library_file("/Applications/Xcode.app/Contents/Developer/"
                               "Toolchains/XcodeDefault.xctoolchain/usr/lib/"
                               "libclang.dylib")

# Preprocessor macros that resolve into enums; these are defined in
# NSObjCRuntime.h, but including that directly causes redefinition errors due
# to it being also imported.
ns_options_def = ("NS_OPTIONS(_type, _name)=enum _name : "
                 "_type _name; enum _name : _type")
ns_enum_def = ("NS_ENUM(_type, _name)=enum _name : _type _name; "
              "enum _name : _type")

tu = cindex.TranslationUnit.from_source(target_file_name, 
                                        args=["-ObjC", "-D", ns_enum_def,
                                              "-D", ns_options_def, "-D",
                                              "NS_ENUM_AVAILABLE="])


enums = [node for node in all_children(tu.cursor) if 
                node.kind == CursorKind.ENUM_DECL and
                node.location.file.name.find(target_file_name) != -1]
if arguments.enums:
    enums = filter(lambda enum: enum.spelling in arguments.enums, enums)

title = arguments.prefix + arguments.name

for enum in enums:
    if not enum.spelling:
        out_f.write(format_anonymous(enum, title))
    else:
        out_f.write(format_enum(enum, title, indent))
    out_f.write("\n\n")
15.08.2013
Materiale të reja

Masterclass Coroutines: Kapitulli-3: Anulimi i korutinave dhe trajtimi i përjashtimeve.
Mirë se vini në udhëzuesin gjithëpërfshirës mbi Kotlin Coroutines! Në këtë seri artikujsh, unë do t'ju çoj në një udhëtim magjepsës, duke filluar nga bazat dhe gradualisht duke u thelluar në..

Faketojeni derisa ta arrini me të dhënat false
A e gjeni ndonjëherë veten duke ndërtuar një aplikacion të ri dhe keni nevojë për të dhëna testimi që duken dhe duken më realiste ose një grup i madh të dhënash për performancën e ngarkesës...

Si të përdorni kërkesën API në Python
Kërkesë API në GitHub për të marrë depot e përdoruesve duke përdorur Python. Në këtë artikull, unë shpjegoj procesin hap pas hapi për të trajtuar një kërkesë API për të marrë të dhëna nga..

Një udhëzues hap pas hapi për të zotëruar React
Në këtë artikull, do të mësoni se si të krijoni aplikacionin React, do të mësoni se si funksionon React dhe konceptet thelbësore që duhet të dini për të ndërtuar aplikacione React. Learning..

AI dhe Psikologjia — Pjesa 2
Në pjesën 2 të serisë sonë të AI dhe Psikologji ne diskutojmë se si makineritë mbledhin dhe përpunojnë të dhëna për të mësuar emocione dhe ndjenja të ndryshme në mendjen e njeriut, duke ndihmuar..

Esencialet e punës ditore të kodit tim VS
Shtesat e mia të preferuara - Git Graph 💹 Kjo shtesë është vërtet e mahnitshme, e përdor përpara se të filloj të punoj për të kontrolluar dy herë ndryshimet dhe degët më të fundit, mund të..

Pse Python? Zbulimi i fuqisë së gjithanshme të një gjiganti programues
Në peizazhin gjithnjë në zhvillim të gjuhëve të programimit, Python është shfaqur si një forcë dominuese. Rritja e tij meteorike nuk është rastësi. Joshja e Python qëndron në thjeshtësinë,..