├── .DS_Store
├── DynamicOC
├── .DS_Store
├── DynamicOC.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcuserdata
│ │ │ ├── dengqingbin.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ │ │ └── yaoshibang.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ │ ├── dengqingbin.xcuserdatad
│ │ ├── xcdebugger
│ │ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ │ └── xcschememanagement.plist
│ │ └── yaoshibang.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
├── DynamicOC
│ ├── .DS_Store
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Class
│ │ ├── ASTBlockNode.h
│ │ ├── ASTBlockNode.m
│ │ ├── ASTCallMethod.h
│ │ ├── ASTCallMethod.m
│ │ ├── ASTContext.h
│ │ ├── ASTContext.m
│ │ ├── ASTHeader.h
│ │ ├── ASTMethodNode.h
│ │ ├── ASTMethodNode.m
│ │ ├── ASTNode.h
│ │ ├── ASTNode.m
│ │ ├── ASTPropertyNode.h
│ │ ├── ASTPropertyNode.m
│ │ ├── ASTType.h
│ │ ├── ASTType.m
│ │ ├── ASTUtil.h
│ │ ├── ASTUtil.m
│ │ ├── ASTVariable.h
│ │ ├── ASTVariable.m
│ │ ├── DynamicOC.h
│ │ ├── DynamicOC.m
│ │ ├── OCBlockWrapper.h
│ │ └── OCBlockWrapper.m
│ ├── Info.plist
│ ├── Parser
│ │ ├── .DS_Store
│ │ ├── parser.ym
│ │ └── tokenizer.lm
│ ├── Vendor
│ │ ├── Aspects
│ │ │ ├── Aspects.h
│ │ │ └── Aspects.m
│ │ └── OCEval
│ │ │ ├── NSValue+struct.h
│ │ │ ├── NSValue+struct.m
│ │ │ ├── OCCFuntionWrapper.h
│ │ │ ├── OCCFuntionWrapper.m
│ │ │ ├── OCCfuntionHelper.h
│ │ │ ├── OCCfuntionHelper.m
│ │ │ ├── OCExtension.h
│ │ │ ├── OCExtension.m
│ │ │ ├── OCMethodSignature.h
│ │ │ ├── OCMethodSignature.m
│ │ │ └── libffi
│ │ │ ├── ffi.h
│ │ │ ├── ffi_arm.h
│ │ │ ├── ffi_arm64.h
│ │ │ ├── ffi_i386.h
│ │ │ ├── ffi_x86_64.h
│ │ │ ├── ffitarget.h
│ │ │ ├── ffitarget_arm.h
│ │ │ ├── ffitarget_arm64.h
│ │ │ ├── ffitarget_i386.h
│ │ │ ├── ffitarget_x86_64.h
│ │ │ └── libffi.a
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
└── DynamicOCUITests
│ ├── ArithmeticTest.m
│ ├── CallCFunctionTest.m
│ ├── CallOCFunctionTest.m
│ ├── Info.plist
│ ├── OCBlockTest.m
│ ├── OCContainerTest.m
│ ├── OCForControlTest.m
│ ├── OCIfControlTest.m
│ ├── OCPropertyTest.m
│ ├── OCWhileControlTest.m
│ └── UnaryOperationTest.m
├── README-chs.md
├── README.md
└── principle_chs.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letqingbin/DynamicOC/8824d9695e14415239b5410ad0f00df88677180f/.DS_Store
--------------------------------------------------------------------------------
/DynamicOC/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letqingbin/DynamicOC/8824d9695e14415239b5410ad0f00df88677180f/DynamicOC/.DS_Store
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC.xcodeproj/project.xcworkspace/xcuserdata/dengqingbin.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letqingbin/DynamicOC/8824d9695e14415239b5410ad0f00df88677180f/DynamicOC/DynamicOC.xcodeproj/project.xcworkspace/xcuserdata/dengqingbin.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC.xcodeproj/project.xcworkspace/xcuserdata/yaoshibang.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letqingbin/DynamicOC/8824d9695e14415239b5410ad0f00df88677180f/DynamicOC/DynamicOC.xcodeproj/project.xcworkspace/xcuserdata/yaoshibang.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC.xcodeproj/xcuserdata/dengqingbin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC.xcodeproj/xcuserdata/dengqingbin.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | DynamicOC.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC.xcodeproj/xcuserdata/yaoshibang.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC.xcodeproj/xcuserdata/yaoshibang.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | DynamicOC.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letqingbin/DynamicOC/8824d9695e14415239b5410ad0f00df88677180f/DynamicOC/DynamicOC/.DS_Store
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/23.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 | @property (strong, nonatomic) UIWindow *window;
13 | @end
14 |
15 |
16 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/23.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "ASTHeader.h"
11 | #import "ASTUtil.h"
12 | #import "OCCfuntionHelper.h"
13 | #import "ASTCallMethod.h"
14 |
15 | #import
16 | #import
17 |
18 | #import "DynamicOC.h"
19 |
20 | @interface AppDelegate ()
21 |
22 | @end
23 |
24 | @implementation AppDelegate
25 |
26 |
27 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
28 |
29 | NSString* text = @" \
30 | [OCCfuntionHelper defineCFunction:@\"NSSelectorFromString\" types:@\"SEL,NSString *\"];\
31 | [OCCfuntionHelper defineCFunction:@\"class_getMethodImplementation\" types:@\"IMP,Class,SEL\"];\
32 | [OCCfuntionHelper defineCFunction:@\"class_addMethod\" types:@\"BOOL,Class,SEL,IMP,char *\"];\
33 | SEL viewDidLoad = NSSelectorFromString(@\"viewDidLoad\");\
34 | IMP imp = class_getMethodImplementation([ViewController class], viewDidLoad);\
35 | SEL selector = NSSelectorFromString(@\"tableView:numberOfRowsInSection:\");\
36 | BOOL didAdd1 = class_addMethod([ViewController class], selector,imp ,@\"i@:@i\");\
37 | SEL selector2 = NSSelectorFromString(@\"tableView:cellForRowAtIndexPath:\");\
38 | BOOL didAdd2 = class_addMethod([ViewController class], selector2,imp,@\"@@:@@\"); return didAdd2;";
39 |
40 | ASTNode* root = [ASTUtil parseString:text];
41 | ASTVariable* result = [root execute];
42 | [root.context clearAllContexts];
43 | NSAssert([result.value boolValue] == YES, nil);
44 |
45 | [ASTUtil registerVariableForYacc:@"self"];
46 |
47 | text = @"\
48 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; \
49 | self.window.backgroundColor = [UIColor whiteColor]; \
50 | ViewController *vc = [[ViewController alloc] init]; \
51 | UINavigationController *navc = [[UINavigationController alloc] initWithRootViewController:vc ]; \
52 | navc.navigationBar.translucent = NO; \
53 | self.window.rootViewController = navc; \
54 | [self.window makeKeyAndVisible]; \
55 | return 666; \
56 | ";
57 |
58 | root = [ASTUtil parseString:text];
59 | ASTVariable* varSelf = [[ASTVariable alloc]init];
60 | varSelf.value = self;
61 | varSelf.type = ASTNodeTypeVariable;
62 | [root.context pushValue:varSelf forKey:@"self"];
63 | result = [root execute];
64 | [root.context clearAllContexts];
65 | NSAssert([result.value doubleValue] == 666, nil);
66 |
67 |
68 | //numberOfRowsInSection
69 | NSString *numberOfRowsInSection = @"NSArray *array = objc_getAssociatedObject(self, @\"data\");\
70 | if (array != nil) {\
71 | return array.count;\
72 | }else{\
73 | return 0;\
74 | };\
75 | ";
76 |
77 | [DynamicOC hookClass:@"ViewController"
78 | selector:@"tableView:numberOfRowsInSection:"
79 | argNames:@[@"tableView",@"section"]
80 | isClass:NO
81 | implementation:numberOfRowsInSection];
82 |
83 |
84 | //cellForRowAtIndexPath
85 | NSString *cellForRowAtIndexPath = @"\
86 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@\"aCell\"];\
87 | if (cell == nil) {\
88 | cell = [[UITableViewCell alloc] initWithStyle:3 reuseIdentifier:@\"aCell\"];\
89 | }\
90 | NSArray *array = objc_getAssociatedObject(self, @\"data\");\
91 | NSDictionary *model = array[indexPath.row];\
92 | NSString *title = model[@\"title\"];\
93 | if (title.length > 45) {\
94 | title = [title substringWithRange:NSMakeRange(0, 45)];\
95 | }\
96 | cell.textLabel.text = title;\
97 | cell.detailTextLabel.text = [NSString stringWithFormat:@\"%@,%@,%@\",model[@\"company\"],model[@\"location\"],model[@\"created_at\"]];\
98 | return cell;\
99 | ";
100 |
101 | [DynamicOC hookClass:@"ViewController"
102 | selector:@"tableView:cellForRowAtIndexPath:"
103 | argNames:@[@"tableView",@"indexPath"]
104 | isClass:NO
105 | implementation:cellForRowAtIndexPath];
106 |
107 |
108 | //viewDidload
109 | NSString *viewDidload = @"\
110 | [OCCfuntionHelper defineCFunction:@\"objc_setAssociatedObject\" types:@\"void,id,void *,id,unsigned int\"];\
111 | [OCCfuntionHelper defineCFunction:@\"objc_getAssociatedObject\" types:@\"id,id,void *\"];\
112 | [originalInvocation invoke];\
113 | self.title = @\"DynamicOC\"; \
114 | CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-64); \
115 | UITableView *tableView = [[UITableView alloc] initWithFrame:frame style:0];\
116 | [self.view addSubview:tableView];\
117 | tableView.delegate = self;\
118 | tableView.dataSource = self;\
119 | tableView.tableFooterView = [UIView new];\
120 | tableView.tableHeaderView = [UIView new];\
121 | UIActivityIndicatorView* loadingView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:2]; \
122 | loadingView.frame = CGRectMake(self.view.frame.size.width/2.0-22, self.view.frame.size.height/2.0-22, 44, 44); \
123 | [loadingView startAnimating]; \
124 | [self.view addSubview:loadingView]; \
125 | NSURL *url = [NSURL URLWithString:@\"https://jobs.github.com/positions.json?page=1&search=iOS\"];\
126 | NSURLRequest *request = [NSURLRequest requestWithURL:url];\
127 | [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * response, NSData * data, NSError * connectionError) {\
128 | if(!self) return; \
129 | [loadingView stopAnimating];\
130 | if(data){\
131 | NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];\
132 | objc_setAssociatedObject(self, @\"data\", array, 1);\
133 | [tableView reloadData];\
134 | }\
135 | }];\
136 | ";
137 |
138 | [DynamicOC hookClass:@"ViewController"
139 | selector:@"viewDidLoad"
140 | argNames:@[]
141 | isClass:NO
142 | implementation:viewDidload];
143 |
144 | return YES;
145 | }
146 |
147 |
148 | - (void)applicationWillResignActive:(UIApplication *)application {
149 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
150 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
151 | }
152 |
153 |
154 | - (void)applicationDidEnterBackground:(UIApplication *)application {
155 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
156 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
157 | }
158 |
159 |
160 | - (void)applicationWillEnterForeground:(UIApplication *)application {
161 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
162 | }
163 |
164 |
165 | - (void)applicationDidBecomeActive:(UIApplication *)application {
166 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
167 | }
168 |
169 |
170 | - (void)applicationWillTerminate:(UIApplication *)application {
171 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
172 | }
173 |
174 |
175 | @end
176 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTBlockNode.h:
--------------------------------------------------------------------------------
1 | //
2 | // ASTBlockNode.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/27.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ASTNode.h"
10 |
11 | @interface ASTBlockNode : ASTNode
12 | @property (nonatomic,strong) NSMutableArray *typeNames;
13 | @property (nonatomic,strong) NSMutableArray *arguments;
14 | @property (nonatomic,strong) NSMutableDictionary* blockContext;
15 | @property (nonatomic,strong) id blockPtr;
16 | - (id)handleBlock;
17 | @end
18 |
19 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTBlockNode.m:
--------------------------------------------------------------------------------
1 | //
2 | // ASTBlockNode.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/27.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ASTBlockNode.h"
10 | #import "ASTUtil.h"
11 | #import "ASTVariable.h"
12 | #import "ASTType.h"
13 | #import "ASTContext.h"
14 | #import "OCBlockWrapper.h"
15 |
16 | @implementation ASTBlockNode
17 |
18 | - (id)handleBlockDeclarator
19 | {
20 | if(self.allChilds.count < 3) return nil;
21 |
22 | //block return type
23 | ASTNode* returnTypeNode = self.allChilds[0];
24 | ASTType* typeName = [ASTUtil typeForNodeType:returnTypeNode.type keyword:returnTypeNode.keyword];
25 |
26 | if(typeName == nil)
27 | {
28 | typeName = [[ASTType alloc]init];
29 | typeName.type = returnTypeNode.type;
30 | typeName.keyword = returnTypeNode.keyword;
31 | }
32 | [self.typeNames addObject:typeName.keyword];
33 |
34 | //block variable name
35 | ASTNode* variableNode = self.allChilds[1];
36 | NSString* variable = variableNode.value;
37 |
38 | //block arugment list
39 | ASTNode* argumentNode = self.allChilds[2];
40 | for(ASTNode* node in argumentNode.allChilds)
41 | {
42 | typeName = [ASTUtil typeForNodeType:node.type keyword:node.keyword];
43 | [self.typeNames addObject:typeName.keyword];
44 | }
45 |
46 | ASTVariable* result = [[ASTVariable alloc]init];
47 | result.type = ASTNodeTypeBlock;
48 | result.name = variable;
49 | result.value = self;
50 |
51 | [self.context pushValue:result forKey:variable];
52 |
53 | return result;
54 | }
55 |
56 | - (id)handleBlock
57 | {
58 | ASTNode* returnTypeNode = self.allChilds[0];
59 | ASTType* typeName = [ASTUtil typeForNodeType:returnTypeNode.type keyword:returnTypeNode.keyword];
60 |
61 | if(typeName == nil)
62 | {
63 | typeName = [[ASTType alloc]init];
64 | typeName.type = returnTypeNode.type;
65 | typeName.keyword = returnTypeNode.keyword;
66 | }
67 | [self.typeNames addObject:typeName.keyword];
68 |
69 | ASTNode* argumentNode = self.allChilds[1];
70 | if(argumentNode.allChilds.count == 0)
71 | {
72 | //if empty, default void
73 | typeName = [ASTUtil typeForNodeType:ASTNodeTypeVoid keyword:nil];
74 | [self.typeNames addObject:typeName.keyword];
75 | }
76 | else
77 | {
78 | for(ASTNode* child in argumentNode.allChilds)
79 | {
80 | if(child.type == ASTNodeTypeVoid)
81 | {
82 | typeName = [ASTUtil typeForNodeType:ASTNodeTypeVoid keyword:nil];
83 | [self.typeNames addObject:typeName.keyword];
84 | }
85 | else
86 | {
87 | ASTNode* node = child.allChilds[0];
88 | typeName = [ASTUtil typeForNodeType:node.type keyword:node.keyword];
89 | if(typeName == nil)
90 | {
91 | typeName = [[ASTType alloc]init];
92 | typeName.type = node.type;
93 | typeName.keyword = node.keyword;
94 | }
95 | [self.typeNames addObject:typeName.keyword];
96 |
97 | ASTNode* nameNode = child.allChilds[1];
98 | ASTVariable* argument = [[ASTVariable alloc]init];
99 | argument.name = nameNode.value; //variable name
100 | argument.type = node.type;
101 | argument.keyword = node.keyword;
102 | argument.hasBlock = node.hasBlock;
103 | argument.hasPointer = node.hasPointer;
104 | [self.arguments addObject:argument];
105 | }
106 | }
107 | }
108 |
109 | [self scanAllVariable:self];
110 |
111 | OCBlockWrapper* wrapper = [OCBlockWrapper blockWrapperWithNode:self];
112 | self.blockPtr = (__bridge id)([wrapper blockPtr]);
113 |
114 | ASTVariable* result = [[ASTVariable alloc]init];
115 | result.value = self.blockPtr;
116 | result.type = ASTNodeTypeBlock;
117 |
118 | return result;
119 | }
120 |
121 | - (void)scanAllVariable:(ASTNode*)node
122 | {
123 | for(ASTNode* child in node.allChilds)
124 | {
125 | [self addNodeToContext:child];
126 | [self scanAllVariable:child];
127 | }
128 |
129 | if([node.value isKindOfClass:ASTNode.class]
130 | && node.value != nil)
131 | {
132 | ASTNode* child = node.value;
133 |
134 | [self addNodeToContext:child];
135 | [self scanAllVariable:child];
136 | }
137 | }
138 |
139 | - (void)addNodeToContext:(ASTNode*)node
140 | {
141 | if(node.type == ASTNodeTypeVariable)
142 | {
143 | if([self.context isKnownKey:node.value])
144 | {
145 | ASTVariable* value = [self.context fetchValueFromKey:node.value];
146 |
147 | ASTVariable* realResult = value;
148 | if(!value.hasBlock)
149 | {
150 | realResult = [[ASTVariable alloc]init];
151 | realResult.type = value.type;
152 | realResult.name = value.name;
153 | realResult.value = value.value;
154 | realResult.keyword = value.keyword;
155 | realResult.hasBlock = value.hasBlock;
156 | realResult.hasPointer = value.hasPointer;
157 | realResult.jumpType = value.jumpType;
158 | }
159 |
160 | [self.blockContext setValue:realResult forKey:node.value];
161 | }
162 | }
163 | }
164 |
165 | - (NSMutableArray*)typeNames
166 | {
167 | if(!_typeNames)
168 | {
169 | _typeNames = [NSMutableArray array];
170 | }
171 | return _typeNames;
172 | }
173 |
174 | - (NSMutableArray*)arguments
175 | {
176 | if(!_arguments)
177 | {
178 | _arguments = [NSMutableArray array];
179 | }
180 | return _arguments;
181 | }
182 |
183 | - (NSMutableDictionary *)blockContext
184 | {
185 | if(!_blockContext)
186 | {
187 | _blockContext = [NSMutableDictionary dictionary];
188 | }
189 |
190 | return _blockContext;
191 | }
192 |
193 | @end
194 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTCallMethod.h:
--------------------------------------------------------------------------------
1 | //
2 | // ASTCallMethod.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/19.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ASTCallMethod : NSObject
12 |
13 | + (id)nilObj;
14 |
15 | + (id)invokeWithCaller:(id)caller selectorName:(NSString *)selectorName argments:(NSArray *)arguments;
16 | + (id)invokeWithInvocation:(NSInvocation *)invocation argments:(NSArray *)arguments;
17 |
18 | @end
19 |
20 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTContext.h:
--------------------------------------------------------------------------------
1 | //
2 | // ASTContext.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/19.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ASTContext : NSObject
12 |
13 | - (void)pushValue:(id)value forKey:(NSString*)key;
14 | - (id)fetchValueFromKey:(NSString*)key;
15 |
16 | - (void)pushContext;
17 | - (void)pushDefinedContext:(NSMutableDictionary*)ctx;
18 | - (void)popContext;
19 | - (void)clearAllContexts;
20 |
21 | - (BOOL)isKnownKey:(NSString*)key;
22 | - (BOOL)isKnownKey:(NSString*)key At:(NSMutableDictionary*)ctx;
23 |
24 | @end
25 |
26 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTContext.m:
--------------------------------------------------------------------------------
1 | //
2 | // ASTContext.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/19.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ASTContext.h"
10 |
11 | #import "ASTCallMethod.h"
12 | #import "ASTVariable.h"
13 |
14 | @interface ASTContext()
15 | @property(nonatomic,strong) NSMutableArray* contexts;
16 | @property(nonatomic,strong) NSMutableDictionary* currentCtx;
17 | @end
18 |
19 | @implementation ASTContext
20 |
21 | - (void)pushValue:(id)value forKey:(NSString*)key
22 | {
23 | if(!self.currentCtx)
24 | {
25 | [self pushContext];
26 | }
27 |
28 | if(value == nil)
29 | {
30 | value = [ASTCallMethod nilObj];
31 | }
32 |
33 | for(int i=(int)self.contexts.count-1;i>=0;i--)
34 | {
35 | id ctx = self.contexts[i];
36 | BOOL isKnown = [self isKnownKey:key At:ctx];
37 | if(isKnown)
38 | {
39 | [ctx setValue:value forKey:key];
40 | return;
41 | }
42 | }
43 |
44 | [self.currentCtx setValue:value forKey:key];
45 | }
46 |
47 | - (id)fetchValueFromKey:(NSString*)key
48 | {
49 | ASTVariable* empty = [[ASTVariable alloc]init];
50 | empty.value = nil;
51 |
52 | if(self.contexts.count == 0) return empty;
53 |
54 | for(int i=(int)self.contexts.count-1;i>=0;i--)
55 | {
56 | id ctx = self.contexts[i];
57 | BOOL isKnown = [self isKnownKey:key At:ctx];
58 | if(isKnown)
59 | {
60 | return [ctx valueForKey:key];
61 | }
62 | }
63 |
64 | return empty;
65 | }
66 |
67 | - (BOOL)isKnownKey:(NSString*)key
68 | {
69 | __block BOOL isKnown = NO;
70 | for(int i=(int)self.contexts.count-1;i>=0;i--)
71 | {
72 | id ctx = self.contexts[i];
73 | isKnown = [self isKnownKey:key At:ctx];
74 | if(isKnown)
75 | {
76 | break;
77 | }
78 | }
79 |
80 | return isKnown;
81 | }
82 |
83 | - (BOOL)isKnownKey:(NSString*)key At:(NSMutableDictionary*)ctx
84 | {
85 | __block BOOL isKnown = NO;
86 | [ctx enumerateKeysAndObjectsUsingBlock:^(NSString* _Nonnull var, id _Nonnull obj, BOOL * _Nonnull stop) {
87 | if([var isEqualToString:key])
88 | {
89 | isKnown = YES;
90 | *stop = YES;
91 | }
92 | }];
93 |
94 | return isKnown;
95 | }
96 |
97 | - (void)pushContext
98 | {
99 | NSMutableDictionary* ctx = [NSMutableDictionary dictionary];
100 | [self.contexts addObject:ctx];
101 |
102 | self.currentCtx = ctx;
103 | }
104 |
105 | - (void)pushDefinedContext:(NSMutableDictionary*)ctx
106 | {
107 | if(!ctx) return;
108 |
109 | [self.contexts addObject:ctx];
110 | self.currentCtx = ctx;
111 | }
112 |
113 | - (void)popContext
114 | {
115 | if(!self.currentCtx) return;
116 |
117 | [self.contexts removeLastObject];
118 | self.currentCtx = [self.contexts lastObject];
119 | }
120 |
121 | - (void)clearAllContexts
122 | {
123 | self.currentCtx = nil;
124 | [self.contexts removeAllObjects];
125 | }
126 |
127 | - (NSMutableArray *)contexts
128 | {
129 | if(!_contexts)
130 | {
131 | _contexts = [NSMutableArray array];
132 | }
133 |
134 | return _contexts;
135 | }
136 |
137 | @end
138 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTHeader.h:
--------------------------------------------------------------------------------
1 | //
2 | // ASTHeader.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/14.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #ifndef ASTHeader_h
10 | #define ASTHeader_h
11 |
12 | typedef enum {
13 |
14 | ASTNodeTypePointer , //*
15 | ASTNodeTypeOCBlock , //__block
16 |
17 | ASTNodeTypeKEYWORD , //Object
18 |
19 | //basic type
20 | ASTNodeTypeChar ,
21 | ASTNodeTypeUnsignedChar ,
22 | ASTNodeTypeShort ,
23 | ASTNodeTypeUnsignedShort ,
24 | ASTNodeTypeInt ,
25 | ASTNodeTypeUnsignedInt ,
26 | ASTNodeTypeLong ,
27 | ASTNodeTypeUnsignedLong ,
28 | ASTNodeTypeFloat ,
29 | ASTNodeTypeDouble ,
30 | ASTNodeTypeBOOL ,
31 | ASTNodeTypeVoid ,
32 |
33 | ASTNodeTypeString ,
34 | ASTNodeTypeNumber ,
35 | ASTNodeTypeArray ,
36 | ASTNodeTypeDictionary ,
37 | ASTNodeTypeNil ,
38 |
39 | ASTNodeTypeScope , // {}
40 | ASTNodeTypeVariable, //
41 | ASTNodeTypeContainer, // NSArray/NSDictionary
42 | ASTNodeTypeIndex , // index for NSArray/NSDictionary
43 | ASTNodeTypeKeyValue,
44 | ASTNodeTypeDeclarator,
45 |
46 | ASTNodeTypeOperationMUL , // 'x'
47 | ASTNodeTypeOperationDIV , // '/'
48 | ASTNodeTypeOperationADD , // '+'
49 | ASTNodeTypeOperationSUB , // '-'
50 |
51 | ASTNodeTypeOperationRemainder , // '%'
52 | ASTNodeTypeOperationRightShitf , // '>>'
53 | ASTNodeTypeOperationLeftShitf , // '<<'
54 | ASTNodeTypeOperationBitAND, // &
55 | ASTNodeTypeOperationBitOR, // |
56 | ASTNodeTypeOperationBitNOT, // ^
57 |
58 |
59 | ASTNodeTypeOperationAND , // '&&'
60 | ASTNodeTypeOperationOR , // '||'
61 | ASTNodeTypeEqual , // '=='
62 | ASTNodeTypeLessEqual , // '<='
63 | ASTNodeTypeGreaterEqual , // '>='
64 | ASTNodeTypeNotEqual , // '!='
65 | ASTNodeLessThan, // '<'
66 | ASTNodeGreaterThan, // '>'
67 |
68 |
69 | ASTNodeTypeOperationPrefixInc , // '++i'
70 | ASTNodeTypeOperationPrefixDec , // '--i'
71 | ASTNodeTypeOperationPostfixInc , // 'i++'
72 | ASTNodeTypeOperationPostfixDec , // 'i--'
73 | ASTNodeTypeUnaryMinus, // '-i'
74 | ASTNodeTypeUnaryPlus, // '+i'
75 | ASTNodeTypeUnaryNot, // '!i'
76 |
77 |
78 | ASTNodeTypeOperationCondition, // ?:
79 | ASTNodeTypePlaceholder,
80 |
81 | ASTNodeTypeAssign , // '='
82 | ASTNodeTypeAddAssign , // '+='
83 | ASTNodeTypeSubAssign , // '-='
84 | ASTNodeTypeExpression,
85 | ASTNodeTypeAddressAssign , // *stop = YES;
86 |
87 | ASTNodeTypeCArugmentList ,
88 | ASTNodeTypeOCArgument,
89 | ASTNodeTypeOCArgumentList ,
90 | ASTNodeTypeUnarySelector,
91 |
92 | ASTNodeTypeBlockDeclarator,
93 | ASTNodeTypeBlockDeclareArugmentList,
94 | ASTNodeTypeBlockArugmentList,
95 | ASTNodeTypeBlock,
96 |
97 | ASTNodeTypeCallCFunction, // func();
98 | ASTNodeTypeCallOCFunction,// [self func];
99 | ASTNodeTypeProperty,
100 | ASTNodeTypePropertyList,
101 | ASTNodeTypeMemberVariables,
102 |
103 | ASTNodeTypeReturn, //return
104 | ASTNodeTypeBreak, //break
105 | ASTNodeTypeContinue, //continue
106 |
107 | ASTNodeTypeIf, //if
108 | ASTNodeTypeElse, //else
109 | ASTNodeTypeWhile, //while
110 | ASTNodeTypeDoWhile, //do while
111 | ASTNodeTypeFor, //for
112 | ASTNodeTypeCase, //case
113 | ASTNodeTypeDefault, //defaults
114 | ASTNodeTypeSwitch, //switch
115 |
116 | ASTNodeTypeProgram, // program
117 | } ASTNodeType;
118 |
119 | typedef enum {
120 | ASTJumpTypeDefault ,
121 | ASTJumpTypeReturn ,
122 | ASTJumpTypeBreak ,
123 | ASTJumpTypeContinue ,
124 | } ASTJumpType;
125 |
126 | typedef struct yy_buffer_state *YY_BUFFER_STATE;
127 | YY_BUFFER_STATE yy_scan_string(const char *s);
128 |
129 | int yyparse(void);
130 | void yy_delete_buffer(YY_BUFFER_STATE buf);
131 |
132 | #endif /* ASTHeader_h */
133 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTMethodNode.h:
--------------------------------------------------------------------------------
1 | //
2 | // ASTMethodNode.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/24.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ASTNode.h"
10 | #import "ASTHeader.h"
11 |
12 | @interface ASTMethodNode : ASTNode
13 | @property(nonatomic,copy) NSString* name;
14 | @property(nonatomic,strong) ASTNode* argument;
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTMethodNode.m:
--------------------------------------------------------------------------------
1 | //
2 | // ASTMethodNode.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/24.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ASTMethodNode.h"
10 |
11 | @implementation ASTMethodNode
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTNode.h:
--------------------------------------------------------------------------------
1 | //
2 | // ASTNode.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/11.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ASTHeader.h"
11 | #import "ASTContext.h"
12 | #import "ASTCallMethod.h"
13 |
14 | @interface ASTNode : NSObject
15 |
16 | @property(nonatomic,strong) NSMutableArray *allChilds;
17 | @property(nonatomic,assign) ASTNodeType type;
18 | @property(nonatomic,copy) NSString* keyword;
19 |
20 | @property(nonatomic,assign) BOOL hasPointer;
21 | @property(nonatomic,assign) BOOL hasBlock;
22 | @property(nonatomic,strong) id value;
23 |
24 | @property(nonatomic,strong) ASTContext* context;
25 |
26 | - (void)addChild:(ASTNode *)node;
27 | - (id)execute;
28 |
29 | - (id)handleProperty;
30 | @end
31 |
32 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTPropertyNode.h:
--------------------------------------------------------------------------------
1 | //
2 | // ASTPropertyNode.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/15.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ASTNode.h"
10 | #import "ASTHeader.h"
11 |
12 | typedef enum {
13 | ASTPropertyHandleTypeDefaultGetter = 0,
14 | ASTPropertyHandleTypeDefualtSetter,
15 | } ASTPropertyHandleType;
16 |
17 | @interface ASTPropertyNode : ASTNode
18 | @property(nonatomic,strong) ASTNode* invoker;
19 | @property(nonatomic,copy) NSString* selector; //property
20 |
21 | @property(nonatomic,assign) ASTPropertyHandleType handleType;
22 | @property(nonatomic,strong) id setterVaule;
23 |
24 |
25 | @end
26 |
27 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTPropertyNode.m:
--------------------------------------------------------------------------------
1 | //
2 | // ASTPropertyNode.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/15.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ASTPropertyNode.h"
10 | #import "ASTVariable.h"
11 | #import "ASTContext.h"
12 | #import "ASTUtil.h"
13 |
14 | @interface ASTPropertyNode ()
15 | @end
16 |
17 | @implementation ASTPropertyNode
18 |
19 | - (id)handleProperty
20 | {
21 | id invoker;
22 |
23 | for(int i=0; i= 2 && [ASTUtil checkOCStructType:result.value])
49 | {
50 | id value = result.value;
51 | for(int j=(int)self.allChilds.count-2;j>=0;j--)
52 | {
53 | ASTPropertyNode* jNode = self.allChilds[j];
54 |
55 | if(j == 0)
56 | {
57 | invoker = [self getInvoker:jNode];
58 | }
59 | else
60 | {
61 | invoker = jNode.invoker;
62 | }
63 |
64 | NSString* selectorName = [self getSelectorSetter:jNode];
65 | value = [ASTCallMethod invokeWithCaller:invoker selectorName:selectorName argments:@[value]];
66 | }
67 |
68 | result.value = value;
69 | }
70 | }
71 | else
72 | {
73 | //getter
74 | NSString* selectorName = [self getSelectorGetter:node];
75 | result.value = [ASTCallMethod invokeWithCaller:invoker selectorName:selectorName argments:@[]];
76 | }
77 |
78 | [ASTUtil castTypeFromValue:result];
79 | return result;
80 | }
81 |
82 | NSString* selectorName = [self getSelectorGetter:node];
83 | invoker = [ASTCallMethod invokeWithCaller:invoker selectorName:selectorName argments:@[]];
84 | }
85 |
86 | return nil;
87 | }
88 |
89 | - (id)getInvoker:(ASTPropertyNode*)node
90 | {
91 | id invoker;
92 | ASTVariable* var;
93 |
94 | ASTNode* invokeNode = node.invoker;
95 | if([invokeNode.value isEqualToString:@"super"])
96 | {
97 | //super
98 | ASTVariable* varSelf = [self.context fetchValueFromKey:@"self"];
99 | id obj = varSelf.value;
100 |
101 | invoker = obj;
102 | }
103 | else if(invokeNode.type == ASTNodeTypeVariable)
104 | {
105 | //self/variable
106 | var = [self.context fetchValueFromKey:invokeNode.value];
107 | invoker = var.value;
108 | }
109 | else if(invokeNode.type == ASTNodeTypeKEYWORD)
110 | {
111 | //keyword
112 | invoker = NSClassFromString(invokeNode.keyword);
113 | }
114 | else
115 | {
116 | var = [invokeNode execute];
117 | invoker = var.value;
118 | }
119 |
120 | return invoker;
121 | }
122 |
123 | - (NSString*)getSelectorSetter:(ASTPropertyNode*)node
124 | {
125 | NSString* selectorName = node.selector;
126 | NSString* headStr = [selectorName substringToIndex:1];
127 | selectorName = [NSString stringWithFormat:@"set%@%@:",headStr.uppercaseString, [selectorName substringFromIndex:1]];
128 |
129 | return selectorName;
130 | }
131 |
132 | - (NSString*)getSelectorGetter:(ASTPropertyNode*)node
133 | {
134 | return node.selector;
135 | }
136 |
137 |
138 | @end
139 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTType.h:
--------------------------------------------------------------------------------
1 | //
2 | // ASTType.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/27.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ASTHeader.h"
11 |
12 | @interface ASTType : NSObject
13 | @property (nonatomic,assign) ASTNodeType type;
14 | @property (nonatomic,copy) NSString* keyword;
15 | @property (nonatomic,copy) NSString* typeEncode;
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTType.m:
--------------------------------------------------------------------------------
1 | //
2 | // ASTType.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/27.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ASTType.h"
10 |
11 | @implementation ASTType
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTUtil.h:
--------------------------------------------------------------------------------
1 | //
2 | // ASTUtil.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/14.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | #import "ASTNode.h"
13 | #import "ASTHeader.h"
14 |
15 | #import "ASTVariable.h"
16 |
17 | #import "ASTPropertyNode.h"
18 | #import "ASTMethodNode.h"
19 | @class ASTType;
20 |
21 | extern ASTNode* gblRootNode;
22 | extern NSMutableDictionary* gblVariables;
23 |
24 | @interface ASTUtil : NSObject
25 |
26 | + (ASTNode*) int_node:(int)value;
27 | + (ASTNode*) double_node:(double)value;
28 | + (ASTNode*) string_node:(NSString*)value;
29 | + (ASTNode*) bool_node:(BOOL)value;
30 | + (ASTNode*) keyword_node:(NSString*)value;
31 | + (ASTNode*) variable_node:(NSString*)value;
32 | + (ASTNode*) placeholder_node;
33 |
34 | + (ASTNode*) op_node:(ASTNodeType)type;
35 | + (ASTPropertyNode*) property_node;
36 | + (ASTNode*) unarySelector_node:(NSString*)value;
37 |
38 | + (void)castTypeFromValue:(ASTVariable*)objc;
39 |
40 | +(BOOL)checkOCStructType:(id)objc;
41 | +(void)defaultValueForOCStruct:(ASTVariable*)variable;
42 |
43 | +(BOOL)checkOCContainerIndexType:(ASTNodeType)type;
44 | +(BOOL)callCFunctionWhitelist:(NSString*)func;
45 |
46 |
47 | +(ASTNode*)parseString:(NSString*)text;
48 |
49 | + (ASTType*)typeForNodeType:(ASTNodeType)type keyword:(NSString*)keyword;
50 | + (ASTContext*)linkContextToRoot:(ASTNode*)rootNode;
51 | + (void)registerVariableForYacc:(NSString*)key;
52 | @end
53 |
54 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTUtil.m:
--------------------------------------------------------------------------------
1 | //
2 | // ASTUtil.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/14.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ASTUtil.h"
10 | #import "ASTType.h"
11 |
12 | ASTNode* gblRootNode = nil;
13 | NSMutableDictionary* gblVariables = nil;
14 |
15 | @interface ASTUtil()
16 |
17 | @end
18 |
19 | @implementation ASTUtil
20 |
21 | + (void)load
22 | {
23 | if(!gblVariables)
24 | {
25 | gblVariables = [NSMutableDictionary dictionary];
26 | }
27 |
28 | //self/super initial as variable
29 | [gblVariables setObject:@"" forKey:@"self"];
30 | [gblVariables setObject:@"" forKey:@"super"];
31 | }
32 |
33 | + (ASTNode*)int_node:(int)value
34 | {
35 | ASTNode* node = [[ASTNode alloc]init];
36 | node.type = ASTNodeTypeInt;
37 | node.value = @(value);
38 | return node;
39 | }
40 |
41 | + (ASTNode*)double_node:(double)value
42 | {
43 | ASTNode* node = [[ASTNode alloc]init];
44 | node.type = ASTNodeTypeDouble;
45 | node.value = @(value);
46 | return node;
47 | }
48 |
49 | + (ASTNode*)string_node:(NSString*)value
50 | {
51 | ASTNode* node = [[ASTNode alloc]init];
52 | node.type = ASTNodeTypeString;
53 | node.value = value;
54 | return node;
55 | }
56 |
57 | + (ASTNode*)bool_node:(BOOL)value
58 | {
59 | ASTNode* node = [[ASTNode alloc]init];
60 | node.type = ASTNodeTypeBOOL;
61 | node.value = @(value);
62 | return node;
63 | }
64 |
65 | + (ASTNode*) keyword_node:(NSString*)value
66 | {
67 | ASTNode* node = [[ASTNode alloc]init];
68 | node.type = ASTNodeTypeKEYWORD;
69 | node.keyword = value;
70 | return node;
71 | }
72 |
73 | + (ASTNode*)variable_node:(NSString*)value
74 | {
75 | ASTNode* node = [[ASTNode alloc]init];
76 | node.type = ASTNodeTypeVariable;
77 | node.value = value;
78 | return node;
79 | }
80 |
81 | + (ASTNode*) op_node:(ASTNodeType)type
82 | {
83 | ASTNode* node = [[ASTNode alloc]init];
84 | node.type = type;
85 | return node;
86 | }
87 |
88 | + (ASTPropertyNode*)property_node
89 | {
90 | ASTPropertyNode* node = [[ASTPropertyNode alloc]init];
91 | node.type = ASTNodeTypeProperty;
92 | return node;
93 | }
94 |
95 | + (ASTNode*)unarySelector_node:(NSString*)value
96 | {
97 | ASTNode* node = [[ASTNode alloc]init];
98 | node.type = ASTNodeTypeUnarySelector;
99 | node.value = value;
100 | return node;
101 | }
102 |
103 | + (ASTNode*)placeholder_node
104 | {
105 | ASTNode* node = [[ASTNode alloc]init];
106 | node.type = ASTNodeTypePlaceholder;
107 |
108 | return node;
109 | }
110 |
111 |
112 | +(NSString*)nodeKey:(ASTNodeType)type keyword:(NSString*)keyword
113 | {
114 | if(type != ASTNodeTypeKEYWORD) keyword = nil;
115 | if(keyword == nil) keyword = @"";
116 |
117 | NSString* key = [NSString stringWithFormat:@"%d##%@",type,keyword];
118 | return key;
119 | }
120 |
121 | //https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
122 | + (void)castTypeFromValue:(ASTVariable*)objc
123 | {
124 | if(![objc.value respondsToSelector:@selector(objCType)])
125 | {
126 | return;
127 | }
128 |
129 | const char* c = [objc.value objCType];
130 |
131 | #define DC_CAST_TYPE(_val, _typeString, _nodeType, _keyword) \
132 | if(strcmp(_typeString, _val) == 0) { \
133 | objc.type = _nodeType; \
134 | objc.keyword = _keyword;\
135 | return;\
136 | }
137 |
138 | DC_CAST_TYPE(c, @encode(char), ASTNodeTypeChar, nil)
139 | DC_CAST_TYPE(c, @encode(unsigned char), ASTNodeTypeUnsignedChar, nil)
140 | DC_CAST_TYPE(c, @encode(short), ASTNodeTypeShort, nil)
141 | DC_CAST_TYPE(c, @encode(unsigned short), ASTNodeTypeUnsignedShort, nil)
142 | DC_CAST_TYPE(c, @encode(int), ASTNodeTypeInt, nil)
143 | DC_CAST_TYPE(c, @encode(unsigned int), ASTNodeTypeUnsignedInt, nil)
144 | DC_CAST_TYPE(c, @encode(long), ASTNodeTypeLong, nil)
145 | DC_CAST_TYPE(c, @encode(unsigned long), ASTNodeTypeUnsignedLong, nil)
146 | DC_CAST_TYPE(c, @encode(float), ASTNodeTypeFloat, nil)
147 | DC_CAST_TYPE(c, @encode(double), ASTNodeTypeDouble, nil)
148 | DC_CAST_TYPE(c, @encode(BOOL), ASTNodeTypeBOOL, nil)
149 | DC_CAST_TYPE(c, @encode(void), ASTNodeTypeVoid, nil)
150 | DC_CAST_TYPE(c, @encode(CGFloat), ASTNodeTypeFloat, nil)
151 | DC_CAST_TYPE(c, @encode(void), ASTNodeTypeVoid, nil)
152 | DC_CAST_TYPE(c, @encode(id), ASTNodeTypeKEYWORD, @"id")
153 | DC_CAST_TYPE(c, @encode(size_t), ASTNodeTypeKEYWORD, @"size_t")
154 | DC_CAST_TYPE(c, @encode(CGSize), ASTNodeTypeKEYWORD, @"CGSize")
155 | DC_CAST_TYPE(c, @encode(CGRect), ASTNodeTypeKEYWORD, @"CGRect")
156 | DC_CAST_TYPE(c, @encode(CGPoint), ASTNodeTypeKEYWORD, @"CGPoint")
157 | DC_CAST_TYPE(c, @encode(NSRange), ASTNodeTypeKEYWORD, @"NSRange")
158 | DC_CAST_TYPE(c, @encode(CGVector), ASTNodeTypeKEYWORD, @"CGVector")
159 | DC_CAST_TYPE(c, @encode(Class), ASTNodeTypeKEYWORD, @"Class")
160 | DC_CAST_TYPE(c, @encode(SEL), ASTNodeTypeKEYWORD, @"SEL")
161 | DC_CAST_TYPE(c, @encode(void*), ASTNodeTypeKEYWORD, @"void*")
162 | }
163 |
164 | +(BOOL)checkOCStructType:(id)objc
165 | {
166 | if(![objc respondsToSelector:@selector(objCType)])
167 | {
168 | return NO;
169 | }
170 |
171 | const char* c = [objc objCType];
172 |
173 | #define DC_CHECK_STRUCT_TYPE(_val, _typeString) \
174 | if(strcmp(_typeString, _val) == 0) { \
175 | return YES; \
176 | }
177 |
178 | DC_CHECK_STRUCT_TYPE(c, @encode(CGSize))
179 | DC_CHECK_STRUCT_TYPE(c, @encode(CGRect))
180 | DC_CHECK_STRUCT_TYPE(c, @encode(CGPoint))
181 | DC_CHECK_STRUCT_TYPE(c, @encode(CGVector))
182 | DC_CHECK_STRUCT_TYPE(c, @encode(NSRange))
183 | DC_CHECK_STRUCT_TYPE(c, @encode(UIEdgeInsets))
184 | DC_CHECK_STRUCT_TYPE(c, @encode(UIOffset))
185 | DC_CHECK_STRUCT_TYPE(c, @encode(CGAffineTransform))
186 |
187 | return NO;
188 | }
189 |
190 | +(void)defaultValueForOCStruct:(ASTVariable*)variable
191 | {
192 | if(variable.type != ASTNodeTypeKEYWORD || ![ASTUtil checkOCStructType:variable.value]) return;
193 |
194 | #define DC_OCSTRUCT_DEFAULT(_type, _caller, _default) \
195 | if ([_type isEqualToString:_caller.keyword]){ \
196 | _caller.value = (_default);\
197 | [ASTUtil castTypeFromValue:_caller];\
198 | return; \
199 | }
200 |
201 | DC_OCSTRUCT_DEFAULT(@"CGSize", variable, @(CGSizeZero))
202 | DC_OCSTRUCT_DEFAULT(@"CGRect", variable, @(CGRectZero))
203 | DC_OCSTRUCT_DEFAULT(@"CGPoint", variable, @(CGSizeZero))
204 | DC_OCSTRUCT_DEFAULT(@"CGVector",variable, @(CGVectorMake(0, 0)))
205 |
206 | DC_OCSTRUCT_DEFAULT(@"UIEdgeInsets", variable, [NSValue valueWithUIEdgeInsets:UIEdgeInsetsZero])
207 | DC_OCSTRUCT_DEFAULT(@"NSRange", variable, [NSValue valueWithRange:NSMakeRange(0, 0)])
208 | DC_OCSTRUCT_DEFAULT(@"UIOffset", variable, [NSValue valueWithUIOffset:UIOffsetMake(0, 0)])
209 | DC_OCSTRUCT_DEFAULT(@"CGAffineTransform", variable, [NSValue valueWithCGAffineTransform:CGAffineTransformIdentity])
210 | }
211 |
212 | +(BOOL)checkOCContainerIndexType:(ASTNodeType)type
213 | {
214 | if(type >= ASTNodeTypeShort && type <= ASTNodeTypeUnsignedLong)
215 | {
216 | //array
217 | return YES;
218 | }
219 |
220 | //dictionary
221 | return NO;
222 | }
223 |
224 | +(BOOL)callCFunctionWhitelist:(NSString*)func
225 | {
226 | static NSMutableArray* whitelist = nil;
227 | if(!whitelist)
228 | {
229 | whitelist = [NSMutableArray array];
230 |
231 | [whitelist addObject:@"CGRectZero"];
232 | [whitelist addObject:@"CGPointZero"];
233 | [whitelist addObject:@"CGSizeZero"];
234 | [whitelist addObject:@"UIEdgeInsetsZero"];
235 | [whitelist addObject:@"dispatch_after"];
236 | }
237 |
238 | if([whitelist containsObject:func]) return YES;
239 |
240 | return NO;
241 | }
242 |
243 | static NSMutableDictionary* _typeEncodeDict = nil;
244 | + (ASTType*)typeForNodeType:(ASTNodeType)type keyword:(NSString*)keyword
245 | {
246 | if(!_typeEncodeDict)
247 | {
248 | _typeEncodeDict = [NSMutableDictionary dictionary];
249 |
250 |
251 | #define DC_TYPE_MAP_NODETYPE(_nodeType, _type, _typeString) { \
252 | ASTType* ast_ = [[ASTType alloc]init]; \
253 | ast_.type = _nodeType; \
254 | ast_.keyword = _typeString; \
255 | ast_.typeEncode = [NSString stringWithUTF8String:@encode(_type)]; \
256 | NSString* key_ = [ASTUtil nodeKey:_nodeType keyword:ast_.keyword]; \
257 | [_typeEncodeDict setObject:ast_ forKey:key_]; }
258 |
259 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeChar, char, @"char")
260 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeUnsignedChar,unsigned char, @"unsigned char")
261 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeShort, short, @"short")
262 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeUnsignedShort, unsigned short, @"unsigned char")
263 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeInt, int, @"int")
264 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeUnsignedInt, unsigned int, @"unsigned int")
265 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeLong, long, @"long")
266 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeUnsignedLong, unsigned long, @"unsigned long")
267 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeFloat, float, @"float")
268 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeDouble, double, @"double")
269 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeBOOL, BOOL, @"BOOL")
270 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeVoid, void, @"void")
271 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeKEYWORD, id, @"id")
272 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeKEYWORD, size_t, @"size_t")
273 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeKEYWORD, CGSize, @"CGSize")
274 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeKEYWORD, CGRect, @"CGRect")
275 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeKEYWORD, CGPoint, @"CGPoint")
276 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeKEYWORD, CGVector, @"CGVector")
277 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeKEYWORD, NSRange, @"NSRange")
278 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeKEYWORD, Class, @"Class")
279 | DC_TYPE_MAP_NODETYPE(ASTNodeTypeKEYWORD, SEL, @"SEL")
280 | }
281 |
282 | NSString* key = [ASTUtil nodeKey:type keyword:keyword];
283 |
284 | return _typeEncodeDict[key];
285 | }
286 |
287 | + (ASTContext*)linkContextToRoot:(ASTNode*)rootNode
288 | {
289 | rootNode.context = [ASTContext new];
290 | [ASTUtil linkAllContext:rootNode ctx:rootNode.context];
291 | return rootNode.context;
292 | }
293 |
294 | + (void)linkAllContext:(ASTNode*)root ctx:(ASTContext*)context
295 | {
296 | for(ASTNode* node in root.allChilds)
297 | {
298 | node.context = context;
299 | [ASTUtil linkAllContext:node ctx:context];
300 | }
301 |
302 | if(root.value != nil && [root.value isKindOfClass:ASTNode.class])
303 | {
304 | ASTNode* node = root.value;
305 | node.context = context;
306 | [ASTUtil linkAllContext:node ctx:context];
307 | }
308 |
309 | if([root isMemberOfClass:ASTPropertyNode.class])
310 | {
311 | ASTPropertyNode* propertyNode = (ASTPropertyNode*)root;
312 | ASTNode* node = propertyNode.invoker;
313 | node.context = context;
314 | [ASTUtil linkAllContext:node ctx:context];
315 | }
316 |
317 | if([root isMemberOfClass:ASTMethodNode.class])
318 | {
319 | ASTMethodNode* methodNode = (ASTMethodNode*)root;
320 | ASTNode* node = methodNode.argument;
321 | node.context = context;
322 | [ASTUtil linkAllContext:node ctx:context];
323 | }
324 | }
325 |
326 | + (void)registerVariableForYacc:(NSString*)key
327 | {
328 | if(!gblVariables)
329 | {
330 | gblVariables = [NSMutableDictionary dictionary];
331 | }
332 |
333 | [gblVariables setValue:@"" forKey:key];
334 | }
335 |
336 | +(ASTNode*)parseString:(NSString*)text
337 | {
338 | gblRootNode = nil;
339 |
340 | YY_BUFFER_STATE buf;
341 | buf = yy_scan_string([text cStringUsingEncoding:NSUTF8StringEncoding]);
342 | yyparse();
343 | yy_delete_buffer(buf);
344 |
345 | [ASTUtil linkContextToRoot:gblRootNode];
346 |
347 | return gblRootNode;
348 | }
349 |
350 |
351 | @end
352 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTVariable.h:
--------------------------------------------------------------------------------
1 | //
2 | // ASTVariable.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/21.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ASTHeader.h"
11 |
12 | @interface ASTVariable : NSObject
13 | @property(nonatomic,assign) ASTNodeType type;
14 | @property(nonatomic,strong) id name;
15 | @property(nonatomic,strong) id value;
16 |
17 | // ASTNodeTypeKeyword value
18 | @property(nonatomic,copy) NSString* keyword;
19 | @property(nonatomic,assign) BOOL hasPointer;
20 | @property(nonatomic,assign) BOOL hasBlock;
21 |
22 | // for i++/i--
23 | @property(nonatomic,copy) void (^postOperation)(void);
24 |
25 | // for return/continue/break
26 | @property(nonatomic,assign) ASTJumpType jumpType;
27 |
28 | - (instancetype)toMutableCopy;
29 | @end
30 |
31 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/ASTVariable.m:
--------------------------------------------------------------------------------
1 | //
2 | // ASTVariable.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/21.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ASTVariable.h"
10 |
11 | @implementation ASTVariable
12 |
13 | - (instancetype)toMutableCopy
14 | {
15 | ASTVariable* result = [[ASTVariable alloc]init];
16 | result.type = self.type;
17 | result.name = self.name;
18 | result.value = self.value;
19 | result.keyword = self.keyword;
20 | result.hasPointer = self.hasPointer;
21 | result.hasBlock = self.hasBlock;
22 |
23 | result.postOperation = self.postOperation;
24 | result.jumpType = self.jumpType;
25 |
26 | return result;
27 | }
28 |
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/DynamicOC.h:
--------------------------------------------------------------------------------
1 | //
2 | // DynamicOC.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/29.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface DynamicOC : NSObject
12 |
13 | + (void)hookClass:(NSString *)clsName
14 | selector:(NSString *)selName
15 | argNames:(NSArray<__kindof NSString *> *)argNames //original parameters variable name
16 | isClass:(BOOL)isClass //hook class method or instance method
17 | implementation:(NSString *)imp;
18 |
19 | @end
20 |
21 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/DynamicOC.m:
--------------------------------------------------------------------------------
1 | //
2 | // DynamicOC.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/29.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "DynamicOC.h"
10 |
11 | #import "Aspects.h"
12 | #import
13 |
14 | #import "ASTUtil.h"
15 | #import "ASTHeader.h"
16 | #import "ASTContext.h"
17 | #import "OCCfuntionHelper.h"
18 | #import "ASTCallMethod.h"
19 |
20 | extern NSMutableDictionary* gblVariables;
21 |
22 | @implementation DynamicOC
23 |
24 | + (void)hookClass:(NSString *)clsName
25 | selector:(NSString *)selName
26 | argNames:(NSArray<__kindof NSString *> *)argNames
27 | isClass:(BOOL)isClass
28 | implementation:(NSString *)imp
29 | {
30 | Class class = NSClassFromString(clsName);
31 | SEL selector = NSSelectorFromString(selName);
32 |
33 | if (isClass) {
34 | class = objc_getMetaClass([NSStringFromClass(class) UTF8String]);
35 | }
36 |
37 | //register variable for yacc
38 | [ASTUtil registerVariableForYacc:@"self"];
39 | [ASTUtil registerVariableForYacc:@"super"];
40 | [ASTUtil registerVariableForYacc:@"originalInvocation"];
41 | for(NSString* name in argNames)
42 | {
43 | [ASTUtil registerVariableForYacc:name];
44 | }
45 |
46 | ASTNode* rootNode = [ASTUtil parseString:imp];
47 |
48 | NSError *error;
49 | [class aspect_hookSelector:selector withOptions:AspectPositionInstead usingBlock:^(id aspectInfo) {
50 |
51 | ASTVariable* varSelf = [[ASTVariable alloc]init];
52 | varSelf.value = aspectInfo.instance;
53 | varSelf.type = ASTNodeTypeVariable;
54 | [rootNode.context pushValue:varSelf forKey:@"self"];
55 |
56 | ASTVariable* varOriginInvocation = [[ASTVariable alloc]init];
57 | varOriginInvocation.value = aspectInfo.originalInvocation;
58 | varOriginInvocation.type = ASTNodeTypeKEYWORD;
59 | varOriginInvocation.keyword = @"NSInvocation";
60 | [rootNode.context pushValue:varOriginInvocation forKey:@"originalInvocation"];
61 |
62 | NSAssert(aspectInfo.arguments.count == argNames.count, @"Error: Method params count must be same.");
63 | [aspectInfo.arguments enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
64 | NSString *name = argNames[idx];
65 |
66 | ASTVariable* objVar = [[ASTVariable alloc]init];
67 |
68 | NSString* keyword;
69 | if([obj isKindOfClass:NSObject.class])
70 | {
71 | NSObject* clsObj = obj;
72 | keyword = NSStringFromClass(clsObj.class);
73 |
74 | objVar.type = ASTNodeTypeKEYWORD;
75 | objVar.keyword = keyword;
76 | }
77 | else
78 | {
79 | objVar.type = ASTNodeTypeVariable;
80 | }
81 |
82 | objVar.value = obj;
83 | [rootNode.context pushValue:objVar forKey:name];
84 | }];
85 |
86 | ASTVariable* var = [rootNode execute];
87 | id result = var.value;
88 |
89 | const char *argumentType = aspectInfo.originalInvocation.methodSignature.methodReturnType;
90 |
91 | switch (argumentType[0] == 'r' ? argumentType[1] : argumentType[0]) {
92 |
93 | #define OC_CALL_ARG_CASE(_typeString, _type, _selector) \
94 | case _typeString: { \
95 | _type value = [result _selector]; \
96 | [aspectInfo.originalInvocation setReturnValue:&value];\
97 | break; \
98 | }
99 | OC_CALL_ARG_CASE('c', char, charValue)
100 | OC_CALL_ARG_CASE('C', unsigned char, unsignedCharValue)
101 | OC_CALL_ARG_CASE('s', short, shortValue)
102 | OC_CALL_ARG_CASE('S', unsigned short, unsignedShortValue)
103 | OC_CALL_ARG_CASE('i', int, intValue)
104 | OC_CALL_ARG_CASE('I', unsigned int, unsignedIntValue)
105 | OC_CALL_ARG_CASE('l', long, longValue)
106 | OC_CALL_ARG_CASE('L', unsigned long, unsignedLongValue)
107 | OC_CALL_ARG_CASE('q', long long, longLongValue)
108 | OC_CALL_ARG_CASE('Q', unsigned long long, unsignedLongLongValue)
109 | OC_CALL_ARG_CASE('f', float, floatValue)
110 | OC_CALL_ARG_CASE('d', double, doubleValue)
111 | OC_CALL_ARG_CASE('B', BOOL, boolValue)
112 |
113 | case ':': {
114 | SEL value = nil;
115 | if (result != [ASTCallMethod nilObj]) {
116 | value = NSSelectorFromString(result);
117 | }
118 | [aspectInfo.originalInvocation setReturnValue:&value];
119 | break;
120 | }
121 | case '{': {
122 | void *pointer = NULL;
123 | [result getValue:&pointer];
124 | [aspectInfo.originalInvocation setReturnValue:&pointer];
125 | break;
126 | }
127 | default: {
128 | if (result == [ASTCallMethod nilObj] ||
129 | ([result isKindOfClass:[NSNumber class]] && strcmp([result objCType], "c") == 0 && ![result boolValue])) {
130 | result = nil;
131 | [aspectInfo.originalInvocation setReturnValue:&result];
132 | break;
133 | }
134 | if (result) {
135 | [aspectInfo.originalInvocation setReturnValue:&result];
136 | }
137 | }
138 | }
139 |
140 | } error:&error];
141 | }
142 |
143 | @end
144 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/OCBlockWrapper.h:
--------------------------------------------------------------------------------
1 | //
2 | // JPBlockWrapper.h
3 | // JSPatch
4 | //
5 | // Created by bang on 1/19/17.
6 | // Copyright © 2017 bang. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ASTNode.h"
11 | #import "ASTBlockNode.h"
12 |
13 | @interface OCBlockWrapper : NSObject
14 |
15 | + (instancetype)blockWrapperWithNode:(ASTBlockNode *)node;
16 | - (void *)blockPtr;
17 | + (id)excuteBlock:(id)block withParams:(NSArray *)params;
18 | @end
19 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Class/OCBlockWrapper.m:
--------------------------------------------------------------------------------
1 | //
2 | // JPBlockWrapper.m
3 | // JSPatch
4 | //
5 | // Created by bang on 1/19/17.
6 | // Copyright © 2017 bang. All rights reserved.
7 | //
8 |
9 | #import "OCBlockWrapper.h"
10 | #import "ffi.h"
11 | #import "OCMethodSignature.h"
12 | #import "ASTCallMethod.h"
13 | #import "ASTVariable.h"
14 | #import "ASTContext.h"
15 |
16 | enum {
17 | BLOCK_DEALLOCATING = (0x0001),
18 | BLOCK_REFCOUNT_MASK = (0xfffe),
19 | BLOCK_NEEDS_FREE = (1 << 24),
20 | BLOCK_HAS_COPY_DISPOSE = (1 << 25),
21 | BLOCK_HAS_CTOR = (1 << 26),
22 | BLOCK_IS_GC = (1 << 27),
23 | BLOCK_IS_GLOBAL = (1 << 28),
24 | BLOCK_USE_STRET = (1 << 29),
25 | BLOCK_HAS_SIGNATURE = (1 << 30)
26 | };
27 |
28 | struct JPSimulateBlock {
29 | void *isa;
30 | int flags;
31 | int reserved;
32 | void *invoke;
33 | struct JPSimulateBlockDescriptor *descriptor;
34 | void *wrapper;
35 | };
36 |
37 | struct JPSimulateBlockDescriptor {
38 | //Block_descriptor_1
39 | struct {
40 | unsigned long int reserved;
41 | unsigned long int size;
42 | };
43 |
44 | //Block_descriptor_2
45 | struct {
46 | // requires BLOCK_HAS_COPY_DISPOSE
47 | void (*copy)(void *dst, const void *src);
48 | void (*dispose)(const void *);
49 | };
50 |
51 | //Block_descriptor_3
52 | struct {
53 | // requires BLOCK_HAS_SIGNATURE
54 | const char *signature;
55 | };
56 | };
57 |
58 | void copy_helper(struct JPSimulateBlock *dst, struct JPSimulateBlock *src)
59 | {
60 | // do not copy anything is this funcion! just retain if need.
61 | CFRetain(dst->wrapper);
62 | }
63 |
64 | void dispose_helper(struct JPSimulateBlock *src)
65 | {
66 | CFRelease(src->wrapper);
67 | }
68 |
69 |
70 | @interface OCBlockWrapper ()
71 | {
72 | ffi_cif *_cifPtr;
73 | ffi_type **_args;
74 | ffi_closure *_closure;
75 | BOOL _generatedPtr;
76 | void *_blockPtr;
77 | struct JPSimulateBlockDescriptor *_descriptor;
78 | }
79 |
80 | @property (nonatomic,strong) OCMethodSignature *signature;
81 | @property (nonatomic,strong) ASTBlockNode *node;
82 | @property (nonatomic,strong) NSMutableDictionary *blockContext;
83 |
84 | @end
85 |
86 | void JPBlockInterpreter(ffi_cif *cif, void *ret, void **args, void *userdata)
87 | {
88 | OCBlockWrapper *blockObj = (__bridge OCBlockWrapper*)userdata;
89 |
90 | [blockObj.node.context pushDefinedContext:blockObj.blockContext];
91 |
92 | for (int i = 1; i < blockObj.signature.argumentTypes.count; i ++) {
93 | id param;
94 | void *argumentPtr = args[i];
95 | const char *typeEncoding = [blockObj.signature.argumentTypes[i] UTF8String];
96 | switch (typeEncoding[0]) {
97 |
98 | #define JP_BLOCK_PARAM_CASE(_typeString, _type, _selector) \
99 | case _typeString: { \
100 | _type returnValue = *(_type *)argumentPtr; \
101 | param = [NSNumber _selector:returnValue];\
102 | break; \
103 | }
104 | JP_BLOCK_PARAM_CASE('c', char, numberWithChar)
105 | JP_BLOCK_PARAM_CASE('C', unsigned char, numberWithUnsignedChar)
106 | JP_BLOCK_PARAM_CASE('s', short, numberWithShort)
107 | JP_BLOCK_PARAM_CASE('S', unsigned short, numberWithUnsignedShort)
108 | JP_BLOCK_PARAM_CASE('i', int, numberWithInt)
109 | JP_BLOCK_PARAM_CASE('I', unsigned int, numberWithUnsignedInt)
110 | JP_BLOCK_PARAM_CASE('l', long, numberWithLong)
111 | JP_BLOCK_PARAM_CASE('L', unsigned long, numberWithUnsignedLong)
112 | JP_BLOCK_PARAM_CASE('q', long long, numberWithLongLong)
113 | JP_BLOCK_PARAM_CASE('Q', unsigned long long, numberWithUnsignedLongLong)
114 | JP_BLOCK_PARAM_CASE('f', float, numberWithFloat)
115 | JP_BLOCK_PARAM_CASE('d', double, numberWithDouble)
116 | JP_BLOCK_PARAM_CASE('B', BOOL, numberWithBool)
117 |
118 | case '@': {
119 | param = (__bridge id)(*(void**)argumentPtr);
120 | break;
121 | }
122 | }
123 |
124 | ASTVariable* var = blockObj.node.arguments[i-1];
125 | NSString* key = var.name;
126 | var.value = param;
127 |
128 | [blockObj.node.context pushValue:var forKey:key];
129 | }
130 |
131 | ASTNode* scopeNode = blockObj.node.allChilds[2];
132 | ASTVariable* var = [scopeNode execute];
133 | id result = var.value;
134 |
135 | [blockObj.node.context popContext];
136 |
137 | switch ([blockObj.signature.returnType UTF8String][0]) {
138 |
139 | #define JP_BLOCK_RET_CASE(_typeString, _type, _selector) \
140 | case _typeString: { \
141 | _type *retPtr = ret; \
142 | *retPtr = [(NSNumber *)result _selector]; \
143 | break; \
144 | }
145 |
146 | JP_BLOCK_RET_CASE('c', char, charValue)
147 | JP_BLOCK_RET_CASE('C', unsigned char, unsignedCharValue)
148 | JP_BLOCK_RET_CASE('s', short, shortValue)
149 | JP_BLOCK_RET_CASE('S', unsigned short, unsignedShortValue)
150 | JP_BLOCK_RET_CASE('i', int, intValue)
151 | JP_BLOCK_RET_CASE('I', unsigned int, unsignedIntValue)
152 | JP_BLOCK_RET_CASE('l', long, longValue)
153 | JP_BLOCK_RET_CASE('L', unsigned long, unsignedLongValue)
154 | JP_BLOCK_RET_CASE('q', long long, longLongValue)
155 | JP_BLOCK_RET_CASE('Q', unsigned long long, unsignedLongLongValue)
156 | JP_BLOCK_RET_CASE('f', float, floatValue)
157 | JP_BLOCK_RET_CASE('d', double, doubleValue)
158 | JP_BLOCK_RET_CASE('B', BOOL, boolValue)
159 |
160 | case '@':
161 | case '#': {
162 | id retObj = result;
163 | void **retPtrPtr = ret;
164 | *retPtrPtr = (__bridge void *)retObj;
165 | break;
166 | }
167 | }
168 | }
169 |
170 | static const char *__BlockSignature__(id blockObj)
171 | {
172 | struct JPSimulateBlock *block = (__bridge void *)blockObj;
173 | struct JPSimulateBlockDescriptor *descriptor = block->descriptor;
174 | assert(block->flags & BLOCK_HAS_SIGNATURE);
175 | return descriptor->signature;
176 | }
177 |
178 |
179 | @implementation OCBlockWrapper
180 |
181 | + (instancetype)blockWrapperWithNode:(ASTBlockNode *)node
182 | {
183 | OCBlockWrapper *wrapper = [[OCBlockWrapper alloc] init];
184 | wrapper.signature = [[OCMethodSignature alloc] initWithBlockTypeNames:node.typeNames];
185 | wrapper.node = node;
186 | wrapper.blockContext = node.blockContext;
187 | return wrapper;
188 | }
189 |
190 | - (void *)blockPtr
191 | {
192 | if (_generatedPtr) {
193 | return _blockPtr;
194 | }
195 |
196 | _generatedPtr = YES;
197 |
198 | ffi_type *returnType = [OCMethodSignature ffiTypeWithEncodingChar:[self.signature.returnType UTF8String]];
199 |
200 | NSUInteger argumentCount = self.signature.argumentTypes.count;
201 |
202 | _cifPtr = malloc(sizeof(ffi_cif));
203 |
204 | void *blockImp = NULL;
205 |
206 | _args = malloc(sizeof(ffi_type *) *argumentCount) ;
207 |
208 | for (int i = 0; i < argumentCount; i++){
209 | ffi_type* current_ffi_type = [OCMethodSignature ffiTypeWithEncodingChar:[self.signature.argumentTypes[i] UTF8String]];
210 | _args[i] = current_ffi_type;
211 | }
212 |
213 | _closure = ffi_closure_alloc(sizeof(ffi_closure), (void **)&blockImp);
214 |
215 | if(ffi_prep_cif(_cifPtr, FFI_DEFAULT_ABI, (unsigned int)argumentCount, returnType, _args) == FFI_OK) {
216 | if (ffi_prep_closure_loc(_closure, _cifPtr, JPBlockInterpreter, (__bridge void *)self, blockImp) != FFI_OK) {
217 | NSAssert(NO, @"generate block error");
218 | }
219 | }
220 |
221 | struct JPSimulateBlockDescriptor descriptor = {
222 | 0,
223 | sizeof(struct JPSimulateBlock),
224 | (void (*)(void *dst, const void *src))copy_helper,
225 | (void (*)(const void *src))dispose_helper,
226 | [self.signature.types cStringUsingEncoding:NSASCIIStringEncoding]
227 | };
228 |
229 | _descriptor = malloc(sizeof(struct JPSimulateBlockDescriptor));
230 | memcpy(_descriptor, &descriptor, sizeof(struct JPSimulateBlockDescriptor));
231 |
232 | struct JPSimulateBlock simulateBlock = {
233 | &_NSConcreteStackBlock,
234 | (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_SIGNATURE),
235 | 0,
236 | blockImp,
237 | _descriptor,
238 | (__bridge void*)self
239 | };
240 |
241 | _blockPtr = Block_copy(&simulateBlock);
242 | return _blockPtr;
243 | }
244 |
245 | + (id)excuteBlock:(id)block withParams:(NSArray *)params
246 | {
247 | NSMethodSignature *methodSignature = [NSMethodSignature signatureWithObjCTypes:__BlockSignature__(block)];
248 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
249 | invocation.target = block;
250 | return [ASTCallMethod invokeWithInvocation:invocation argments:params];
251 | }
252 |
253 | - (void)dealloc
254 | {
255 | ffi_closure_free(_closure);
256 | free(_args);
257 | free(_cifPtr);
258 | free(_descriptor);
259 | return;
260 | }
261 |
262 | @end
263 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Parser/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letqingbin/DynamicOC/8824d9695e14415239b5410ad0f00df88677180f/DynamicOC/DynamicOC/Parser/.DS_Store
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Parser/tokenizer.lm:
--------------------------------------------------------------------------------
1 | %{
2 | #import
3 | #import "ASTNode.h"
4 | #import "ASTContext.h"
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | #include "y.tab.h"
11 |
12 | void count(void);
13 | void comment(void);
14 | int toInt(void);
15 | double toDouble(void);
16 | extern NSString* toString(const char* text);
17 | extern NSString* toStringLiteral(const char* text);
18 |
19 | extern BOOL isKnownVariableName(NSString* key);
20 | %}
21 |
22 | D [0-9]
23 | L [a-zA-Z_]
24 |
25 | %%
26 | "/*" { comment(); }
27 | "//"[^\n]* { /* consume //-comment */ }
28 |
29 | "YES" { count(); yylval.t_int=1; return(OC_YES); }
30 | "NO" { count(); yylval.t_int=0; return(OC_NO); }
31 | "true" { count(); yylval.t_int=1; return(OC_YES); }
32 | "false" { count(); yylval.t_int=0; return(OC_NO); }
33 | "nil" { count(); return(OC_NIL); }
34 | "NULL" { count(); return(OC_NIL); }
35 | "break" { count(); return(BREAK); }
36 | "continue" { count(); return(CONTINUE); }
37 | "else" { count(); return(ELSE); }
38 | "for" { count(); return(FOR); }
39 | "if" { count(); return(IF); }
40 | "return" { count(); return(RETURN); }
41 | "void" { count(); return(VOID); }
42 | "while" { count(); return(WHILE); }
43 | "do" { count(); return(DO); }
44 | "in" { count(); return(IN); }
45 | "switch" { count(); return(SWITCH); }
46 | "case" { count(); return(CASE); }
47 | "default" { count(); return(DEFAULT); }
48 |
49 | "unsigned" { count(); return(UNSIGNED); }
50 | "char" { count(); return(CHAR); }
51 | "short" { count(); return(SHORT); }
52 | "int" { count(); return(INT); }
53 | "long" { count(); return(LONG); }
54 | "float" { count(); return(FLOAT); }
55 | "double" { count(); return(DOUBLE); }
56 | "BOOL" { count(); return(OC_BOOL); }
57 | "NSInteger" { count(); return(LONG); }
58 | "NSUInteger" { count(); return(NSUINTEGER); }
59 |
60 | "CGFloat" {
61 | count();
62 | #if CGFLOAT_IS_DOUBLE
63 | return(DOUBLE);
64 | #else
65 | return(FLOAT);
66 | #endif
67 | }
68 |
69 | "__block" { count(); return(OC_BLOCK); }
70 | "_Nonnull" {;}
71 | "_Nullable" {;}
72 |
73 | {L}({L}|{D})* {
74 | count();
75 | NSString* title = toString(yytext);
76 | yylval.t_string = title;
77 |
78 | if(isKnownVariableName(title))
79 | {
80 | return(VARIABLE);
81 | }
82 |
83 | return(KEYWORD);
84 | }
85 |
86 | [1-9]{D}* { count(); yylval.t_int = toInt(); return(CONSTANT_INT); }
87 |
88 | {D}+ { count(); yylval.t_int = toInt(); return(CONSTANT_INT); }
89 | {D}*"."{D}+ { count(); yylval.t_double = toDouble(); return(CONSTANT_DOUBLE); }
90 | {D}+"."{D}* { count(); yylval.t_double = toDouble(); return(CONSTANT_DOUBLE); }
91 |
92 | @?\"(\\.|[^\\"\n])*\" {
93 | count();
94 | NSString* val = toStringLiteral(yytext);
95 | yylval.t_string = val;
96 | return(STRING_LITERAL);
97 | }
98 |
99 | "+=" { count(); return(ADD_ASSIGN); }
100 | "-=" { count(); return(SUB_ASSIGN); }
101 | ">>" { count(); return(OP_RIGHT_SHIFT); }
102 | "<<" { count(); return(OP_LEFT_SHIFT); }
103 | "++" { count(); return(OP_INC); }
104 | "--" { count(); return(OP_DEC); }
105 | "->" { count(); return(OP_PTR); }
106 | "&&" { count(); return(OP_AND); }
107 | "||" { count(); return(OP_OR); }
108 | "<=" { count(); return(OP_LE); }
109 | ">=" { count(); return(OP_GE); }
110 | "==" { count(); return(OP_EQUAL); }
111 | "!=" { count(); return(OP_NOTEQUAL); }
112 | ";" { count(); return(';'); }
113 | "{" { count(); return('{'); }
114 | "}" { count(); return('}'); }
115 | "," { count(); return(','); }
116 | ":" { count(); return(':'); }
117 | "=" { count(); return('='); }
118 | "(" { count(); return('('); }
119 | ")" { count(); return(')'); }
120 | "[" { count(); return('['); }
121 | "]" { count(); return(']'); }
122 | "." { count(); return('.'); }
123 | "&" { count(); return('&'); }
124 | "!" { count(); return('!'); }
125 | "-" { count(); return('-'); }
126 | "+" { count(); return('+'); }
127 | "*" { count(); return('*'); }
128 | "/" { count(); return('/'); }
129 | "%" { count(); return('%'); }
130 | "<" { count(); return('<'); }
131 | ">" { count(); return('>'); }
132 | "^" { count(); return('^'); }
133 | "|" { count(); return('|'); }
134 | "?" { count(); return('?'); }
135 | "@" { count(); return('@'); }
136 | "@(" { count(); return(LEFT_PAREN);}
137 | "@{" { count(); return(LEFT_BRACE);}
138 | "@[" { count(); return(LEFT_SQUARE);}
139 |
140 | [ \t\r\n]* { count(); }
141 | . { ; }
142 |
143 | %%
144 |
145 | int yywrap(void)
146 | {
147 | return 1;
148 | }
149 |
150 | void comment(void)
151 | {
152 | char c, prev = 0;
153 |
154 | while ((c = input()) != 0) /* (EOF maps to 0) */
155 | {
156 | if (c == '/' && prev == '*')
157 | return;
158 | prev = c;
159 | }
160 | }
161 |
162 | int column = 0;
163 |
164 | void count(void)
165 | {
166 | int i;
167 |
168 | for (i = 0; yytext[i] != '\0'; i++)
169 | if (yytext[i] == '\n')
170 | column = 0;
171 | else if (yytext[i] == '\t')
172 | column += 8 - (column % 8);
173 | else
174 | column++;
175 |
176 | ECHO;
177 | }
178 |
179 | int toInt()
180 | {
181 | int result = (int)strtol(yytext, NULL, 10);
182 | return result;
183 | }
184 |
185 | double toDouble()
186 | {
187 | double result = atof(yytext);
188 | return result;
189 | }
190 |
191 |
192 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/Aspects/Aspects.h:
--------------------------------------------------------------------------------
1 | //
2 | // Aspects.h
3 | // Aspects - A delightful, simple library for aspect oriented programming.
4 | //
5 | // Copyright (c) 2014 Peter Steinberger. Licensed under the MIT license.
6 | //
7 |
8 | #import
9 |
10 | typedef NS_OPTIONS(NSUInteger, AspectOptions) {
11 | AspectPositionAfter = 0, /// Called after the original implementation (default)
12 | AspectPositionInstead = 1, /// Will replace the original implementation.
13 | AspectPositionBefore = 2, /// Called before the original implementation.
14 |
15 | AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution.
16 | };
17 |
18 | /// Opaque Aspect Token that allows to deregister the hook.
19 | @protocol AspectToken
20 |
21 | /// Deregisters an aspect.
22 | /// @return YES if deregistration is successful, otherwise NO.
23 | - (BOOL)remove;
24 |
25 | @end
26 |
27 | /// The AspectInfo protocol is the first parameter of our block syntax.
28 | @protocol AspectInfo
29 |
30 | /// The instance that is currently hooked.
31 | - (id)instance;
32 |
33 | /// The original invocation of the hooked method.
34 | - (NSInvocation *)originalInvocation;
35 |
36 | /// All method arguments, boxed. This is lazily evaluated.
37 | - (NSArray *)arguments;
38 |
39 | @end
40 |
41 | /**
42 | Aspects uses Objective-C message forwarding to hook into messages. This will create some overhead. Don't add aspects to methods that are called a lot. Aspects is meant for view/controller code that is not called a 1000 times per second.
43 |
44 | Adding aspects returns an opaque token which can be used to deregister again. All calls are thread safe.
45 | */
46 | @interface NSObject (Aspects)
47 |
48 | /// Adds a block of code before/instead/after the current `selector` for a specific class.
49 | ///
50 | /// @param block Aspects replicates the type signature of the method being hooked.
51 | /// The first parameter will be `id`, followed by all parameters of the method.
52 | /// These parameters are optional and will be filled to match the block signature.
53 | /// You can even use an empty block, or one that simple gets `id`.
54 | ///
55 | /// @note Hooking static methods is not supported.
56 | /// @return A token which allows to later deregister the aspect.
57 | + (id)aspect_hookSelector:(SEL)selector
58 | withOptions:(AspectOptions)options
59 | usingBlock:(id)block
60 | error:(NSError **)error;
61 |
62 | /// Adds a block of code before/instead/after the current `selector` for a specific instance.
63 | - (id)aspect_hookSelector:(SEL)selector
64 | withOptions:(AspectOptions)options
65 | usingBlock:(id)block
66 | error:(NSError **)error;
67 |
68 | @end
69 |
70 |
71 | typedef NS_ENUM(NSUInteger, AspectErrorCode) {
72 | AspectErrorSelectorBlacklisted, /// Selectors like release, retain, autorelease are blacklisted.
73 | AspectErrorDoesNotRespondToSelector, /// Selector could not be found.
74 | AspectErrorSelectorDeallocPosition, /// When hooking dealloc, only AspectPositionBefore is allowed.
75 | AspectErrorSelectorAlreadyHookedInClassHierarchy, /// Statically hooking the same method in subclasses is not allowed.
76 | AspectErrorFailedToAllocateClassPair, /// The runtime failed creating a class pair.
77 | AspectErrorMissingBlockSignature, /// The block misses compile time signature info and can't be called.
78 | AspectErrorIncompatibleBlockSignature, /// The block signature does not match the method or is too large.
79 |
80 | AspectErrorRemoveObjectAlreadyDeallocated = 100 /// (for removing) The object hooked is already deallocated.
81 | };
82 |
83 | extern NSString *const AspectErrorDomain;
84 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/NSValue+struct.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSValue+struct.h
3 | // OCEval
4 | //
5 | // Created by sgcy on 2018/11/27.
6 | //
7 |
8 | #import
9 |
10 | @interface NSValue(structt)
11 |
12 | //CGPoint,CGSize,CGRect
13 | - (id)setX:(CGFloat)x;
14 | - (CGFloat)x;
15 | - (id)setY:(CGFloat)y;
16 | - (CGFloat)y;
17 |
18 | - (id)setWidth:(CGFloat)width;
19 | - (CGFloat)width;
20 | - (id)setHeight:(CGFloat)height;
21 | - (CGFloat)height;
22 |
23 | - (id)setOrigin:(CGPoint)origin;
24 | - (id)setSize:(CGSize)size;
25 | - (CGPoint)origin;
26 | - (CGSize)size;
27 |
28 | //NSRange
29 | - (id)setLocation:(NSUInteger)location;
30 | - (NSUInteger)location;
31 | - (id)setLength:(NSUInteger)length;
32 | - (NSUInteger)length;
33 |
34 | //UIOffset
35 | - (id)setHorizontal:(CGFloat)horizontal;
36 | - (CGFloat)horizontal;
37 | - (id)setVertical:(CGFloat)vertical;
38 | - (CGFloat)vertical;
39 |
40 |
41 | //UIEdgeInsets
42 | - (id)setTop:(CGFloat)top;
43 | - (CGFloat)top;
44 | - (id)setLeft:(CGFloat)left;
45 | - (CGFloat)left;
46 | - (id)setBottom:(CGFloat)bottom;
47 | - (CGFloat)bottom;
48 | - (id)setRight:(CGFloat)right;
49 | - (CGFloat)right;
50 |
51 | //CGVector
52 | - (id)setDx:(CGFloat)dx;
53 | - (CGFloat)dx;
54 | - (id)setDy:(CGFloat)dy;
55 | - (CGFloat)dy;
56 |
57 |
58 | //CGAffineTransform
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/NSValue+struct.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSValue+struct.m
3 | // OCEval
4 | //
5 | // Created by sgcy on 2018/11/27.
6 | //
7 | #import "NSValue+struct.h"
8 |
9 | @implementation NSValue(structt)
10 |
11 | //CGPoint,CGSize,CGRect
12 | - (id)setX:(CGFloat)x
13 | {
14 | CGPoint point = [self CGPointValue];
15 | point.x = x;
16 | return [NSValue valueWithCGPoint:point];
17 | }
18 |
19 | - (CGFloat)x
20 | {
21 | CGPoint point = [self CGPointValue];
22 | return point.x;
23 | }
24 |
25 | - (id)setY:(CGFloat)y
26 | {
27 | CGPoint point = [self CGPointValue];
28 | point.y = y;
29 | return [NSValue valueWithCGPoint:point];
30 | }
31 |
32 | - (CGFloat)y
33 | {
34 | CGPoint point = [self CGPointValue];
35 | return point.y;
36 | }
37 |
38 | - (id)setWidth:(CGFloat)width
39 | {
40 | CGSize size = [self CGSizeValue];
41 | size.width = width;
42 | return [NSValue valueWithCGSize:size];
43 | }
44 |
45 | - (CGFloat)width
46 | {
47 | CGSize size = [self CGSizeValue];
48 | return size.width;
49 | }
50 |
51 | - (id)setHeight:(CGFloat)height
52 | {
53 | CGSize size = [self CGSizeValue];
54 | size.height = height;
55 | return [NSValue valueWithCGSize:size];
56 | }
57 |
58 | - (CGFloat)height
59 | {
60 | CGSize size = [self CGSizeValue];
61 | return size.height;
62 | }
63 |
64 | - (id)setOrigin:(CGPoint)origin
65 | {
66 | CGRect rect = [self CGRectValue];
67 | rect.origin = origin;
68 |
69 | return [NSValue valueWithCGRect:rect];
70 | }
71 |
72 | - (id)setSize:(CGSize)size
73 | {
74 | CGRect rect = [self CGRectValue];
75 | rect.size = size;
76 |
77 | return [NSValue valueWithCGRect:rect];
78 | }
79 |
80 | - (CGPoint)origin
81 | {
82 | CGRect rect = [self CGRectValue];
83 | return rect.origin;
84 | }
85 |
86 | - (CGSize)size
87 | {
88 | CGRect rect = [self CGRectValue];
89 | return rect.size;
90 | }
91 |
92 | //NSRange
93 | - (id)setLocation:(NSUInteger)location
94 | {
95 | NSRange range = [self rangeValue];
96 | range.location = location;
97 | return [NSValue valueWithRange:range];
98 | }
99 |
100 | - (NSUInteger)location
101 | {
102 | NSRange range = [self rangeValue];
103 | return range.location;
104 | }
105 |
106 | - (id)setLength:(NSUInteger)length
107 | {
108 | NSRange range = [self rangeValue];
109 | range.length = length;
110 | return [NSValue valueWithRange:range];
111 | }
112 |
113 | - (NSUInteger)length
114 | {
115 | NSRange range = [self rangeValue];
116 | return range.length;
117 | }
118 |
119 | //UIOffset
120 | - (id)setHorizontal:(CGFloat)horizontal
121 | {
122 | UIOffset offset = [self UIOffsetValue];
123 | offset.horizontal = horizontal;
124 | return [NSValue valueWithUIOffset:offset];
125 | }
126 |
127 | - (CGFloat)horizontal
128 | {
129 | UIOffset offset = [self UIOffsetValue];
130 | return offset.horizontal;
131 | }
132 |
133 | - (id)setVertical:(CGFloat)vertical
134 | {
135 | UIOffset offset = [self UIOffsetValue];
136 | offset.vertical = vertical;
137 | return [NSValue valueWithUIOffset:offset];
138 | }
139 |
140 | - (CGFloat)vertical
141 | {
142 | UIOffset offset = [self UIOffsetValue];
143 | return offset.vertical;
144 | }
145 |
146 | //UIEdgeInsets
147 | - (id)setTop:(CGFloat)top
148 | {
149 | UIEdgeInsets inset = [self UIEdgeInsetsValue];
150 | inset.top = top;
151 | return [NSValue valueWithUIEdgeInsets:inset];
152 | }
153 |
154 | - (CGFloat)top
155 | {
156 | UIEdgeInsets inset = [self UIEdgeInsetsValue];
157 | return inset.top;
158 | }
159 |
160 | - (id)setLeft:(CGFloat)left
161 | {
162 | UIEdgeInsets inset = [self UIEdgeInsetsValue];
163 | inset.left = left;
164 | return [NSValue valueWithUIEdgeInsets:inset];
165 | }
166 |
167 | - (CGFloat)left
168 | {
169 | UIEdgeInsets inset = [self UIEdgeInsetsValue];
170 | return inset.left;
171 | }
172 |
173 | - (id)setBottom:(CGFloat)bottom
174 | {
175 | UIEdgeInsets inset = [self UIEdgeInsetsValue];
176 | inset.bottom = bottom;
177 | return [NSValue valueWithUIEdgeInsets:inset];
178 | }
179 |
180 | - (CGFloat)bottom
181 | {
182 | UIEdgeInsets inset = [self UIEdgeInsetsValue];
183 | return inset.bottom;
184 | }
185 |
186 | - (id)setRight:(CGFloat)right
187 | {
188 | UIEdgeInsets inset = [self UIEdgeInsetsValue];
189 | inset.right = right;
190 | return [NSValue valueWithUIEdgeInsets:inset];
191 | }
192 |
193 | - (CGFloat)right
194 | {
195 | UIEdgeInsets inset = [self UIEdgeInsetsValue];
196 | return inset.right;
197 | }
198 |
199 | //CGVector
200 | - (id)setDx:(CGFloat)dx
201 | {
202 | CGVector vector = [self CGVectorValue];
203 | vector.dx = dx;
204 | return [NSValue valueWithCGVector:vector];
205 | }
206 |
207 | - (CGFloat)dx
208 | {
209 | CGVector vector = [self CGVectorValue];
210 | return vector.dx;
211 | }
212 |
213 | - (id)setDy:(CGFloat)dy
214 | {
215 | CGVector vector = [self CGVectorValue];
216 | vector.dy = dy;
217 | return [NSValue valueWithCGVector:vector];
218 | }
219 |
220 | - (CGFloat)dy
221 | {
222 | CGVector vector = [self CGVectorValue];
223 | return vector.dy;
224 | }
225 |
226 |
227 |
228 | @end
229 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/OCCFuntionWrapper.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCCFuntionWrapper.h
3 | // OCParser
4 | //
5 | // Created by sgcy on 2018/11/21.
6 | // Copyright © 2018年 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface OCCFuntionWrapper : NSObject
12 |
13 | + (id)callCFunction:(NSString *)funcName arguments:(NSArray *)arguments;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/OCCFuntionWrapper.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCCFuntionWrapper.m
3 | // OCParser
4 | //
5 | // Created by sgcy on 2018/11/21.
6 | // Copyright © 2018年 sgcy. All rights reserved.
7 | //
8 |
9 |
10 | #import "OCCFuntionWrapper.h"
11 | #import "ASTCallMethod.h"
12 | #import "OCBlockWrapper.h"
13 |
14 | #import
15 |
16 | @implementation OCCFuntionWrapper
17 |
18 | + (id)callCFunction:(NSString *)funcName arguments:(NSArray *)arguments
19 | {
20 | funcName = [funcName stringByAppendingString:@":"];
21 | return [ASTCallMethod invokeWithCaller:self selectorName:funcName argments:@[arguments]];
22 | }
23 |
24 | + (void)dispatch_after:(NSArray*)arugments
25 | {
26 | double delayInSeconds = [arugments[0] doubleValue];
27 | id funcPtr = arugments[1];
28 |
29 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
30 | [OCBlockWrapper excuteBlock:funcPtr withParams:@[]];
31 | });
32 | }
33 |
34 | + (id)CGRectMake:(NSArray *)arguments
35 | {
36 | return [NSValue valueWithCGRect:CGRectMake([arguments[0] doubleValue], [arguments[1] doubleValue], [arguments[2] doubleValue], [arguments[3] doubleValue])];
37 | }
38 |
39 | + (id)CGRectZero:(NSArray *)arguments
40 | {
41 | return [NSValue valueWithCGRect:CGRectZero];
42 | }
43 |
44 | + (id)CGPointMake:(NSArray *)arguments
45 | {
46 | return [NSValue valueWithCGPoint:CGPointMake([arguments[0] doubleValue], [arguments[1] doubleValue])];
47 | }
48 |
49 | + (id)CGPointZero:(NSArray *)arguments
50 | {
51 | return [NSValue valueWithCGPoint:CGPointZero];
52 | }
53 |
54 | + (id)CGSizeMake:(NSArray *)arguments
55 | {
56 | return [NSValue valueWithCGSize:CGSizeMake([arguments[0] doubleValue], [arguments[1] doubleValue])];
57 | }
58 |
59 | + (id)CGSizeZero:(NSArray *)arguments
60 | {
61 | return [NSValue valueWithCGSize:CGSizeZero];
62 | }
63 |
64 | + (id)NSMakeRange:(NSArray *)arguments
65 | {
66 | return [NSValue valueWithRange:NSMakeRange([arguments[0] integerValue], [arguments[1] integerValue])];
67 | }
68 |
69 | + (id)UIEdgeInsetsMake:(NSArray *)arguments
70 | {
71 | return [NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake([arguments[0] floatValue], [arguments[1] floatValue], [arguments[2] floatValue], [arguments[3] floatValue])];
72 | }
73 |
74 | + (id)UIEdgeInsetsZero:(NSArray*)arguments
75 | {
76 | return [NSValue valueWithUIEdgeInsets:UIEdgeInsetsZero];
77 | }
78 |
79 | + (id)CGVectorMake:(NSArray *)arguments
80 | {
81 | return [NSValue valueWithCGVector:CGVectorMake([arguments[0] floatValue], [arguments[1] floatValue])];
82 | }
83 |
84 | + (id)CGAffineTransformMake:(NSArray *)arguments
85 | {
86 | return [NSValue valueWithCGAffineTransform:CGAffineTransformMake([arguments[0] floatValue], [arguments[1] floatValue], [arguments[2] floatValue], [arguments[3] floatValue],[arguments[4] floatValue],[arguments[5] floatValue])];
87 | }
88 |
89 | @end
90 |
91 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/OCCfuntionHelper.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCCfuntionHelper.h
3 | // OCParser
4 | //
5 | // Created by sgcy on 2018/11/20.
6 | // Copyright © 2018年 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface OCCfuntionHelper : NSObject
12 |
13 | + (void)defineCFunction:(NSString *)funcName types:(NSString *)types;
14 | + (id)callCFunction:(NSString *)funcName arguments:(NSArray *)arguments;
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/OCCfuntionHelper.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCCfuntionHelper.m
3 | // OCParser
4 | //
5 | // Created by sgcy on 2018/11/20.
6 | // Copyright © 2018年 sgcy. All rights reserved.
7 | //
8 |
9 | #import "OCCfuntionHelper.h"
10 | #import "ffi.h"
11 | #import "OCMethodSignature.h"
12 | #import
13 | #import "OCExtension.h"
14 | #import "OCCFuntionWrapper.h"
15 |
16 | #if CGFLOAT_IS_DOUBLE
17 | #define CGFloatValue doubleValue
18 | #define numberWithCGFloat numberWithDouble
19 | #else
20 | #define CGFloatValue floatValue
21 | #define numberWithCGFloat numberWithFloat
22 | #endif
23 |
24 | static NSMutableDictionary *_funcDefines;
25 |
26 | @implementation OCCfuntionHelper
27 |
28 | + (void)initialize
29 | {
30 | _funcDefines = [[NSMutableDictionary alloc] init];
31 | }
32 |
33 | + (void)defineCFunction:(NSString *)funcName types:(NSString *)types
34 | {
35 | NSMutableString *encodeStr = [[NSMutableString alloc] init];
36 | NSArray *typeArr = [types componentsSeparatedByString:@","];
37 | for (NSInteger i = 0; i < typeArr.count; i++)
38 | {
39 | NSString *typeStr = trim([typeArr objectAtIndex:i]);
40 | NSString *encode = [OCMethodSignature typeEncodeWithTypeName:typeStr];
41 | if (!encode)
42 | {
43 | if ([typeStr hasPrefix:@"{"] && [typeStr hasSuffix:@"}"])
44 | {
45 | encode = typeStr;
46 | }
47 | else
48 | {
49 | NSString *argClassName = trim([typeStr stringByReplacingOccurrencesOfString:@"*" withString:@""]);
50 | if (NSClassFromString(argClassName) != NULL)
51 | {
52 | encode = @"@";
53 | }
54 | else
55 | {
56 | NSCAssert(NO, @"unreconized type %@", typeStr);
57 | return;
58 | }
59 | }
60 | }
61 | [encodeStr appendString:encode];
62 | }
63 | [_funcDefines setObject:encodeStr forKey:funcName];
64 | }
65 |
66 | + (id)objectWithCValue:(void *)src forType:(const char *)typeString
67 | {
68 | switch (typeString[0]) {
69 |
70 | #define JP_FFI_RETURN_CASE(_typeString, _type, _selector)\
71 | case _typeString:{\
72 | _type v = *(_type *)src;\
73 | return [NSNumber _selector:v];\
74 | }
75 |
76 | JP_FFI_RETURN_CASE('c', char, numberWithChar)
77 | JP_FFI_RETURN_CASE('C', unsigned char, numberWithUnsignedChar)
78 | JP_FFI_RETURN_CASE('s', short, numberWithShort)
79 | JP_FFI_RETURN_CASE('S', unsigned short, numberWithUnsignedShort)
80 | JP_FFI_RETURN_CASE('i', int, numberWithInt)
81 | JP_FFI_RETURN_CASE('I', unsigned int, numberWithUnsignedInt)
82 | JP_FFI_RETURN_CASE('l', long, numberWithLong)
83 | JP_FFI_RETURN_CASE('L', unsigned long, numberWithUnsignedLong)
84 | JP_FFI_RETURN_CASE('q', long long, numberWithLongLong)
85 | JP_FFI_RETURN_CASE('Q', unsigned long long, numberWithUnsignedLongLong)
86 | JP_FFI_RETURN_CASE('f', float, numberWithFloat)
87 | JP_FFI_RETURN_CASE('F', CGFloat, numberWithCGFloat)
88 | JP_FFI_RETURN_CASE('d', double, numberWithDouble)
89 | JP_FFI_RETURN_CASE('B', BOOL, numberWithBool)
90 | case '@':
91 | case '#': {
92 | return (__bridge id)(*(void**)src);
93 | }
94 | case '{': {
95 | return [NSValue value:&src withObjCType:typeString];
96 | }
97 | case '^': {
98 | char c = typeString[1];
99 | if (c == '?') {
100 | NSValue *value = [NSValue valueWithPointer:(*(void**)src)];
101 | return value;
102 | }else{
103 | return (__bridge id)(*(void**)src);
104 | }
105 | }
106 | case '*':{
107 | return [NSString stringWithUTF8String:src];
108 | }
109 | case ':':{
110 | NSValue *value = [NSValue valueWithPointer:(*(void**)src)];
111 | return value;
112 | }
113 | default:
114 | return nil;
115 | }
116 | }
117 |
118 | + (void)convertObject:(id)object toCValue:(void *)dist forType:(const char *)typeString
119 | {
120 | #define JP_CALL_ARG_CASE(_typeString, _type, _selector)\
121 | case _typeString:{\
122 | *(_type *)dist = [(NSNumber *)object _selector];\
123 | break;\
124 | }
125 |
126 | switch (typeString[0]) {
127 | JP_CALL_ARG_CASE('c', char, charValue)
128 | JP_CALL_ARG_CASE('C', unsigned char, unsignedCharValue)
129 | JP_CALL_ARG_CASE('s', short, shortValue)
130 | JP_CALL_ARG_CASE('S', unsigned short, unsignedShortValue)
131 | JP_CALL_ARG_CASE('i', int, intValue)
132 | JP_CALL_ARG_CASE('I', unsigned int, unsignedIntValue)
133 | JP_CALL_ARG_CASE('l', long, longValue)
134 | JP_CALL_ARG_CASE('L', unsigned long, unsignedLongValue)
135 | JP_CALL_ARG_CASE('q', long long, longLongValue)
136 | JP_CALL_ARG_CASE('Q', unsigned long long, unsignedLongLongValue)
137 | JP_CALL_ARG_CASE('f', float, floatValue)
138 | JP_CALL_ARG_CASE('F', CGFloat, CGFloatValue)
139 | JP_CALL_ARG_CASE('d', double, doubleValue)
140 | JP_CALL_ARG_CASE('B', BOOL, boolValue)
141 | case '#':
142 | case '@': {
143 | id ptr = object;
144 | *(void **)dist = (__bridge void *)(ptr);
145 | break;
146 | }
147 | case ':':{
148 | SEL sel = [object pointerValue];
149 | (*(void**)dist) = sel;
150 | break;
151 | }
152 | case '{': {
153 | [object getValue:&dist];
154 | break;
155 | }
156 | case '*':{
157 | (*(void**)dist) = (void*)[object UTF8String];
158 | break;
159 | }
160 | case '^':{
161 | //^type -- a pointer to type
162 | char c = typeString[1];
163 | if (c == '?')
164 | {
165 | IMP imp = [object pointerValue];
166 | (*(void**)dist) = imp;
167 | break;
168 | }
169 | else
170 | {
171 | id ptr = object;
172 | *(void **)dist = (__bridge void *)(ptr);
173 | break;
174 | }
175 | }
176 | default:
177 | abort();
178 | }
179 | }
180 |
181 | + (id)callCFunction:(NSString *)funcName arguments:(NSArray *)arguments
182 | {
183 | void* functionPtr = dlsym(RTLD_DEFAULT, [funcName UTF8String]); //might be rejected by AppStore
184 | if (!functionPtr) {
185 | //inline function
186 | return [OCCFuntionWrapper callCFunction:funcName arguments:arguments];
187 | }
188 |
189 | OCMethodSignature *funcSignature = [[OCMethodSignature alloc] initWithObjCTypes:[_funcDefines objectForKey:funcName]];
190 |
191 | NSUInteger argCount = funcSignature.argumentTypes.count;
192 | if (argCount != [arguments count]){
193 | abort();
194 | }
195 |
196 | ffi_type **ffiArgTypes = alloca(sizeof(ffi_type *) *argCount);
197 | void **ffiArgs = alloca(sizeof(void *) *argCount);
198 | for (int i = 0; i < argCount; i ++) {
199 | const char *argumentType = [funcSignature.argumentTypes[i] UTF8String];
200 | ffi_type *ffiType = [OCMethodSignature ffiTypeWithEncodingChar:argumentType];
201 | ffiArgTypes[i] = ffiType;
202 | void *ffiArgPtr = alloca(ffiType->size);
203 | [self convertObject:arguments[i] toCValue:ffiArgPtr forType:argumentType];
204 | ffiArgs[i] = ffiArgPtr;
205 | }
206 |
207 | ffi_cif cif;
208 | id ret = nil;
209 | const char *returnTypeChar = [funcSignature.returnType UTF8String];
210 | ffi_type *returnFfiType = [OCMethodSignature ffiTypeWithEncodingChar:returnTypeChar];
211 | ffi_status ffiPrepStatus = ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, (unsigned int)0, (unsigned int)argCount, returnFfiType, ffiArgTypes);
212 |
213 | if (ffiPrepStatus == FFI_OK) {
214 | void *returnPtr = NULL;
215 | if (returnFfiType->size) {
216 | returnPtr = alloca(returnFfiType->size);
217 | }
218 | ffi_call(&cif, functionPtr, returnPtr, ffiArgs);
219 |
220 | if (returnFfiType->size) {
221 | ret = [self objectWithCValue:returnPtr forType:returnTypeChar];
222 | }
223 | }
224 |
225 | return ret;
226 | }
227 |
228 |
229 | static NSString *trim(NSString *string)
230 | {
231 | return [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
232 | }
233 |
234 | @end
235 |
236 |
237 |
238 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/OCExtension.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCExtension.h
3 | // OCParser
4 | //
5 | // Created by sgcy on 2018/11/21.
6 | // Copyright © 2018年 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface OCExtension : NSObject
12 |
13 | + (int)sizeOfStructTypes:(NSString *)structTypes;
14 | + (void)getStructDataWidthDict:(void *)structData dict:(NSDictionary *)dict structDefine:(NSDictionary *)structDefine;
15 | + (NSDictionary *)getDictOfStruct:(void *)structData structDefine:(NSDictionary *)structDefine;
16 |
17 | + (NSMutableDictionary *)registeredStruct;
18 |
19 | + (NSString *)extractStructName:(NSString *)typeEncodeString;
20 | + (void)defineStruct:(NSDictionary *)defineDict;
21 |
22 | @end
23 |
24 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/OCExtension.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCExtension.m
3 | // OCParser
4 | //
5 | // Created by sgcy on 2018/11/21.
6 | // Copyright © 2018年 sgcy. All rights reserved.
7 | //
8 |
9 | #import "OCExtension.h"
10 |
11 | #if CGFLOAT_IS_DOUBLE
12 | #define CGFloatValue doubleValue
13 | #else
14 | #define CGFloatValue floatValue
15 | #endif
16 |
17 | static NSMutableDictionary *_registeredStruct;
18 |
19 | @implementation OCExtension
20 |
21 | + (void)load
22 | {
23 | _registeredStruct = [[NSMutableDictionary alloc] init];
24 | }
25 |
26 | + (void)defineStruct:(NSDictionary *)defineDict
27 | {
28 | [_registeredStruct setObject:defineDict forKey:defineDict[@"name"]];
29 | }
30 |
31 |
32 | #pragma mark - Struct
33 |
34 | static int sizeOfStructTypes(NSString *structTypes)
35 | {
36 | const char *types = [structTypes cStringUsingEncoding:NSUTF8StringEncoding];
37 | int index = 0;
38 | int size = 0;
39 | while (types[index]) {
40 | switch (types[index]) {
41 | #define JP_STRUCT_SIZE_CASE(_typeChar, _type) \
42 | case _typeChar: \
43 | size += sizeof(_type); \
44 | break;
45 |
46 | JP_STRUCT_SIZE_CASE('c', char)
47 | JP_STRUCT_SIZE_CASE('C', unsigned char)
48 | JP_STRUCT_SIZE_CASE('s', short)
49 | JP_STRUCT_SIZE_CASE('S', unsigned short)
50 | JP_STRUCT_SIZE_CASE('i', int)
51 | JP_STRUCT_SIZE_CASE('I', unsigned int)
52 | JP_STRUCT_SIZE_CASE('l', long)
53 | JP_STRUCT_SIZE_CASE('L', unsigned long)
54 | JP_STRUCT_SIZE_CASE('q', long long)
55 | JP_STRUCT_SIZE_CASE('Q', unsigned long long)
56 | JP_STRUCT_SIZE_CASE('f', float)
57 | JP_STRUCT_SIZE_CASE('F', CGFloat)
58 | JP_STRUCT_SIZE_CASE('N', NSInteger)
59 | JP_STRUCT_SIZE_CASE('U', NSUInteger)
60 | JP_STRUCT_SIZE_CASE('d', double)
61 | JP_STRUCT_SIZE_CASE('B', BOOL)
62 | JP_STRUCT_SIZE_CASE('*', void *)
63 | JP_STRUCT_SIZE_CASE('^', void *)
64 |
65 | case '{': {
66 | NSString *structTypeStr = [structTypes substringFromIndex:index];
67 | NSUInteger end = [structTypeStr rangeOfString:@"}"].location;
68 | if (end != NSNotFound) {
69 | NSString *subStructName = [structTypeStr substringWithRange:NSMakeRange(1, end - 1)];
70 | NSDictionary *subStructDefine = [OCExtension registeredStruct][subStructName];
71 | NSString *subStructTypes = subStructDefine[@"types"];
72 | size += sizeOfStructTypes(subStructTypes);
73 | index += (int)end;
74 | break;
75 | }
76 | }
77 |
78 | default:
79 | break;
80 | }
81 | index ++;
82 | }
83 | return size;
84 | }
85 |
86 | static void getStructDataWithDict(void *structData, NSDictionary *dict, NSDictionary *structDefine)
87 | {
88 | NSArray *itemKeys = structDefine[@"keys"];
89 | const char *structTypes = [structDefine[@"types"] cStringUsingEncoding:NSUTF8StringEncoding];
90 | int position = 0;
91 | for (NSString *itemKey in itemKeys) {
92 | switch(*structTypes) {
93 | #define JP_STRUCT_DATA_CASE(_typeStr, _type, _transMethod) \
94 | case _typeStr: { \
95 | int size = sizeof(_type); \
96 | _type val = [dict[itemKey] _transMethod]; \
97 | memcpy(structData + position, &val, size); \
98 | position += size; \
99 | break; \
100 | }
101 |
102 | JP_STRUCT_DATA_CASE('c', char, charValue)
103 | JP_STRUCT_DATA_CASE('C', unsigned char, unsignedCharValue)
104 | JP_STRUCT_DATA_CASE('s', short, shortValue)
105 | JP_STRUCT_DATA_CASE('S', unsigned short, unsignedShortValue)
106 | JP_STRUCT_DATA_CASE('i', int, intValue)
107 | JP_STRUCT_DATA_CASE('I', unsigned int, unsignedIntValue)
108 | JP_STRUCT_DATA_CASE('l', long, longValue)
109 | JP_STRUCT_DATA_CASE('L', unsigned long, unsignedLongValue)
110 | JP_STRUCT_DATA_CASE('q', long long, longLongValue)
111 | JP_STRUCT_DATA_CASE('Q', unsigned long long, unsignedLongLongValue)
112 | JP_STRUCT_DATA_CASE('f', float, floatValue)
113 | JP_STRUCT_DATA_CASE('F', CGFloat, CGFloatValue)
114 | JP_STRUCT_DATA_CASE('d', double, doubleValue)
115 | JP_STRUCT_DATA_CASE('B', BOOL, boolValue)
116 | JP_STRUCT_DATA_CASE('N', NSInteger, integerValue)
117 | JP_STRUCT_DATA_CASE('U', NSUInteger, unsignedIntegerValue)
118 |
119 | case '*':
120 | case '{': {
121 | NSString *subStructName = [NSString stringWithCString:structTypes encoding:NSASCIIStringEncoding];
122 | NSUInteger end = [subStructName rangeOfString:@"}"].location;
123 | if (end != NSNotFound) {
124 | subStructName = [subStructName substringWithRange:NSMakeRange(1, end - 1)];
125 | NSDictionary *subStructDefine = [OCExtension registeredStruct][subStructName];
126 | NSDictionary *subDict = dict[itemKey];
127 | int size = sizeOfStructTypes(subStructDefine[@"types"]);
128 | getStructDataWithDict(structData + position, subDict, subStructDefine);
129 | position += size;
130 | structTypes += end;
131 | break;
132 | }
133 | }
134 | default:
135 | break;
136 |
137 | }
138 | structTypes ++;
139 | }
140 | }
141 |
142 | static NSDictionary *getDictOfStruct(void *structData, NSDictionary *structDefine)
143 | {
144 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
145 | NSArray *itemKeys = structDefine[@"keys"];
146 | const char *structTypes = [structDefine[@"types"] cStringUsingEncoding:NSUTF8StringEncoding];
147 | int position = 0;
148 |
149 | for (NSString *itemKey in itemKeys) {
150 | switch(*structTypes) {
151 | #define JP_STRUCT_DICT_CASE(_typeName, _type) \
152 | case _typeName: { \
153 | size_t size = sizeof(_type); \
154 | _type *val = malloc(size); \
155 | memcpy(val, structData + position, size); \
156 | [dict setObject:@(*val) forKey:itemKey]; \
157 | free(val); \
158 | position += size; \
159 | break; \
160 | }
161 | JP_STRUCT_DICT_CASE('c', char)
162 | JP_STRUCT_DICT_CASE('C', unsigned char)
163 | JP_STRUCT_DICT_CASE('s', short)
164 | JP_STRUCT_DICT_CASE('S', unsigned short)
165 | JP_STRUCT_DICT_CASE('i', int)
166 | JP_STRUCT_DICT_CASE('I', unsigned int)
167 | JP_STRUCT_DICT_CASE('l', long)
168 | JP_STRUCT_DICT_CASE('L', unsigned long)
169 | JP_STRUCT_DICT_CASE('q', long long)
170 | JP_STRUCT_DICT_CASE('Q', unsigned long long)
171 | JP_STRUCT_DICT_CASE('f', float)
172 | JP_STRUCT_DICT_CASE('F', CGFloat)
173 | JP_STRUCT_DICT_CASE('N', NSInteger)
174 | JP_STRUCT_DICT_CASE('U', NSUInteger)
175 | JP_STRUCT_DICT_CASE('d', double)
176 | JP_STRUCT_DICT_CASE('B', BOOL)
177 |
178 | case '*':
179 |
180 | case '{': {
181 | NSString *subStructName = [NSString stringWithCString:structTypes encoding:NSASCIIStringEncoding];
182 | NSUInteger end = [subStructName rangeOfString:@"}"].location;
183 | if (end != NSNotFound) {
184 | subStructName = [subStructName substringWithRange:NSMakeRange(1, end - 1)];
185 | NSDictionary *subStructDefine = [OCExtension registeredStruct][subStructName];
186 | int size = sizeOfStructTypes(subStructDefine[@"types"]);
187 | NSDictionary *subDict = getDictOfStruct(structData + position, subStructDefine);
188 | [dict setObject:subDict forKey:itemKey];
189 | position += size;
190 | structTypes += end;
191 | break;
192 | }
193 | }
194 | }
195 | structTypes ++;
196 | }
197 | return dict;
198 | }
199 |
200 | static NSString *extractStructName(NSString *typeEncodeString)
201 | {
202 | NSArray *array = [typeEncodeString componentsSeparatedByString:@"="];
203 | NSString *typeString = array[0];
204 | int firstValidIndex = 0;
205 | for (int i = 0; i< typeString.length; i++) {
206 | char c = [typeString characterAtIndex:i];
207 | if (c == '{' || c=='_') {
208 | firstValidIndex++;
209 | }else {
210 | break;
211 | }
212 | }
213 | return [typeString substringFromIndex:firstValidIndex];
214 | }
215 |
216 | #pragma mark - Utils
217 |
218 |
219 | + (NSString *)extractStructName:(NSString *)typeEncodeString
220 | {
221 | return extractStructName(typeEncodeString);
222 | }
223 |
224 | static NSString *trim(NSString *string)
225 | {
226 | return [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
227 | }
228 |
229 | + (int)sizeOfStructTypes:(NSString *)structTypes
230 | {
231 | return sizeOfStructTypes(structTypes);
232 | }
233 |
234 | + (void)getStructDataWidthDict:(void *)structData dict:(NSDictionary *)dict structDefine:(NSDictionary *)structDefine
235 | {
236 | return getStructDataWithDict(structData, dict, structDefine);
237 | }
238 |
239 | + (NSDictionary *)getDictOfStruct:(void *)structData structDefine:(NSDictionary *)structDefine
240 | {
241 | return getDictOfStruct(structData, structDefine);
242 | }
243 |
244 | + (NSMutableDictionary *)registeredStruct
245 | {
246 | return _registeredStruct;
247 | }
248 |
249 | @end
250 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/OCMethodSignature.h:
--------------------------------------------------------------------------------
1 | //
2 | // OCMethodSignature.h
3 | // OCParser
4 | //
5 | // Created by sgcy on 2018/11/19.
6 | // Copyright © 2018年 sgcy. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "ffi.h"
11 |
12 | @interface OCMethodSignature : NSObject
13 |
14 | @property (nonatomic, strong) NSString *types;
15 | @property (nonatomic, strong) NSArray *argumentTypes;
16 | @property (nonatomic, strong) NSString *returnType;
17 |
18 | - (instancetype)initWithBlockTypeNames:(NSArray *)typeNames;
19 | - (instancetype)initWithObjCTypes:(NSString *)objCTypes;
20 |
21 | + (ffi_type *)ffiTypeWithEncodingChar:(const char *)c;
22 | + (NSString *)typeEncodeWithTypeName:(NSString *)typeName;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/OCMethodSignature.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCMethodSignature.m
3 | // OCParser
4 | //
5 | // Created by sgcy on 2018/11/19.
6 | // Copyright © 2018年 sgcy. All rights reserved.
7 | //
8 |
9 | #import "OCMethodSignature.h"
10 | #import "OCExtension.h"
11 |
12 | @implementation OCMethodSignature{
13 | NSArray *_typeNames;
14 | }
15 |
16 | - (instancetype)initWithBlockTypeNames:(NSArray *)typeNames
17 | {
18 | if (self = [super init]) {
19 | _typeNames = typeNames;
20 | [self parseTypeNames];
21 | [self parse];
22 | }
23 | return self;
24 | }
25 |
26 | - (instancetype)initWithObjCTypes:(NSString *)objCTypes
27 | {
28 | self = [super init];
29 | if (self) {
30 | _types = objCTypes;
31 | [self parse];
32 | }
33 | return self;
34 | }
35 |
36 | - (void)parse
37 | {
38 | NSMutableArray *argumentTypes = [[NSMutableArray alloc] init];
39 | int i = 0;
40 | while (i < _types.length) {
41 | unichar c = [_types characterAtIndex:i];
42 | NSString *arg;
43 |
44 | if (isdigit(c)) {
45 | i++;
46 | continue;
47 | }
48 |
49 | BOOL skipNext = NO;
50 | if (c == '^') {
51 | skipNext = YES;
52 | arg = [_types substringWithRange:NSMakeRange(i, 2)];
53 |
54 | } else if (c == '?') {
55 | // @? is block
56 | arg = [_types substringWithRange:NSMakeRange(i - 1, 2)];
57 | [argumentTypes removeLastObject];
58 | } else if (c == '{') {
59 | int semaphore = 1;
60 | int j = i + 1;
61 | while (semaphore > 0) {
62 | arg = [_types substringWithRange:NSMakeRange(i, j - i)];
63 | unichar c2 = [_types characterAtIndex:j];
64 | if (c2 == '{') {
65 | semaphore ++;
66 | }else if (c2 == '}') {
67 | semaphore --;
68 | }
69 | j++;
70 | }
71 | arg = [_types substringWithRange:NSMakeRange(i, j - i)];
72 | if (i == 0) {
73 | _returnType = arg;
74 | } else {
75 | [argumentTypes addObject:arg];
76 | }
77 | i = (int)j;
78 | continue;
79 | } else {
80 |
81 | arg = [_types substringWithRange:NSMakeRange(i, 1)];
82 | }
83 |
84 | if (i == 0) {
85 | _returnType = arg;
86 | } else {
87 | [argumentTypes addObject:arg];
88 | }
89 | i ++;
90 | if (skipNext) i++;
91 | }
92 | self.argumentTypes = [argumentTypes copy];
93 | }
94 |
95 | - (void)parseTypeNames
96 | {
97 | NSMutableString *encodeStr = [[NSMutableString alloc] init];
98 | NSArray *typeArr = _typeNames;
99 | for (NSInteger i = 0; i < typeArr.count; i++) {
100 | NSString *typeStr = trim([typeArr objectAtIndex:i]);
101 | NSString *encode = [OCMethodSignature typeEncodeWithTypeName:typeStr];
102 | if (!encode) {
103 | NSString *argClassName = trim([typeStr stringByReplacingOccurrencesOfString:@"*" withString:@""]);
104 | if (NSClassFromString(argClassName) != NULL) {
105 | encode = @"@";
106 | } else {
107 | NSCAssert(NO, @"unreconized type %@", typeStr);
108 | return;
109 | }
110 | }
111 | [encodeStr appendString:encode];
112 | int length = [OCMethodSignature typeLengthWithTypeName:typeStr];
113 | [encodeStr appendString:[NSString stringWithFormat:@"%d", length]];
114 |
115 | if (i == 0) {
116 | // Blocks are passed one implicit argument - the block, of type "@?".
117 | [encodeStr appendString:@"@?0"];
118 | }
119 | }
120 | _types = encodeStr;
121 | }
122 |
123 | #pragma mark - class methods
124 |
125 | + (ffi_type *)ffiTypeWithEncodingChar:(const char *)c
126 | {
127 | switch (c[0]) {
128 | case 'v':
129 | return &ffi_type_void;
130 | case 'c':
131 | return &ffi_type_schar;
132 | case 'C':
133 | return &ffi_type_uchar;
134 | case 's':
135 | return &ffi_type_sshort;
136 | case 'S':
137 | return &ffi_type_ushort;
138 | case 'i':
139 | return &ffi_type_sint;
140 | case 'I':
141 | return &ffi_type_uint;
142 | case 'l':
143 | return &ffi_type_slong;
144 | case 'L':
145 | return &ffi_type_ulong;
146 | case 'q':
147 | return &ffi_type_sint64;
148 | case 'Q':
149 | return &ffi_type_uint64;
150 | case 'f':
151 | return &ffi_type_float;
152 | case 'd':
153 | return &ffi_type_double;
154 | case 'F':
155 | #if CGFLOAT_IS_DOUBLE
156 | return &ffi_type_double;
157 | #else
158 | return &ffi_type_float;
159 | #endif
160 | case 'B':
161 | return &ffi_type_uint8;
162 | case '^':
163 | return &ffi_type_pointer;
164 | case '@':
165 | return &ffi_type_pointer;
166 | case '#':
167 | return &ffi_type_pointer;
168 | case ':':
169 | return &ffi_type_pointer;
170 | case '*':
171 | return &ffi_type_pointer;
172 | case '{': //c struct support ?
173 | {
174 | NSString *typeStr = [NSString stringWithCString:c encoding:NSASCIIStringEncoding];
175 | NSUInteger end = [typeStr rangeOfString:@"="].location;
176 | if (end != NSNotFound) {
177 | NSString *structName = [typeStr substringWithRange:NSMakeRange(1, end - 1)];
178 | ffi_type *type = malloc(sizeof(ffi_type));
179 | type->alignment = 0;
180 | type->size = 0;
181 | type->type = FFI_TYPE_STRUCT;
182 | NSDictionary *structDefine = [OCExtension registeredStruct][structName];
183 | NSUInteger subTypeCount = [structDefine[@"keys"] count];
184 | NSString *subTypes = structDefine[@"types"];
185 | ffi_type **sub_types = malloc(sizeof(ffi_type *) * (subTypeCount + 1));
186 | for (NSUInteger i=0; ielements = sub_types;
193 | printf("number of test.elements: %d\n", (int)(sizeof(sub_types) / sizeof(ffi_type *)));
194 | return type;
195 | }
196 | }
197 | default:
198 | {
199 | abort();
200 | }
201 |
202 | }
203 | return NULL;
204 | }
205 |
206 | static NSMutableDictionary *_typeEncodeDict;
207 | static NSMutableDictionary *_typeLengthDict;
208 |
209 | + (int)typeLengthWithTypeName:(NSString *)typeName
210 | {
211 | if (!typeName) return 0;
212 | if (!_typeLengthDict) {
213 | _typeLengthDict = [[NSMutableDictionary alloc] init];
214 |
215 | #define JP_DEFINE_TYPE_LENGTH(_type) \
216 | [_typeLengthDict setObject:@(sizeof(_type)) forKey:@#_type];\
217 |
218 | JP_DEFINE_TYPE_LENGTH(id);
219 | JP_DEFINE_TYPE_LENGTH(BOOL);
220 | JP_DEFINE_TYPE_LENGTH(int);
221 | JP_DEFINE_TYPE_LENGTH(void);
222 | JP_DEFINE_TYPE_LENGTH(char);
223 | JP_DEFINE_TYPE_LENGTH(short);
224 | JP_DEFINE_TYPE_LENGTH(unsigned short);
225 | JP_DEFINE_TYPE_LENGTH(unsigned int);
226 | JP_DEFINE_TYPE_LENGTH(long);
227 | JP_DEFINE_TYPE_LENGTH(unsigned long);
228 | JP_DEFINE_TYPE_LENGTH(long long);
229 | JP_DEFINE_TYPE_LENGTH(unsigned long long);
230 | JP_DEFINE_TYPE_LENGTH(float);
231 | JP_DEFINE_TYPE_LENGTH(double);
232 | JP_DEFINE_TYPE_LENGTH(bool);
233 | JP_DEFINE_TYPE_LENGTH(size_t);
234 | JP_DEFINE_TYPE_LENGTH(CGFloat);
235 | JP_DEFINE_TYPE_LENGTH(CGSize);
236 | JP_DEFINE_TYPE_LENGTH(CGRect);
237 | JP_DEFINE_TYPE_LENGTH(CGPoint);
238 | JP_DEFINE_TYPE_LENGTH(CGVector);
239 | JP_DEFINE_TYPE_LENGTH(NSRange);
240 | JP_DEFINE_TYPE_LENGTH(NSInteger);
241 | JP_DEFINE_TYPE_LENGTH(NSUInteger);
242 | JP_DEFINE_TYPE_LENGTH(NSComparisonResult);
243 | JP_DEFINE_TYPE_LENGTH(Class);
244 | JP_DEFINE_TYPE_LENGTH(SEL);
245 | JP_DEFINE_TYPE_LENGTH(IMP);
246 | JP_DEFINE_TYPE_LENGTH(void*);
247 | JP_DEFINE_TYPE_LENGTH(void *);
248 | JP_DEFINE_TYPE_LENGTH(id *);
249 | JP_DEFINE_TYPE_LENGTH(char *);
250 | JP_DEFINE_TYPE_LENGTH(char*);
251 | }
252 | return [_typeLengthDict[typeName] intValue];
253 | }
254 |
255 | + (NSString *)typeEncodeWithTypeName:(NSString *)typeName
256 | {
257 | if (!typeName) return nil;
258 | if (!_typeEncodeDict) {
259 | _typeEncodeDict = [[NSMutableDictionary alloc] init];
260 |
261 | #define JP_DEFINE_TYPE_ENCODE_CASE(_type) \
262 | [_typeEncodeDict setObject:[NSString stringWithUTF8String:@encode(_type)] forKey:@#_type];\
263 |
264 | JP_DEFINE_TYPE_ENCODE_CASE(id);
265 | JP_DEFINE_TYPE_ENCODE_CASE(BOOL);
266 | JP_DEFINE_TYPE_ENCODE_CASE(int);
267 | JP_DEFINE_TYPE_ENCODE_CASE(void);
268 | JP_DEFINE_TYPE_ENCODE_CASE(char);
269 | JP_DEFINE_TYPE_ENCODE_CASE(short);
270 | JP_DEFINE_TYPE_ENCODE_CASE(unsigned short);
271 | JP_DEFINE_TYPE_ENCODE_CASE(unsigned int);
272 | JP_DEFINE_TYPE_ENCODE_CASE(long);
273 | JP_DEFINE_TYPE_ENCODE_CASE(unsigned long);
274 | JP_DEFINE_TYPE_ENCODE_CASE(long long);
275 | JP_DEFINE_TYPE_ENCODE_CASE(unsigned long long);
276 | JP_DEFINE_TYPE_ENCODE_CASE(float);
277 | JP_DEFINE_TYPE_ENCODE_CASE(double);
278 | JP_DEFINE_TYPE_ENCODE_CASE(bool);
279 | JP_DEFINE_TYPE_ENCODE_CASE(size_t);
280 | JP_DEFINE_TYPE_ENCODE_CASE(CGFloat);
281 | JP_DEFINE_TYPE_ENCODE_CASE(CGSize);
282 | JP_DEFINE_TYPE_ENCODE_CASE(CGRect);
283 | JP_DEFINE_TYPE_ENCODE_CASE(CGPoint);
284 | JP_DEFINE_TYPE_ENCODE_CASE(CGVector);
285 | JP_DEFINE_TYPE_ENCODE_CASE(NSRange);
286 | JP_DEFINE_TYPE_ENCODE_CASE(NSInteger);
287 | JP_DEFINE_TYPE_ENCODE_CASE(NSUInteger);
288 | JP_DEFINE_TYPE_ENCODE_CASE(NSComparisonResult);
289 | JP_DEFINE_TYPE_ENCODE_CASE(Class);
290 | JP_DEFINE_TYPE_ENCODE_CASE(SEL);
291 | JP_DEFINE_TYPE_ENCODE_CASE(IMP);
292 | JP_DEFINE_TYPE_ENCODE_CASE(void*);
293 | JP_DEFINE_TYPE_ENCODE_CASE(void *);
294 | JP_DEFINE_TYPE_ENCODE_CASE(char *);
295 | JP_DEFINE_TYPE_ENCODE_CASE(char*);
296 | [_typeEncodeDict setObject:@"@?" forKey:@"block"];
297 | [_typeEncodeDict setObject:@"^@" forKey:@"id*"];
298 | }
299 | return _typeEncodeDict[typeName];
300 | }
301 |
302 | static NSString *trim(NSString *string)
303 | {
304 | return [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
305 | }
306 |
307 | @end
308 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/libffi/ffi.h:
--------------------------------------------------------------------------------
1 | #ifdef __arm64__
2 |
3 | #include "ffi_arm64.h"
4 |
5 |
6 | #endif
7 | #ifdef __i386__
8 |
9 | #include "ffi_i386.h"
10 |
11 |
12 | #endif
13 | #ifdef __arm__
14 |
15 | #include "ffi_arm.h"
16 |
17 |
18 | #endif
19 | #ifdef __x86_64__
20 |
21 | #include "ffi_x86_64.h"
22 |
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/libffi/ffitarget.h:
--------------------------------------------------------------------------------
1 | #ifdef __arm64__
2 |
3 | #include "ffitarget_arm64.h"
4 |
5 |
6 | #endif
7 | #ifdef __i386__
8 |
9 | #include "ffitarget_i386.h"
10 |
11 |
12 | #endif
13 | #ifdef __arm__
14 |
15 | #include "ffitarget_arm.h"
16 |
17 |
18 | #endif
19 | #ifdef __x86_64__
20 |
21 | #include "ffitarget_x86_64.h"
22 |
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/libffi/ffitarget_arm.h:
--------------------------------------------------------------------------------
1 | /* -----------------------------------------------------------------*-C-*-
2 | ffitarget.h - Copyright (c) 2012 Anthony Green
3 | Copyright (c) 2010 CodeSourcery
4 | Copyright (c) 1996-2003 Red Hat, Inc.
5 |
6 | Target configuration macros for ARM.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining
9 | a copy of this software and associated documentation files (the
10 | ``Software''), to deal in the Software without restriction, including
11 | without limitation the rights to use, copy, modify, merge, publish,
12 | distribute, sublicense, and/or sell copies of the Software, and to
13 | permit persons to whom the Software is furnished to do so, subject to
14 | the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included
17 | in all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 | DEALINGS IN THE SOFTWARE.
27 |
28 | ----------------------------------------------------------------------- */
29 |
30 | #ifndef LIBFFI_TARGET_H
31 | #define LIBFFI_TARGET_H
32 |
33 | #ifndef LIBFFI_H
34 | #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
35 | #endif
36 |
37 | #ifndef LIBFFI_ASM
38 | typedef unsigned long ffi_arg;
39 | typedef signed long ffi_sarg;
40 |
41 | typedef enum ffi_abi {
42 | FFI_FIRST_ABI = 0,
43 | FFI_SYSV,
44 | FFI_VFP,
45 | FFI_LAST_ABI,
46 | #ifdef __ARM_PCS_VFP
47 | FFI_DEFAULT_ABI = FFI_VFP,
48 | #else
49 | FFI_DEFAULT_ABI = FFI_SYSV,
50 | #endif
51 | } ffi_abi;
52 | #endif
53 |
54 | #define FFI_EXTRA_CIF_FIELDS \
55 | int vfp_used; \
56 | unsigned short vfp_reg_free, vfp_nargs; \
57 | signed char vfp_args[16] \
58 |
59 | #define FFI_TARGET_SPECIFIC_VARIADIC
60 | #define FFI_TARGET_HAS_COMPLEX_TYPE
61 |
62 | /* ---- Definitions for closures ----------------------------------------- */
63 |
64 | #define FFI_CLOSURES 1
65 | #define FFI_GO_CLOSURES 1
66 | #define FFI_NATIVE_RAW_API 0
67 |
68 | #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE
69 |
70 | #ifdef __MACH__
71 | #define FFI_TRAMPOLINE_SIZE 12
72 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET 8
73 | #else
74 | #error "No trampoline table implementation"
75 | #endif
76 |
77 | #else
78 | #define FFI_TRAMPOLINE_SIZE 12
79 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE
80 | #endif
81 |
82 | #endif
83 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/libffi/ffitarget_arm64.h:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | ``Software''), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
21 |
22 | #ifndef LIBFFI_TARGET_H
23 | #define LIBFFI_TARGET_H
24 |
25 | #ifndef LIBFFI_H
26 | #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
27 | #endif
28 |
29 | #ifndef LIBFFI_ASM
30 | #ifdef __ILP32__
31 | #define FFI_SIZEOF_ARG 8
32 | #define FFI_SIZEOF_JAVA_RAW 4
33 | typedef unsigned long long ffi_arg;
34 | typedef signed long long ffi_sarg;
35 | #else
36 | typedef unsigned long ffi_arg;
37 | typedef signed long ffi_sarg;
38 | #endif
39 |
40 | typedef enum ffi_abi
41 | {
42 | FFI_FIRST_ABI = 0,
43 | FFI_SYSV,
44 | FFI_LAST_ABI,
45 | FFI_DEFAULT_ABI = FFI_SYSV
46 | } ffi_abi;
47 | #endif
48 |
49 | /* ---- Definitions for closures ----------------------------------------- */
50 |
51 | #define FFI_CLOSURES 1
52 | #define FFI_NATIVE_RAW_API 0
53 |
54 | #if defined (FFI_EXEC_TRAMPOLINE_TABLE) && FFI_EXEC_TRAMPOLINE_TABLE
55 |
56 | #ifdef __MACH__
57 | #define FFI_TRAMPOLINE_SIZE 16
58 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET 16
59 | #else
60 | #error "No trampoline table implementation"
61 | #endif
62 |
63 | #else
64 | #define FFI_TRAMPOLINE_SIZE 24
65 | #define FFI_TRAMPOLINE_CLOSURE_OFFSET FFI_TRAMPOLINE_SIZE
66 | #endif
67 |
68 | /* ---- Internal ---- */
69 |
70 | #if defined (__APPLE__)
71 | #define FFI_TARGET_SPECIFIC_VARIADIC
72 | #define FFI_EXTRA_CIF_FIELDS unsigned aarch64_nfixedargs
73 | #else
74 | /* iOS reserves x18 for the system. Disable Go closures until
75 | a new static chain is chosen. */
76 | #define FFI_GO_CLOSURES 1
77 | #endif
78 |
79 | #define FFI_TARGET_HAS_COMPLEX_TYPE
80 |
81 | #endif
82 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/libffi/ffitarget_i386.h:
--------------------------------------------------------------------------------
1 | #ifdef __i386__
2 |
3 | /* -----------------------------------------------------------------*-C-*-
4 | ffitarget.h - Copyright (c) 2012, 2014 Anthony Green
5 | Copyright (c) 1996-2003, 2010 Red Hat, Inc.
6 | Copyright (C) 2008 Free Software Foundation, Inc.
7 |
8 | Target configuration macros for x86 and x86-64.
9 |
10 | Permission is hereby granted, free of charge, to any person obtaining
11 | a copy of this software and associated documentation files (the
12 | ``Software''), to deal in the Software without restriction, including
13 | without limitation the rights to use, copy, modify, merge, publish,
14 | distribute, sublicense, and/or sell copies of the Software, and to
15 | permit persons to whom the Software is furnished to do so, subject to
16 | the following conditions:
17 |
18 | The above copyright notice and this permission notice shall be included
19 | in all copies or substantial portions of the Software.
20 |
21 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
22 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 | DEALINGS IN THE SOFTWARE.
29 |
30 | ----------------------------------------------------------------------- */
31 |
32 | #ifndef LIBFFI_TARGET_H
33 | #define LIBFFI_TARGET_H
34 |
35 | #ifndef LIBFFI_H
36 | #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
37 | #endif
38 |
39 | /* ---- System specific configurations ----------------------------------- */
40 |
41 | /* For code common to all platforms on x86 and x86_64. */
42 | #define X86_ANY
43 |
44 | #if defined (X86_64) && defined (__i386__)
45 | #undef X86_64
46 | #define X86
47 | #endif
48 |
49 | #ifdef X86_WIN64
50 | #define FFI_SIZEOF_ARG 8
51 | #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */
52 | #endif
53 |
54 | #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
55 | #define FFI_TARGET_HAS_COMPLEX_TYPE
56 |
57 | /* ---- Generic type definitions ----------------------------------------- */
58 |
59 | #ifndef LIBFFI_ASM
60 | #ifdef X86_WIN64
61 | #ifdef _MSC_VER
62 | typedef unsigned __int64 ffi_arg;
63 | typedef __int64 ffi_sarg;
64 | #else
65 | typedef unsigned long long ffi_arg;
66 | typedef long long ffi_sarg;
67 | #endif
68 | #else
69 | #if defined __x86_64__ && defined __ILP32__
70 | #define FFI_SIZEOF_ARG 8
71 | #define FFI_SIZEOF_JAVA_RAW 4
72 | typedef unsigned long long ffi_arg;
73 | typedef long long ffi_sarg;
74 | #else
75 | typedef unsigned long ffi_arg;
76 | typedef signed long ffi_sarg;
77 | #endif
78 | #endif
79 |
80 | typedef enum ffi_abi {
81 | FFI_FIRST_ABI = 0,
82 |
83 | /* ---- Intel x86 Win32 ---------- */
84 | #ifdef X86_WIN32
85 | FFI_SYSV,
86 | FFI_STDCALL,
87 | FFI_THISCALL,
88 | FFI_FASTCALL,
89 | FFI_MS_CDECL,
90 | FFI_PASCAL,
91 | FFI_REGISTER,
92 | FFI_LAST_ABI,
93 | #ifdef _MSC_VER
94 | FFI_DEFAULT_ABI = FFI_MS_CDECL
95 | #else
96 | FFI_DEFAULT_ABI = FFI_SYSV
97 | #endif
98 |
99 | #elif defined(X86_WIN64)
100 | FFI_WIN64,
101 | FFI_LAST_ABI,
102 | FFI_DEFAULT_ABI = FFI_WIN64
103 |
104 | #else
105 | /* ---- Intel x86 and AMD x86-64 - */
106 | FFI_SYSV,
107 | FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */
108 | FFI_THISCALL,
109 | FFI_FASTCALL,
110 | FFI_STDCALL,
111 | FFI_PASCAL,
112 | FFI_REGISTER,
113 | FFI_LAST_ABI,
114 | #if defined(__i386__) || defined(__i386)
115 | FFI_DEFAULT_ABI = FFI_SYSV
116 | #else
117 | FFI_DEFAULT_ABI = FFI_UNIX64
118 | #endif
119 | #endif
120 | } ffi_abi;
121 | #endif
122 |
123 | /* ---- Definitions for closures ----------------------------------------- */
124 |
125 | #define FFI_CLOSURES 1
126 | #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1)
127 | #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2)
128 | #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3)
129 | #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4)
130 |
131 | #if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
132 | #define FFI_TRAMPOLINE_SIZE 24
133 | #define FFI_NATIVE_RAW_API 0
134 | #else
135 | #ifdef X86_WIN32
136 | #define FFI_TRAMPOLINE_SIZE 52
137 | #else
138 | #ifdef X86_WIN64
139 | #define FFI_TRAMPOLINE_SIZE 29
140 | #define FFI_NATIVE_RAW_API 0
141 | #define FFI_NO_RAW_API 1
142 | #else
143 | #define FFI_TRAMPOLINE_SIZE 10
144 | #endif
145 | #endif
146 | #ifndef X86_WIN64
147 | #define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
148 | #endif
149 | #endif
150 |
151 | #endif
152 |
153 |
154 |
155 | #endif
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/libffi/ffitarget_x86_64.h:
--------------------------------------------------------------------------------
1 | /* -----------------------------------------------------------------*-C-*-
2 | ffitarget.h - Copyright (c) 2012, 2014 Anthony Green
3 | Copyright (c) 1996-2003, 2010 Red Hat, Inc.
4 | Copyright (C) 2008 Free Software Foundation, Inc.
5 |
6 | Target configuration macros for x86 and x86-64.
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining
9 | a copy of this software and associated documentation files (the
10 | ``Software''), to deal in the Software without restriction, including
11 | without limitation the rights to use, copy, modify, merge, publish,
12 | distribute, sublicense, and/or sell copies of the Software, and to
13 | permit persons to whom the Software is furnished to do so, subject to
14 | the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included
17 | in all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 | DEALINGS IN THE SOFTWARE.
27 |
28 | ----------------------------------------------------------------------- */
29 |
30 | #ifndef LIBFFI_TARGET_H
31 | #define LIBFFI_TARGET_H
32 |
33 | #ifndef LIBFFI_H
34 | #error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
35 | #endif
36 |
37 | /* ---- System specific configurations ----------------------------------- */
38 |
39 | /* For code common to all platforms on x86 and x86_64. */
40 | #define X86_ANY
41 |
42 | #if defined (X86_64) && defined (__i386__)
43 | #undef X86_64
44 | #define X86
45 | #endif
46 |
47 | #ifdef X86_WIN64
48 | #define FFI_SIZEOF_ARG 8
49 | #define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */
50 | #endif
51 |
52 | #define FFI_TARGET_SPECIFIC_STACK_SPACE_ALLOCATION
53 | #ifndef _MSC_VER
54 | #define FFI_TARGET_HAS_COMPLEX_TYPE
55 | #endif
56 |
57 | /* ---- Generic type definitions ----------------------------------------- */
58 |
59 | #ifndef LIBFFI_ASM
60 | #ifdef X86_WIN64
61 | #ifdef _MSC_VER
62 | typedef unsigned __int64 ffi_arg;
63 | typedef __int64 ffi_sarg;
64 | #else
65 | typedef unsigned long long ffi_arg;
66 | typedef long long ffi_sarg;
67 | #endif
68 | #else
69 | #if defined __x86_64__ && defined __ILP32__
70 | #define FFI_SIZEOF_ARG 8
71 | #define FFI_SIZEOF_JAVA_RAW 4
72 | typedef unsigned long long ffi_arg;
73 | typedef long long ffi_sarg;
74 | #else
75 | typedef unsigned long ffi_arg;
76 | typedef signed long ffi_sarg;
77 | #endif
78 | #endif
79 |
80 | typedef enum ffi_abi {
81 | #if defined(X86_WIN64)
82 | FFI_FIRST_ABI = 0,
83 | FFI_WIN64,
84 | FFI_LAST_ABI,
85 | FFI_DEFAULT_ABI = FFI_WIN64
86 |
87 | #elif defined(X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
88 | FFI_FIRST_ABI = 1,
89 | FFI_UNIX64,
90 | FFI_WIN64,
91 | FFI_EFI64 = FFI_WIN64,
92 | FFI_LAST_ABI,
93 | FFI_DEFAULT_ABI = FFI_UNIX64
94 |
95 | #elif defined(X86_WIN32)
96 | FFI_FIRST_ABI = 0,
97 | FFI_SYSV = 1,
98 | FFI_STDCALL = 2,
99 | FFI_THISCALL = 3,
100 | FFI_FASTCALL = 4,
101 | FFI_MS_CDECL = 5,
102 | FFI_PASCAL = 6,
103 | FFI_REGISTER = 7,
104 | FFI_LAST_ABI,
105 | FFI_DEFAULT_ABI = FFI_MS_CDECL
106 | #else
107 | FFI_FIRST_ABI = 0,
108 | FFI_SYSV = 1,
109 | FFI_THISCALL = 3,
110 | FFI_FASTCALL = 4,
111 | FFI_STDCALL = 5,
112 | FFI_PASCAL = 6,
113 | FFI_REGISTER = 7,
114 | FFI_MS_CDECL = 8,
115 | FFI_LAST_ABI,
116 | FFI_DEFAULT_ABI = FFI_SYSV
117 | #endif
118 | } ffi_abi;
119 | #endif
120 |
121 | /* ---- Definitions for closures ----------------------------------------- */
122 |
123 | #define FFI_CLOSURES 1
124 | #define FFI_GO_CLOSURES 1
125 |
126 | #define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1)
127 | #define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2)
128 | #define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3)
129 | #define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4)
130 |
131 | #if defined (X86_64) || defined(X86_WIN64) \
132 | || (defined (__x86_64__) && defined (X86_DARWIN))
133 | # define FFI_TRAMPOLINE_SIZE 24
134 | # define FFI_NATIVE_RAW_API 0
135 | #else
136 | # define FFI_TRAMPOLINE_SIZE 12
137 | # define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
138 | #endif
139 |
140 | #endif
141 |
142 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/Vendor/OCEval/libffi/libffi.a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letqingbin/DynamicOC/8824d9695e14415239b5410ad0f00df88677180f/DynamicOC/DynamicOC/Vendor/OCEval/libffi/libffi.a
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/23.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 | @end
14 |
15 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/16.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 |
11 | @interface ViewController ()
12 | @end
13 |
14 | @implementation ViewController
15 |
16 | - (void)viewDidLoad
17 | {
18 | [super viewDidLoad];
19 | }
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOC/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // DynamicOC
4 | //
5 | // Created by dKingbin on 2019/7/23.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOCUITests/ArithmeticTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // ArithmeticTest.m
3 | // DynamicOCUITests
4 | //
5 | // Created by dKingbin on 2019/7/23.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "ASTHeader.h"
12 | #import "ASTUtil.h"
13 | #import "OCCfuntionHelper.h"
14 |
15 | @interface ArithmeticTest : XCTestCase
16 |
17 | @end
18 |
19 | @implementation ArithmeticTest
20 |
21 | - (void)testAdd
22 | {
23 | NSString* text = @"int i=1;int j=2;i=i+j;return i;";
24 | ASTNode* root = [ASTUtil parseString:text];
25 |
26 | ASTVariable* result = [root execute];
27 | NSAssert([result.value doubleValue] == 3, nil);
28 | }
29 |
30 | - (void)testSub
31 | {
32 | NSString* text = @"int i=10;int j=2;i=i-j;return i;";
33 | ASTNode* root = [ASTUtil parseString:text];
34 |
35 | ASTVariable* result = [root execute];
36 | NSAssert([result.value doubleValue] == 8, nil);
37 | }
38 |
39 | - (void)testSub1
40 | {
41 | NSString* text = @"int i=10;int j=2;i=j-i;return i;";
42 | ASTNode* root = [ASTUtil parseString:text];
43 |
44 | ASTVariable* result = [root execute];
45 | NSAssert([result.value doubleValue] == -8, nil);
46 | }
47 |
48 | - (void)testMul
49 | {
50 | NSString* text = @"int i=3;int j=2;i=i*j;return i;";
51 | ASTNode* root = [ASTUtil parseString:text];
52 |
53 | ASTVariable* result = [root execute];
54 | NSAssert([result.value doubleValue] == 6, nil);
55 | }
56 |
57 | - (void)testMul1
58 | {
59 | NSString* text = @"int i=0;int j=2;i=i*j;return i;";
60 | ASTNode* root = [ASTUtil parseString:text];
61 |
62 | ASTVariable* result = [root execute];
63 | NSAssert([result.value doubleValue] == 0, nil);
64 | }
65 |
66 | - (void)testDiv
67 | {
68 | NSString* text = @"int i=4;int j=2;i=i/j;return i;";
69 | ASTNode* root = [ASTUtil parseString:text];
70 |
71 | ASTVariable* result = [root execute];
72 | NSAssert([result.value doubleValue] == 2, nil);
73 | }
74 |
75 | - (void)testRemainder
76 | {
77 | NSString* text = @"int i=5;int j=2;i=i%j;return i;";
78 | ASTNode* root = [ASTUtil parseString:text];
79 |
80 | ASTVariable* result = [root execute];
81 | NSAssert([result.value doubleValue] == 1, nil);
82 | }
83 |
84 | - (void)testRightShitf
85 | {
86 | NSString* text = @"int i=20;int j=2;i=i>>j;return i;";
87 | ASTNode* root = [ASTUtil parseString:text];
88 |
89 | ASTVariable* result = [root execute];
90 | NSAssert([result.value doubleValue] == 5, nil);
91 | }
92 |
93 | - (void)testLeftShitf
94 | {
95 | NSString* text = @"int i=5;int j=2;i=i<
10 |
11 | #import "ASTHeader.h"
12 | #import "ASTUtil.h"
13 | #import "OCCfuntionHelper.h"
14 | #import
15 | #import
16 |
17 | @interface CallCFunctionTest : XCTestCase
18 |
19 | @end
20 |
21 | @implementation CallCFunctionTest
22 |
23 | int funcWithNoArgs()
24 | {
25 | return 1024;
26 | }
27 |
28 | int funcWithOneArg(int value)
29 | {
30 | return value;
31 | }
32 |
33 | NSString* funcWithOCArg(NSString* str)
34 | {
35 | return str;
36 | }
37 |
38 | - (void)testCallCFunctionWithNoArgs
39 | {
40 | [OCCfuntionHelper defineCFunction:@"funcWithNoArgs" types:@"int"];
41 |
42 | NSString* text = @"int i = funcWithNoArgs(); return i;";
43 | ASTNode* root = [ASTUtil parseString:text];
44 |
45 | ASTVariable* result = [root execute];
46 | NSAssert([result.value doubleValue] == 1024, nil);
47 | }
48 |
49 | - (void)testCallCFunctionWithOneArg
50 | {
51 | [OCCfuntionHelper defineCFunction:@"funcWithOneArg" types:@"int,int"];
52 |
53 | NSString* text = @"return funcWithOneArg(1024);";
54 | ASTNode* root = [ASTUtil parseString:text];
55 |
56 | ASTVariable* result = [root execute];
57 | NSAssert([result.value doubleValue] == 1024, nil);
58 | }
59 |
60 | - (void)testCallCFunctionWithOCArg
61 | {
62 | [OCCfuntionHelper defineCFunction:@"funcWithOCArg" types:@"NSString*,NSString*"];
63 |
64 | NSString* text = @"return funcWithOCArg(@\"hello iOS!\");";
65 | ASTNode* root = [ASTUtil parseString:text];
66 |
67 | ASTVariable* result = [root execute];
68 | NSAssert([result.value isEqualToString:@"hello iOS!"], nil);
69 | }
70 |
71 | - (void)testOCCFunctionCall
72 | {
73 | [OCCfuntionHelper defineCFunction:@"NSClassFromString" types:@"Class, NSString *"];
74 |
75 | NSString* text = @"Class cls = NSClassFromString(@\"NSObject\"); return cls;";
76 | ASTNode* root = [ASTUtil parseString:text];
77 |
78 | ASTVariable* result = [root execute];
79 | NSAssert(result.value == [NSObject class], nil);
80 | }
81 |
82 | - (void)testOCCFunctionCall1
83 | {
84 | [OCCfuntionHelper defineCFunction:@"NSSelectorFromString" types:@"SEL, NSString *"];
85 |
86 | NSString* text = @"SEL sel = NSSelectorFromString(@\"alloc\"); return sel;";
87 | ASTNode* root = [ASTUtil parseString:text];
88 |
89 | ASTVariable* result = [root execute];
90 | SEL sel = [result.value pointerValue];
91 | NSAssert([NSStringFromSelector(sel) isEqualToString:@"alloc"], nil);
92 | }
93 |
94 | - (void)testOCCFunctionCallWithStruct
95 | {
96 | NSString* text = @"CGPoint point = CGPointMake(2,3); return point;";
97 | ASTNode* root = [ASTUtil parseString:text];
98 |
99 | ASTVariable* result = [root execute];
100 | CGPoint point = [result.value CGPointValue];
101 | NSAssert(point.x == 2 && point.y == 3, nil);
102 | }
103 |
104 | - (void)testOCCFunctionCallWithStruct1
105 | {
106 | NSString* text = @"CGRect rect = CGRectMake(1,2,3,4); return rect;";
107 | ASTNode* root = [ASTUtil parseString:text];
108 |
109 | ASTVariable* result = [root execute];
110 | CGRect rect = [result.value CGRectValue];
111 | NSAssert(CGRectEqualToRect(rect, CGRectMake(1, 2, 3, 4)), nil);
112 | }
113 |
114 | - (void)testOCCFunctionCallWithStruct2
115 | {
116 | NSString* text = @"CGRect rect = CGRectZero(); return rect;";
117 | ASTNode* root = [ASTUtil parseString:text];
118 |
119 | ASTVariable* result = [root execute];
120 | CGRect rect = [result.value CGRectValue];
121 | NSAssert(CGRectEqualToRect(rect, CGRectZero), nil);
122 | }
123 |
124 | - (void)testOCCFunctionCallWithStruct3
125 | {
126 | NSString* text = @"CGSize size = CGSizeZero(); return size;";
127 | ASTNode* root = [ASTUtil parseString:text];
128 |
129 | ASTVariable* result = [root execute];
130 | CGSize size = [result.value CGSizeValue];
131 | NSAssert(CGSizeEqualToSize(size, CGSizeZero), nil);
132 | }
133 |
134 | - (void)testOCCFunctionCallWithStruct4
135 | {
136 | NSString* text = @"CGPoint point = CGPointZero(); return point;";
137 | ASTNode* root = [ASTUtil parseString:text];
138 |
139 | ASTVariable* result = [root execute];
140 | CGPoint point = [result.value CGPointValue];
141 | NSAssert(CGPointEqualToPoint(point, CGPointZero), nil);
142 | }
143 |
144 | - (void)testOCCFunctionCallWithStruct5
145 | {
146 | NSString* text = @"UIEdgeInsets inset = UIEdgeInsetsZero(); return inset;";
147 | ASTNode* root = [ASTUtil parseString:text];
148 |
149 | ASTVariable* result = [root execute];
150 | UIEdgeInsets inset = [result.value UIEdgeInsetsValue];
151 | NSAssert(UIEdgeInsetsEqualToEdgeInsets(inset, UIEdgeInsetsZero), nil);
152 | }
153 |
154 | - (void)testGetMethodImp
155 | {
156 | [OCCfuntionHelper defineCFunction:@"NSClassFromString" types:@"Class, NSString *"];
157 | [OCCfuntionHelper defineCFunction:@"NSSelectorFromString" types:@"SEL,NSString *"];
158 | [OCCfuntionHelper defineCFunction:@"class_getMethodImplementation" types:@"IMP,Class,SEL"];
159 |
160 | NSString* text = @"Class cls = NSClassFromString(@\"NSObject\");\
161 | SEL sel = NSSelectorFromString(@\"copy\");\
162 | IMP imp = class_getMethodImplementation(cls,sel);\
163 | return imp;";
164 |
165 | ASTNode* root = [ASTUtil parseString:text];
166 |
167 | ASTVariable* result = [root execute];
168 | IMP imp = [result.value pointerValue];
169 | Method m = class_getInstanceMethod(NSObject.class, @selector(copy));
170 | IMP imp2 = method_getImplementation(m);
171 | NSAssert(imp == imp2, nil);
172 | }
173 |
174 | - (void)testAddMethod
175 | {
176 | [OCCfuntionHelper defineCFunction:@"NSClassFromString" types:@"Class, NSString *"];
177 | [OCCfuntionHelper defineCFunction:@"NSSelectorFromString" types:@"SEL,NSString *"];
178 | [OCCfuntionHelper defineCFunction:@"class_getMethodImplementation" types:@"IMP,Class,SEL"];
179 | [OCCfuntionHelper defineCFunction:@"class_addMethod" types:@"BOOL,Class,SEL,IMP,char *"];
180 |
181 | NSString* text = @" Class cls = NSClassFromString(@\"UIView\");\
182 | SEL sel = NSSelectorFromString(@\"setNeedsDisplay\");\
183 | IMP imp = class_getMethodImplementation(cls,sel);\
184 | Class cls2 = NSClassFromString(@\"NSObject\");\
185 | BOOL didAdd = class_addMethod(cls2,sel,imp,\"v:\"); \
186 | return didAdd;";
187 |
188 | ASTNode* root = [ASTUtil parseString:text];
189 | ASTVariable* result = [root execute];
190 | NSAssert([result.value boolValue], nil);
191 |
192 | NSMethodSignature *methodSignature = [NSObject instanceMethodSignatureForSelector:NSSelectorFromString(@"setNeedsDisplay")];
193 | NSAssert(methodSignature != nil, nil);
194 | }
195 |
196 | - (void)testAssocateObject
197 | {
198 | [OCCfuntionHelper defineCFunction:@"objc_setAssociatedObject" types:@"void,id,void *,id,unsigned int"];
199 | [OCCfuntionHelper defineCFunction:@"objc_getAssociatedObject" types:@"id,id,void *"];
200 |
201 | NSString* text = @"NSObject *object = [[NSObject alloc] init];\
202 | NSString* key = @\"key\"; \
203 | objc_setAssociatedObject(object, key, @\"1024\", 1);\
204 | return objc_getAssociatedObject(object,key);";
205 |
206 | ASTNode* root = [ASTUtil parseString:text];
207 | ASTVariable* result = [root execute];;
208 |
209 | NSAssert([result.value isEqualToString:@"1024"], nil);
210 | }
211 |
212 | - (void)testAssocateObject1
213 | {
214 | [OCCfuntionHelper defineCFunction:@"objc_setAssociatedObject" types:@"void,id,void *,id,unsigned int"];
215 | [OCCfuntionHelper defineCFunction:@"objc_getAssociatedObject" types:@"id,id,void *"];
216 |
217 | NSString* text = @" NSObject *object = [[NSObject alloc] init];\
218 | NSObject* key = [[NSObject alloc]init]; \
219 | objc_setAssociatedObject(object, key, @\"1024\", 1);\
220 | return objc_getAssociatedObject(object, key);";
221 |
222 | ASTNode* root = [ASTUtil parseString:text];
223 | ASTVariable* result = [root execute];
224 |
225 | NSAssert([result.value isEqualToString:@"1024"], nil);
226 | }
227 |
228 | - (void)testAssocateObject2
229 | {
230 | [OCCfuntionHelper defineCFunction:@"objc_setAssociatedObject" types:@"void,id,void *,id,unsigned int"];
231 | [OCCfuntionHelper defineCFunction:@"objc_getAssociatedObject" types:@"id,id,void *"];
232 |
233 | NSString* text = @"NSObject *object = [[NSObject alloc] init];\
234 | UIView* view = [[UIView alloc]init]; \
235 | objc_setAssociatedObject(object, view, @\"2048\", 1);\
236 | return objc_getAssociatedObject(object,view);";
237 |
238 | ASTNode* root = [ASTUtil parseString:text];
239 | ASTVariable* result = [root execute];
240 |
241 | NSAssert([result.value isEqualToString:@"2048"], nil);
242 | }
243 |
244 | - (void)testAssocateObject3
245 | {
246 | [OCCfuntionHelper defineCFunction:@"objc_setAssociatedObject" types:@"void,id,void *,id,unsigned int"];
247 | [OCCfuntionHelper defineCFunction:@"objc_getAssociatedObject" types:@"id,id,void *"];
248 |
249 | NSString* text = @" \
250 | NSString* key = @\"testAssocateObject3\"; \
251 | objc_setAssociatedObject(XCTestCase.class, key, @\"1024\", 1);\
252 | return objc_getAssociatedObject(XCTestCase.class, key);";
253 | ASTNode* root = [ASTUtil parseString:text];
254 |
255 | ASTVariable* result = [root execute];
256 |
257 | NSAssert([result.value isEqualToString:@"1024"], nil);
258 | }
259 |
260 | - (void)testAssocateObject4
261 | {
262 | [OCCfuntionHelper defineCFunction:@"objc_setAssociatedObject" types:@"void,id,void *,id,unsigned int"];
263 | [OCCfuntionHelper defineCFunction:@"objc_getAssociatedObject" types:@"id,id,void *"];
264 |
265 | NSString* text = @" \
266 | NSString* key = @\"testAssocateObject4\"; \
267 | objc_setAssociatedObject([XCTestCase class], key, @\"1024\", 1);\
268 | return objc_getAssociatedObject([XCTestCase class], key);";
269 | ASTNode* root = [ASTUtil parseString:text];
270 |
271 | ASTVariable* result = [root execute];
272 |
273 | NSAssert([result.value isEqualToString:@"1024"], nil);
274 | }
275 |
276 | //TODO
277 | //- (void)testDispatch
278 | //{
279 | // NSString* text = @" \
280 | // dispatch_after(3, ^(int _){ \
281 | // int i = 10; \
282 | // });";
283 | // static ASTNode* root;
284 | // root = [ASTUtil parseString:text];
285 | //
286 | // [root execute];
287 | //}
288 |
289 | @end
290 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOCUITests/CallOCFunctionTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // CallOCFunctionTest.m
3 | // DynamicOCUITests
4 | //
5 | // Created by dKingbin on 2019/7/23.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "ASTHeader.h"
12 | #import "ASTUtil.h"
13 | #import "OCCfuntionHelper.h"
14 |
15 | @interface CallOCFunctionTest : XCTestCase
16 |
17 | @end
18 |
19 | @implementation CallOCFunctionTest
20 |
21 | + (int)echo
22 | {
23 | return 1024;
24 | }
25 |
26 | + (int)echoInteger:(int)value
27 | {
28 | return value;
29 | }
30 |
31 | + (float)echoFloat:(float)value
32 | {
33 | return value;
34 | }
35 |
36 | + (NSString*)echoString:(NSString*)value
37 | {
38 | return value;
39 | }
40 |
41 | + (float)echo:(float)value1 value2:(float)value2 value3:(float)value3
42 | {
43 | return value1 + value2 + value3;
44 | }
45 |
46 | + (float)echo:(float)value1 :(float)value2 :(float)value3
47 | {
48 | return value1 + value2 + value3;
49 | }
50 |
51 | - (CGRect)frame
52 | {
53 | return CGRectMake(0, 0, 375, 667);
54 | }
55 |
56 | - (void)testSelf
57 | {
58 | [ASTUtil registerVariableForYacc:@"self"];
59 |
60 | NSMutableDictionary* ctx = [NSMutableDictionary dictionary];
61 | ASTVariable* varSelf = [[ASTVariable alloc]init];
62 | varSelf.value = self;
63 | varSelf.type = ASTNodeTypeVariable;
64 | [ctx setObject:varSelf forKey:@"self"];
65 |
66 | NSString* text = @"return [self frame].size.width;";
67 |
68 | ASTNode* root = [ASTUtil parseString:text];
69 | [root.context pushDefinedContext:ctx];
70 |
71 | ASTVariable* result = [root execute];
72 |
73 | NSAssert([result.value doubleValue] == 375, nil);
74 | }
75 |
76 | - (void)testCallOCFunction
77 | {
78 | NSString* text = @"return [CallOCFunctionTest echo];";
79 | ASTNode* root = [ASTUtil parseString:text];
80 |
81 | ASTVariable* result = [root execute];
82 | NSAssert([result.value doubleValue] == 1024, nil);
83 | }
84 |
85 | - (void)testCallOCFunction1
86 | {
87 | NSString* text = @"return [CallOCFunctionTest echoInteger:1024];";
88 | ASTNode* root = [ASTUtil parseString:text];
89 |
90 | ASTVariable* result = [root execute];
91 | NSAssert([result.value doubleValue] == 1024, nil);
92 | }
93 |
94 | - (void)testCallOCFunction2
95 | {
96 | NSString* text = @"return [CallOCFunctionTest echoFloat:6.666];";
97 | ASTNode* root = [ASTUtil parseString:text];
98 |
99 | ASTVariable* result = [root execute];
100 | NSAssert(fabs([result.value floatValue]-6.666) <= 0.001 , nil);
101 | }
102 |
103 | - (void)testCallOCFunction3
104 | {
105 | NSString* text = @"return [CallOCFunctionTest echoString:@\"DynamicOC!\"];";
106 | ASTNode* root = [ASTUtil parseString:text];
107 |
108 | ASTVariable* result = [root execute];
109 | NSAssert([@"DynamicOC!" isEqualToString:result.value], nil);
110 | }
111 |
112 | - (void)testCallOCFunction4
113 | {
114 | NSString* text = @"return [CallOCFunctionTest echo:1.0 value2:2.0 value3:3.0];";
115 | ASTNode* root = [ASTUtil parseString:text];
116 |
117 | ASTVariable* result = [root execute];
118 | NSAssert(fabs([result.value floatValue]-6.0) <= 0.001, nil);
119 | }
120 |
121 | - (void)testCallOCFunction5
122 | {
123 | NSString* text = @"return [CallOCFunctionTest echo:1.0 :2.0 :3.0];";
124 | ASTNode* root = [ASTUtil parseString:text];
125 |
126 | ASTVariable* result = [root execute];
127 | NSAssert(fabs([result.value floatValue]-6.0) <= 0.001, nil);
128 | }
129 |
130 | - (void)testCallOCFunction6
131 | {
132 | NSString* text = @"NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@(1024),@\"key1\",@(2),@\"key2\", nil]; return dict[@\"key1\"];";
133 | ASTNode* root = [ASTUtil parseString:text];
134 |
135 | ASTVariable* result = [root execute];
136 | NSAssert([result.value doubleValue] == 1024, nil);
137 | }
138 |
139 | - (void)testCallOCFunction7
140 | {
141 | NSString* text = @"NSString *str = @\"a\";\
142 | NSString *str2 = [str stringByAppendingFormat:@\"%@,%@\",@\"2\",@(4+5*2)];\
143 | return str2;";
144 | ASTNode* root = [ASTUtil parseString:text];
145 |
146 | ASTVariable* result = [root execute];
147 | NSAssert([result.value isEqualToString:@"a2,14"], nil);
148 | }
149 |
150 | @end
151 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOCUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOCUITests/OCBlockTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCBlockTest.m
3 | // DynamicOCUITests
4 | //
5 | // Created by dKingbin on 2019/7/26.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "ASTHeader.h"
12 | #import "ASTUtil.h"
13 | #import "OCCfuntionHelper.h"
14 | #import "ASTVariable.h"
15 |
16 | @interface OCBlockTest : XCTestCase
17 |
18 | @end
19 |
20 | @implementation OCBlockTest
21 |
22 | - (void)testBlock
23 | {
24 | NSString* text = @"__block int result = 0;\
25 | UIView* view = [[UIView alloc]init];\
26 | void(^blk)(NSInteger toAdd) = ^(NSInteger toAdd){\
27 | result = result + toAdd;\
28 | view.tag = 1024;\
29 | };\
30 | blk(3);\
31 | return view.tag;";
32 |
33 | ASTNode* root = [ASTUtil parseString:text];
34 |
35 | ASTVariable* result = [root execute];
36 | NSAssert([result.value doubleValue] == 1024, nil);
37 | }
38 |
39 | - (void)testBlock1
40 | {
41 | NSString* text = @"__block int result = 0;\
42 | UIView* view = [[UIView alloc]init];\
43 | void(^blk)(NSInteger toAdd) = ^(NSInteger toAdd){\
44 | result = result + toAdd;\
45 | view.tag = 1024;\
46 | };\
47 | blk(666);\
48 | return result;";
49 |
50 | ASTNode* root = [ASTUtil parseString:text];
51 |
52 | ASTVariable* result = [root execute];
53 | NSAssert([result.value doubleValue] == 666, nil);
54 | }
55 |
56 | - (void)testBlock2
57 | {
58 | NSString *text = @"NSArray *content = @[@6,@7,@8,@9,@1,@2,@3,@4];\
59 | __block NSInteger result = 0;\
60 | [content enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {\
61 | result = result + 1;\
62 | }];\
63 | return result;";
64 |
65 | ASTNode* root = [ASTUtil parseString:text];
66 |
67 | ASTVariable* result = [root execute];
68 | NSAssert([result.value doubleValue] == 8, nil);
69 | }
70 |
71 | - (void)testBlock3
72 | {
73 | NSString *text = @"NSArray *content = @[@6,@7,@8,@9,@1,@2,@3,@4];\
74 | NSComparisonResult (^comparison)(id obj1, id obj2) = ^NSComparisonResult(id obj1, id obj2) {\
75 | return [obj1 doubleValue] > [obj2 doubleValue];\
76 | };\
77 | content = [content sortedArrayUsingComparator:comparison];\
78 | return content;";
79 |
80 | ASTNode* root = [ASTUtil parseString:text];
81 |
82 | ASTVariable* result = [root execute];
83 | NSAssert([result.value[6] intValue] == 8, nil);
84 | }
85 |
86 | - (void)testBlock4
87 | {
88 | NSString *text = @"^{};";
89 |
90 | ASTNode* root = [ASTUtil parseString:text];
91 |
92 | [root execute];
93 | }
94 |
95 | //TODO
96 | //- (void)testBlock5
97 | //{
98 | // NSString *text = @"NSArray *content = @[@6,@7,@8,@9,@1,@2,@3,@4];\
99 | // __block NSInteger result = 0;\
100 | // [content enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {\
101 | // result = result + 1;\
102 | // if(result == 1) *stop = YES;\
103 | // }]; \
104 | // return result;";
105 | //
106 | // ASTNode* root = [ASTUtil parseString:text];
107 | //
108 | // ASTVariable* result = [root execute];
109 | // NSAssert([result.value doubleValue] == 1, nil);
110 | //}
111 |
112 | @end
113 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOCUITests/OCContainerTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCContainerTest.m
3 | // DynamicOCUITests
4 | //
5 | // Created by dKingbin on 2019/7/26.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "ASTHeader.h"
12 | #import "ASTUtil.h"
13 | #import "OCCfuntionHelper.h"
14 |
15 | @interface OCContainerTest : XCTestCase
16 |
17 | @end
18 |
19 | @implementation OCContainerTest
20 |
21 | - (void)testNSArray
22 | {
23 | NSString* text = @"NSArray *array = @[@\"a\",[NSNull null],@\"c\",[NSString string],@(1024)]; return array[4];";
24 | ASTNode* root = [ASTUtil parseString:text];
25 |
26 | ASTVariable* result = [root execute];
27 | NSAssert([result.value doubleValue] == 1024, nil);
28 | }
29 |
30 | - (void)testNSArraySetterGetter
31 | {
32 | NSString* text = @"NSArray *array = @[@\"a\",[NSNull null],@\"c\",[NSString string],@(5)];\
33 | NSMutableArray *mutaArray = [array mutableCopy];\
34 | mutaArray[5] = @(1024);\
35 | return mutaArray[5];";
36 | ASTNode* root = [ASTUtil parseString:text];
37 |
38 | ASTVariable* result = [root execute];
39 | NSAssert([result.value doubleValue] == 1024, nil);
40 | }
41 |
42 | - (void)testNSArraySetterGetter1
43 | {
44 | NSString* text = @"NSMutableArray *mutaArray = [NSMutableArray array];\
45 | [mutaArray addObject:@(1024)];\
46 | return mutaArray[0];";
47 | ASTNode* root = [ASTUtil parseString:text];
48 |
49 | ASTVariable* result = [root execute];
50 | NSAssert([result.value doubleValue] == 1024, nil);
51 | }
52 |
53 | - (void)testNSArraySetterGetter2
54 | {
55 | NSString* text = @"NSArray *array = @[@\"a\",[NSNull null],@\"c\",[NSString string],@(5)];\
56 | NSMutableArray *mutaArray = [array mutableCopy];\
57 | [mutaArray removeAllObjects];\
58 | return mutaArray.count == 0 && array.count == 5;";
59 | ASTNode* root = [ASTUtil parseString:text];
60 |
61 | ASTVariable* result = [root execute];
62 | NSAssert([result.value boolValue] == YES, nil);
63 | }
64 |
65 | - (void)testNSArraySetterGetter3
66 | {
67 | NSString* text = @"NSArray *array = @[@\"a\",[NSNull null],@\"c\",[NSString string],@(1024)];\
68 | NSObject *object = [[NSObject alloc] init];\
69 | NSObject* key = [[NSObject alloc]init]; \
70 | objc_setAssociatedObject(object, key, array, 1);\
71 | NSArray *objcArray = objc_getAssociatedObject(object, key); \
72 | return objcArray[4];";
73 | ASTNode* root = [ASTUtil parseString:text];
74 |
75 | ASTVariable* result = [root execute];
76 | NSAssert([result.value doubleValue] == 1024, nil);
77 | }
78 |
79 | int indexFunc(int index)
80 | {
81 | return index;
82 | }
83 |
84 | - (void)testNSArraySetterGetter4
85 | {
86 | [OCCfuntionHelper defineCFunction:@"indexFunc" types:@"int,int"];
87 | NSString* text = @"NSMutableArray *array = [@[@\"a\",[NSNull null],@\"c\",[NSString string],@(666)] mutableCopy]; return array[indexFunc(4)];";
88 | ASTNode* root = [ASTUtil parseString:text];
89 |
90 | ASTVariable* result = [root execute];
91 | NSAssert([result.value doubleValue] == 666, nil);
92 | }
93 |
94 | + (int)indexFunc:(int)index
95 | {
96 | return index;
97 | }
98 |
99 | - (void)testNSArraySetterGetter5
100 | {
101 | [OCCfuntionHelper defineCFunction:@"indexFunc" types:@"int,int"];
102 | NSString* text = @"NSMutableArray *array = [@[@\"a\",[NSNull null],@\"c\",[NSString string],@(1024)] mutableCopy]; return array[[OCContainerTest indexFunc:4]];";
103 | ASTNode* root = [ASTUtil parseString:text];
104 |
105 | ASTVariable* result = [root execute];
106 | NSAssert([result.value doubleValue] == 1024, nil);
107 | }
108 |
109 | - (void)testNSArraySetterGetter6
110 | {
111 | NSString* text = @"NSDictionary *dict = @{@\"aaa\":@(1),@\"6666\":@{@\"bbb\":@\"cccc\"}}; \
112 | NSMutableArray *array = [@[dict, @\"a\",[NSNull null],@\"c\",[NSString string],@(1024)] mutableCopy]; \
113 | return array[0][@\"6666\"][@\"bbb\"];";
114 | ASTNode* root = [ASTUtil parseString:text];
115 |
116 | ASTVariable* result = [root execute];
117 | NSAssert([@"cccc" isEqualToString:result.value], nil);
118 | }
119 |
120 | - (void)testNSArraySetterGetter7
121 | {
122 | NSString* text = @"NSMutableArray *array = [@[@1,@666,@3,@4.5,@(1024)] mutableCopy]; \
123 | return array[1];";
124 | ASTNode* root = [ASTUtil parseString:text];
125 |
126 | ASTVariable* result = [root execute];
127 | NSAssert([result.value doubleValue] == 666, nil);
128 | }
129 |
130 | - (void)testNSDictionarySetterGetter
131 | {
132 | NSString* text = @"NSDictionary *dict = @{@\"aaa\":@(1024),@\"6666\":@{@\"bbb\":@\"cccc\"}}; return dict[@\"aaa\"];";
133 | ASTNode* root = [ASTUtil parseString:text];
134 |
135 | ASTVariable* result = [root execute];
136 | NSAssert([result.value doubleValue] == 1024, nil);
137 | }
138 |
139 | - (void)testNSDictionarySetterGetter1
140 | {
141 | NSString* text = @"NSMutableDictionary *dict = [@{@\"aaa\":@(1024),@\"6666\":@{@\"bbb\":@\"cccc\"}} mutableCopy];dict[@(1024)] = @(666); return dict[@(1024)];";
142 | ASTNode* root = [ASTUtil parseString:text];
143 |
144 | ASTVariable* result = [root execute];
145 | NSAssert([result.value doubleValue] == 666, nil);
146 | }
147 |
148 | - (void)testNSDictionarySetterGetter2
149 | {
150 | NSString* text = @"NSDictionary *dict = @{@\"aaa\":@(1),@\"6666\":@{@\"bbb\":@\"cccc\"}};\
151 | return dict[@\"6666\"][@\"bbb\"];";
152 | ASTNode* root = [ASTUtil parseString:text];
153 |
154 | ASTVariable* result = [root execute];
155 | NSAssert([@"cccc" isEqualToString:result.value], nil);
156 | }
157 |
158 | - (void)testNSDictionarySetterGetter3
159 | {
160 | NSString* text = @"NSArray *array = @[@(666),@(1024),@(2048)];NSDictionary *dic = @{@\"aaa\":@(1),@\"6666\":@{@\"bbb\":array}};\
161 | return dic[@\"6666\"][@\"bbb\"][1];";
162 | ASTNode* root = [ASTUtil parseString:text];
163 |
164 | ASTVariable* result = [root execute];
165 | NSAssert([result.value doubleValue] == 1024, nil);
166 | }
167 |
168 | - (void)testNSDictionarySetterGetter4
169 | {
170 | NSString* text = @"NUIView* view = [[UIView alloc]init];view.tag=1024;NSDictionary *dic = @{@\"aaa\":@(1),@\"6666\":@{@\"bbb\":view}};\
171 | return dic[@\"6666\"][@\"bbb\"].tag;";
172 | ASTNode* root = [ASTUtil parseString:text];
173 |
174 | ASTVariable* result = [root execute];
175 | NSAssert([result.value doubleValue] == 1024, nil);
176 | }
177 |
178 | - (void)testNSDictionarySetterGetter5
179 | {
180 | NSString* text = @"NUIView* view = [[UIView alloc]initWithFrame:CGRectMake(1,2,3,4)];NSDictionary *dic = @{@\"aaa\":@(1),@\"6666\":@{@\"bbb\":view}};\
181 | return dic[@\"6666\"][@\"bbb\"].frame;";
182 | ASTNode* root = [ASTUtil parseString:text];
183 |
184 | ASTVariable* result = [root execute];
185 | CGRect rect = [result.value CGRectValue];
186 | NSAssert(CGRectEqualToRect(rect, CGRectMake(1, 2, 3, 4)), nil);
187 | }
188 |
189 | - (void)testNSDictionarySetterGetter6
190 | {
191 | NSString* text = @"NUIView* view = [[UIView alloc]initWithFrame:CGRectMake(1,2,3,4)];NSDictionary *dic = @{@\"aaa\":@(1),@\"6666\":@{@\"bbb\":view}};\
192 | return dic[@\"6666\"][@\"bbb\"].frame.size;";
193 | ASTNode* root = [ASTUtil parseString:text];
194 |
195 | ASTVariable* result = [root execute];
196 | CGSize size = [result.value CGSizeValue];
197 | NSAssert(CGSizeEqualToSize(CGSizeMake(3, 4), size), nil);
198 | }
199 |
200 | - (void)testNSDictionarySetterGetter7
201 | {
202 | NSString* text = @"NUIView* view = [[UIView alloc]initWithFrame:CGRectMake(1,2,3,4)];NSDictionary *dic = @{@\"aaa\":@(1),@\"6666\":@{@\"bbb\":view}};\
203 | return dic[@\"6666\"][@\"bbb\"].frame.size.width;";
204 | ASTNode* root = [ASTUtil parseString:text];
205 |
206 | ASTVariable* result = [root execute];
207 | NSAssert([result.value doubleValue] == 3, nil);
208 | }
209 |
210 |
211 | @end
212 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOCUITests/OCForControlTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCForControlTest.m
3 | // DynamicOCUITests
4 | //
5 | // Created by dKingbin on 2019/7/23.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "ASTHeader.h"
12 | #import "ASTUtil.h"
13 | #import "OCCfuntionHelper.h"
14 |
15 | @interface OCForControlTest : XCTestCase
16 |
17 | @end
18 |
19 | @implementation OCForControlTest
20 |
21 | - (void)testFor
22 | {
23 | NSString* text = @"int i; for(i=0;i<10;i++){} return i;";
24 | ASTNode* root = [ASTUtil parseString:text];
25 |
26 | ASTVariable* result = [root execute];
27 | NSAssert([result.value doubleValue] == 10, nil);
28 | }
29 |
30 | - (void)testFor1
31 | {
32 | NSString* text = @"int i; for(i=0;i<10;i++); return i;";
33 | ASTNode* root = [ASTUtil parseString:text];
34 |
35 | ASTVariable* result = [root execute];
36 | NSAssert([result.value doubleValue] == 10, nil);
37 | }
38 |
39 | - (void)testFor2
40 | {
41 | NSString* text = @"int i=0;for(;i<10;i++); return i;";
42 | ASTNode* root = [ASTUtil parseString:text];
43 |
44 | ASTVariable* result = [root execute];
45 | NSAssert([result.value doubleValue] == 10, nil);
46 | }
47 |
48 | - (void)testFor3
49 | {
50 | NSString* text = @"int i;for(i=0;i<10;i++); return i;";
51 | ASTNode* root = [ASTUtil parseString:text];
52 |
53 | ASTVariable* result = [root execute];
54 | NSAssert([result.value doubleValue] == 10, nil);
55 | }
56 |
57 | - (void)testFor4
58 | {
59 | NSString* text = @"int i; for(i=0;i<10;){ i++;} return i;";
60 | ASTNode* root = [ASTUtil parseString:text];
61 |
62 | ASTVariable* result = [root execute];
63 | NSAssert([result.value doubleValue] == 10, nil);
64 | }
65 |
66 | - (void)testFor5
67 | {
68 | NSString* text = @"int i; for(i=0;i<10;i++){ if(i==5)break;} return i;";
69 | ASTNode* root = [ASTUtil parseString:text];
70 |
71 | ASTVariable* result = [root execute];
72 | NSAssert([result.value doubleValue] == 5, nil);
73 | }
74 |
75 | - (void)testFor6
76 | {
77 | NSString* text = @"for(int i=0;i<10;i++){ if(i==5) return i;}";
78 | ASTNode* root = [ASTUtil parseString:text];
79 |
80 | ASTVariable* result = [root execute];
81 | NSAssert([result.value doubleValue] == 5, nil);
82 | }
83 |
84 | - (void)testFor7
85 | {
86 | NSString* text = @"int j = 0; for(int i=0;i<10;i++){ if(j==5) continue; j++;} return j;";
87 | ASTNode* root = [ASTUtil parseString:text];
88 |
89 | ASTVariable* result = [root execute];
90 | NSAssert([result.value doubleValue] == 5, nil);
91 | }
92 |
93 |
94 | - (void)testFor8
95 | {
96 | NSString* text = @"for(int i=0;i<10;i++){ } return i;";
97 | ASTNode* root = [ASTUtil parseString:text];
98 |
99 | ASTVariable* result = [root execute];
100 | NSAssert(result.value == nil, nil);
101 | }
102 | @end
103 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOCUITests/OCIfControlTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCIfControlTest.m
3 | // DynamicOCUITests
4 | //
5 | // Created by dKingbin on 2019/7/23.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "ASTHeader.h"
12 | #import "ASTUtil.h"
13 | #import "OCCfuntionHelper.h"
14 |
15 | @interface OCControlTest : XCTestCase
16 |
17 | @end
18 |
19 | @implementation OCControlTest
20 |
21 | - (void)testIf
22 | {
23 | NSString* text = @"int i=1;if(i==1){ return 1024; }";
24 | ASTNode* root = [ASTUtil parseString:text];
25 |
26 | ASTVariable* result = [root execute];
27 | NSAssert([result.value doubleValue] == 1024, nil);
28 | }
29 |
30 | - (void)testIf1
31 | {
32 | NSString* text = @"int i=1;if(i==1);";
33 | [ASTUtil parseString:text];
34 | }
35 |
36 | - (void)testIf2
37 | {
38 | NSString* text = @"int i=1; int j=2; if(i==j){ return i; } else { return j; }";
39 | ASTNode* root = [ASTUtil parseString:text];
40 |
41 | ASTVariable* result = [root execute];
42 | NSAssert([result.value doubleValue] == 2, nil);
43 | }
44 |
45 | - (void)testIf3
46 | {
47 | NSString* text = @"int i=1; int j=2; if(i==j){ return i; } else if( i<= j) { return j; }";
48 | ASTNode* root = [ASTUtil parseString:text];
49 |
50 | ASTVariable* result = [root execute];
51 | NSAssert([result.value doubleValue] == 2, nil);
52 | }
53 |
54 | - (void)testIf4
55 | {
56 | NSString* text = @"int i=1; int j=2; if(i==j){ return i; } else if( i>= j) { return j; } else { return 1024; }";
57 | ASTNode* root = [ASTUtil parseString:text];
58 |
59 | ASTVariable* result = [root execute];
60 | NSAssert([result.value doubleValue] == 1024, nil);
61 | }
62 |
63 | - (void)testIf5
64 | {
65 | NSString* text = @"NSNumber* ival = @(0);if(ival){ return YES; }";
66 | ASTNode* root = [ASTUtil parseString:text];
67 |
68 | ASTVariable* result = [root execute];
69 | NSAssert([result.value boolValue] == YES, nil);
70 | }
71 |
72 | - (void)testIf6
73 | {
74 | NSString* text = @"NSNumber* ival = @(0);if(!ival){ return YES; } else { return NO; }";
75 | ASTNode* root = [ASTUtil parseString:text];
76 |
77 | ASTVariable* result = [root execute];
78 | NSAssert([result.value boolValue] == NO, nil);
79 | }
80 |
81 | - (void)testIf7
82 | {
83 | NSString* text = @"NSString* str = @\"abcdefg\"; if(str.length > 0) { return str; }";
84 | ASTNode* root = [ASTUtil parseString:text];
85 |
86 | ASTVariable* result = [root execute];
87 | NSAssert([result.value isEqualToString:@"abcdefg"], nil);
88 | }
89 |
90 | - (void)testIf8
91 | {
92 | NSString* text = @"NSString* str = @\"abcdefg\"; if(str) { return str; }";
93 | ASTNode* root = [ASTUtil parseString:text];
94 |
95 | ASTVariable* result = [root execute];
96 | NSAssert([result.value isEqualToString:@"abcdefg"], nil);
97 | }
98 |
99 | - (void)testIf9
100 | {
101 | NSString* text = @"NSNumber* ival = nil; if(ival) { return 0; } else { return 1024; }";
102 | ASTNode* root = [ASTUtil parseString:text];
103 |
104 | ASTVariable* result = [root execute];
105 | NSAssert([result.value doubleValue] == 1024, nil);
106 | }
107 |
108 | - (void)testIf10
109 | {
110 | NSString* text = @"NSNumber* ival = nil; if(!ival) { return 1024; } else { return 0; }";
111 | ASTNode* root = [ASTUtil parseString:text];
112 |
113 | ASTVariable* result = [root execute];
114 | NSAssert([result.value doubleValue] == 1024, nil);
115 | }
116 |
117 | - (void)testIf11
118 | {
119 | NSString* text = @"if(YES) { return 1024; } else { return 0; }";
120 | ASTNode* root = [ASTUtil parseString:text];
121 |
122 | ASTVariable* result = [root execute];
123 | NSAssert([result.value doubleValue] == 1024, nil);
124 | }
125 |
126 | - (void)testIf12
127 | {
128 | NSString* text = @"if(YES && NO) { return 1024; } else { return 0; }";
129 | ASTNode* root = [ASTUtil parseString:text];
130 |
131 | ASTVariable* result = [root execute];
132 | NSAssert([result.value doubleValue] == 0, nil);
133 | }
134 |
135 | - (void)testIf13
136 | {
137 | NSString* text = @"if((YES) && (NO)) { return 1024; } else { return 0; }";
138 | ASTNode* root = [ASTUtil parseString:text];
139 |
140 | ASTVariable* result = [root execute];
141 | NSAssert([result.value doubleValue] == 0, nil);
142 | }
143 |
144 | - (void)testIf14
145 | {
146 | NSString* text = @"if((YES) || (NO)) { return 1024; } else { return 0; }";
147 | ASTNode* root = [ASTUtil parseString:text];
148 |
149 | ASTVariable* result = [root execute];
150 | NSAssert([result.value doubleValue] == 1024, nil);
151 | }
152 |
153 | - (void)testIf15
154 | {
155 | NSString* text = @"if((true) || (false)) { return 1024; } else { return 0; }";
156 | ASTNode* root = [ASTUtil parseString:text];
157 |
158 | ASTVariable* result = [root execute];
159 | NSAssert([result.value doubleValue] == 1024, nil);
160 | }
161 |
162 | - (void)testIf16
163 | {
164 | NSString* text = @"CGRect rect = CGRectMake(1,2,3,4); if(rect.size.width == 3) return rect;";
165 | ASTNode* root = [ASTUtil parseString:text];
166 |
167 | ASTVariable* result = [root execute];
168 | NSAssert(CGRectEqualToRect([result.value CGRectValue], CGRectMake(1,2,3,4)), nil);
169 | }
170 |
171 | - (void)testIf17
172 | {
173 | NSString* text = @"UIView* view = [[UIView alloc]init]; view.tag = 1024; if(view.tag == 1024) return view.tag;";
174 | ASTNode* root = [ASTUtil parseString:text];
175 |
176 | ASTVariable* result = [root execute];
177 | NSAssert([result.value doubleValue] == 1024, nil);
178 | }
179 |
180 | - (void)testIf18
181 | {
182 | NSString* text = @"UIView* view = [[UIView alloc]init]; view.tag = 1; if(view.tag != 1024) return 6666;";
183 | ASTNode* root = [ASTUtil parseString:text];
184 |
185 | ASTVariable* result = [root execute];
186 | NSAssert([result.value doubleValue] == 6666, nil);
187 | }
188 |
189 | - (void)testIf19
190 | {
191 | NSString* text = @"NSArray* array = @[@(1)]; if(array.count>0) return 6666;";
192 | ASTNode* root = [ASTUtil parseString:text];
193 |
194 | ASTVariable* result = [root execute];
195 | NSAssert([result.value doubleValue] == 6666, nil);
196 | }
197 |
198 | - (void)testIf20
199 | {
200 | NSString* text = @"if([NSString string] != nil) return 6666; else return 1024;";
201 | ASTNode* root = [ASTUtil parseString:text];
202 |
203 | ASTVariable* result = [root execute];
204 | NSAssert([result.value doubleValue] == 6666, nil);
205 | }
206 |
207 | - (void)testIf21
208 | {
209 | NSString* text = @"if(3 <= 4 && [NSString string] != nil) return 6666; else return 1024;";
210 | ASTNode* root = [ASTUtil parseString:text];
211 |
212 | ASTVariable* result = [root execute];
213 | NSAssert([result.value doubleValue] == 6666, nil);
214 | }
215 |
216 | - (void)testIf22
217 | {
218 | NSString* text = @"int i=1; if(i > 0) i = 2; if(i < 0) i = 666; else i = 1024; return i;";
219 | ASTNode* root = [ASTUtil parseString:text];
220 |
221 | ASTVariable* result = [root execute];
222 | NSAssert([result.value doubleValue] == 1024, nil);
223 | }
224 |
225 | - (void)testCondition
226 | {
227 | NSString* text = @"int i=1;int j=2;int k = i <= j ? 666 : 1024; return k;";
228 | ASTNode* root = [ASTUtil parseString:text];
229 |
230 | ASTVariable* result = [root execute];
231 | NSAssert([result.value doubleValue] == 666, nil);
232 | }
233 |
234 | - (void)testCondition1
235 | {
236 | NSString* text = @"int i=1;int j=2;int k = i > j ? 666 : 1024; return k;";
237 | ASTNode* root = [ASTUtil parseString:text];
238 |
239 | ASTVariable* result = [root execute];
240 | NSAssert([result.value doubleValue] == 1024, nil);
241 | }
242 |
243 | - (void)testCondition2
244 | {
245 | NSString* text = @"int i=1;int j=2;int k = (i <= j) ? 666 : 1024; return k;";
246 | ASTNode* root = [ASTUtil parseString:text];
247 |
248 | ASTVariable* result = [root execute];
249 | NSAssert([result.value doubleValue] == 666, nil);
250 | }
251 |
252 | - (void)testCondition3
253 | {
254 | NSString* text = @"NSNumber* ival = @(0);int k = ival ? 666 : 1024; return k;";
255 | ASTNode* root = [ASTUtil parseString:text];
256 |
257 | ASTVariable* result = [root execute];
258 | NSAssert([result.value doubleValue] == 666, nil);
259 | }
260 |
261 | - (void)testCondition4
262 | {
263 | NSString* text = @"NSNumber* ival = @(0);int k = !ival ? 666 : 1024; return k;";
264 | ASTNode* root = [ASTUtil parseString:text];
265 |
266 | ASTVariable* result = [root execute];
267 | NSAssert([result.value doubleValue] == 1024, nil);
268 | }
269 |
270 | - (void)testCondition5
271 | {
272 | NSString* text = @"NSString* str = @\"abcedf\";int k = str.length > 0 ? 666 : 1024; return k;";
273 | ASTNode* root = [ASTUtil parseString:text];
274 |
275 | ASTVariable* result = [root execute];
276 | NSAssert([result.value doubleValue] == 666, nil);
277 | }
278 |
279 | - (void)testCondition6
280 | {
281 | NSString* text = @"NSString* str = @\"abcedf\";int k = [str length] > 0 ? 666 : 1024; return k;";
282 | ASTNode* root = [ASTUtil parseString:text];
283 |
284 | ASTVariable* result = [root execute];
285 | NSAssert([result.value doubleValue] == 666, nil);
286 | }
287 |
288 | - (void)testCondition7
289 | {
290 | NSString* text = @"NSArray* array = @[@(1),@(2)];int k = array.count > 0 ? 666 : 1024; return k;";
291 | ASTNode* root = [ASTUtil parseString:text];
292 |
293 | ASTVariable* result = [root execute];
294 | NSAssert([result.value doubleValue] == 666, nil);
295 | }
296 |
297 | - (void)testCondition8
298 | {
299 | NSString* text = @"NSArray* array = @[@(1),@(2)];int k = [array count] > 0 ? 666 : 1024; return k;";
300 | ASTNode* root = [ASTUtil parseString:text];
301 |
302 | ASTVariable* result = [root execute];
303 | NSAssert([result.value doubleValue] == 666, nil);
304 | }
305 |
306 | - (void)testCondition9
307 | {
308 | NSString* text = @"NSArray* array = @[@(1),@(2)];int k = array[0] > 0 ? 666 : 1024; return k;";
309 | ASTNode* root = [ASTUtil parseString:text];
310 |
311 | ASTVariable* result = [root execute];
312 | NSAssert([result.value doubleValue] == 666, nil);
313 | }
314 |
315 | - (void)testSelf
316 | {
317 | [ASTUtil registerVariableForYacc:@"self"];
318 |
319 | NSMutableDictionary* ctx = [NSMutableDictionary dictionary];
320 | ASTVariable* varSelf = [[ASTVariable alloc]init];
321 | varSelf.value = self;
322 | varSelf.type = ASTNodeTypeVariable;
323 | [ctx setObject:varSelf forKey:@"self"];
324 |
325 | NSString* text = @"if(!self) return 666; else return 1024;";
326 |
327 | ASTNode* root = [ASTUtil parseString:text];
328 | [root.context pushDefinedContext:ctx];
329 |
330 | ASTVariable* result = [root execute];
331 | NSAssert([result.value doubleValue] == 1024, nil);
332 | }
333 |
334 | @end
335 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOCUITests/OCPropertyTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCPropertyTest.m
3 | // DynamicOCUITests
4 | //
5 | // Created by dKingbin on 2019/7/24.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "ASTHeader.h"
12 | #import "ASTUtil.h"
13 | #import "OCCfuntionHelper.h"
14 | #import
15 |
16 | @interface OCPropertyTest : XCTestCase
17 | {
18 | int __tag;
19 | NSString* _str;
20 | }
21 |
22 | @property(nonatomic,assign) int value;
23 | @property(nonatomic,assign) CGRect frame;
24 | @end
25 |
26 | @implementation OCPropertyTest
27 |
28 | - (void)testSelf
29 | {
30 | self.frame = CGRectMake(0, 0, 375, 667);
31 |
32 | [ASTUtil registerVariableForYacc:@"self"];
33 |
34 | NSMutableDictionary* ctx = [NSMutableDictionary dictionary];
35 | ASTVariable* varSelf = [[ASTVariable alloc]init];
36 | varSelf.value = self;
37 | varSelf.type = ASTNodeTypeVariable;
38 | [ctx setObject:varSelf forKey:@"self"];
39 |
40 | NSString* text = @"UITableView *tableView = [[UITableView alloc] initWithFrame:self.frame style:0]; return tableView.frame.size.width;";
41 |
42 | ASTNode* root = [ASTUtil parseString:text];
43 | [root.context pushDefinedContext:ctx];
44 | ASTVariable* result = [root execute];
45 |
46 | NSAssert([result.value doubleValue] == 375, nil);
47 | }
48 |
49 | - (void)testSelf1
50 | {
51 | self.frame = CGRectMake(0, 0, 375, 667);
52 |
53 | [ASTUtil registerVariableForYacc:@"self"];
54 |
55 | NSMutableDictionary* ctx = [NSMutableDictionary dictionary];
56 | ASTVariable* varSelf = [[ASTVariable alloc]init];
57 | varSelf.value = self;
58 | varSelf.type = ASTNodeTypeVariable;
59 | [ctx setObject:varSelf forKey:@"self"];
60 |
61 | NSString* text = @"self.frame.size.width = 1024; return self.frame;";
62 |
63 | ASTNode* root = [ASTUtil parseString:text];
64 | [root.context pushDefinedContext:ctx];
65 |
66 | ASTVariable* result = [root execute];
67 |
68 | NSAssert(CGRectEqualToRect(CGRectMake(0, 0, 1024, 667), [result.value CGRectValue]), nil);
69 | }
70 |
71 | - (void)testSuper
72 | {
73 | [ASTUtil registerVariableForYacc:@"self"];
74 | [ASTUtil registerVariableForYacc:@"super"];
75 |
76 | NSMutableDictionary* ctx = [NSMutableDictionary dictionary];
77 | ASTVariable* varSelf = [[ASTVariable alloc]init];
78 | varSelf.value = self;
79 | varSelf.type = ASTNodeTypeVariable;
80 | [ctx setObject:varSelf forKey:@"self"];
81 |
82 | NSString* text = @"return [super name];";
83 |
84 | ASTNode* root = [ASTUtil parseString:text];
85 | [root.context pushDefinedContext:ctx];
86 |
87 | ASTVariable* result = [root execute];
88 |
89 | NSAssert([[super name] isEqualToString:result.value], nil);
90 | }
91 |
92 | - (void)testSuper1
93 | {
94 | [ASTUtil registerVariableForYacc:@"self"];
95 | [ASTUtil registerVariableForYacc:@"super"];
96 |
97 | NSMutableDictionary* ctx = [NSMutableDictionary dictionary];
98 | ASTVariable* varSelf = [[ASTVariable alloc]init];
99 | varSelf.value = self;
100 | varSelf.type = ASTNodeTypeVariable;
101 | [ctx setObject:varSelf forKey:@"self"];
102 |
103 | NSString* text = @"return super.name;";
104 |
105 | ASTNode* root = [ASTUtil parseString:text];
106 | [root.context pushDefinedContext:ctx];
107 |
108 | ASTVariable* result = [root execute];
109 |
110 | NSAssert([[super name] isEqualToString:result.value], nil);
111 | }
112 |
113 | - (void)testMemberVariable
114 | {
115 | NSString* text = @"OCPropertyTest *test = [[OCPropertyTest alloc]init]; test->__tag = 1024; return test->__tag;";
116 | ASTNode* root = [ASTUtil parseString:text];
117 |
118 | ASTVariable* result = [root execute];
119 | NSAssert([result.value doubleValue] == 1024, nil);
120 | }
121 |
122 | - (void)testMemberVariable1
123 | {
124 | NSString* text = @"OCPropertyTest *test = [[OCPropertyTest alloc]init]; test->_str = @\"helloworld\"; return test->_str;";
125 | ASTNode* root = [ASTUtil parseString:text];
126 |
127 | ASTVariable* result = [root execute];
128 | NSAssert([result.value isEqualToString:@"helloworld"], nil);
129 | }
130 |
131 | - (void)testProperty
132 | {
133 | NSString* text = @"OCPropertyTest *test = [[OCPropertyTest alloc]init]; test->_value = 666; return test->_value;";
134 | ASTNode* root = [ASTUtil parseString:text];
135 |
136 | ASTVariable* result = [root execute];
137 | NSAssert([result.value doubleValue] == 666, nil);
138 | }
139 |
140 | - (void)testStructGetterSetter
141 | {
142 | NSString* text = @" UIView *view = [[UIView alloc] init];\
143 | CGRect bound = [view bounds];\
144 | return bound;";
145 | ASTNode* root = [ASTUtil parseString:text];
146 |
147 | ASTVariable* result = [root execute];
148 | CGRect rect = [result.value CGRectValue];
149 | NSAssert(CGRectEqualToRect(CGRectZero,rect), nil);
150 | }
151 |
152 | - (void)testStructGetterSetter1
153 | {
154 | NSString* text = @"UIView *view = [[UIView alloc]initWithFrame:CGRectMake(1, 2, 3, 4)];\
155 | CGRect bound = [view bounds];\
156 | return bound;";
157 | ASTNode* root = [ASTUtil parseString:text];
158 |
159 | ASTVariable* result = [root execute];
160 | CGRect rect = [result.value CGRectValue];
161 | NSAssert(CGRectEqualToRect(CGRectMake(0, 0, 3, 4),rect), nil);
162 | }
163 |
164 | - (void)testStructGetterSetter2
165 | {
166 | NSString* text = @"CGPoint point = CGPointMake(1,2); return point;";
167 | ASTNode* root = [ASTUtil parseString:text];
168 |
169 | ASTVariable* result = [root execute];
170 | CGPoint pt = [result.value CGPointValue];
171 | NSAssert(CGPointEqualToPoint(pt, CGPointMake(1, 2)), nil);
172 | }
173 |
174 | - (void)testStructGetterSetter3
175 | {
176 | NSString* text = @"CGPoint point = CGPointMake(1,2); return point.x;";
177 | ASTNode* root = [ASTUtil parseString:text];
178 |
179 | ASTVariable* result = [root execute];
180 | NSAssert([result.value doubleValue] == 1, nil);
181 | }
182 |
183 | - (void)testUIView
184 | {
185 | NSString* text = @"UIView* view = [[UIView alloc]init];view.tag=1024;return view.tag;";
186 | ASTNode* root = [ASTUtil parseString:text];
187 |
188 | ASTVariable* result = [root execute];
189 | NSAssert([result.value doubleValue] == 1024, nil);
190 | }
191 |
192 | - (void)testOCStructGetterSetter1
193 | {
194 | NSString* text = @"UIView* view = [[UIView alloc]initWithFrame:CGRectMake(1, 2, 3, 4)];view.frame.size.width=1024; return view.frame.size.width;";
195 | ASTNode* root = [ASTUtil parseString:text];
196 |
197 | ASTVariable* result = [root execute];
198 | NSAssert([result.value doubleValue] == 1024, nil);
199 | }
200 |
201 | - (void)testOCStructGetterSetter2
202 | {
203 | NSString* text = @"UIView* view = [[UIView alloc]initWithFrame:CGRectMake(1, 2, 3, 4)];view.frame = CGRectMake(6,6,1024,6); return view.frame.size.width;";
204 | ASTNode* root = [ASTUtil parseString:text];
205 |
206 | ASTVariable* result = [root execute];
207 | NSAssert([result.value doubleValue] == 1024, nil);
208 | }
209 |
210 | - (void)testOCStructGetterSetter3
211 | {
212 | NSString* text = @"UIView* view = [[UIView alloc]initWithFrame:CGRectMake(1, 2, 3, 4)];view.frame.size = CGSizeMake(2048,0); return view.frame.size.width;";
213 | ASTNode* root = [ASTUtil parseString:text];
214 |
215 | ASTVariable* result = [root execute];
216 | NSAssert([result.value doubleValue] == 2048, nil);
217 | }
218 |
219 | - (void)testOCStructGetterSetter4
220 | {
221 | NSString* text = @"CGRect rect = CGRectMake(1, 2, 3, 4); return rect.size.width;";
222 | ASTNode* root = [ASTUtil parseString:text];
223 |
224 | ASTVariable* result = [root execute];
225 | NSAssert([result.value doubleValue] == 3, nil);
226 | }
227 |
228 | - (void)testOCStructGetterSetter5
229 | {
230 | NSString* text = @"CGRect rect = CGRectMake(1, 2, 3, 4); return rect.size.height;";
231 | ASTNode* root = [ASTUtil parseString:text];
232 |
233 | ASTVariable* result = [root execute];
234 | NSAssert([result.value doubleValue] == 4, nil);
235 | }
236 |
237 | - (void)testOCStructGetterSetter6
238 | {
239 | NSString* text = @"CGRect rect = CGRectMake(1, 2, 3, 4); return rect.origin.x;";
240 | ASTNode* root = [ASTUtil parseString:text];
241 |
242 | ASTVariable* result = [root execute];
243 | NSAssert([result.value doubleValue] == 1, nil);
244 | }
245 |
246 | - (void)testOCStructGetterSetter7
247 | {
248 | NSString* text = @"CGRect rect = CGRectMake(1, 2, 3, 4); return rect.origin.y;";
249 | ASTNode* root = [ASTUtil parseString:text];
250 |
251 | ASTVariable* result = [root execute];
252 | NSAssert([result.value doubleValue] == 2, nil);
253 | }
254 |
255 | - (void)testOCStructGetterSetter8
256 | {
257 | NSString* text = @"CGRect rect = CGRectMake(1, 2, 3, 4); rect.origin.x=1024; return rect.origin.x;";
258 | ASTNode* root = [ASTUtil parseString:text];
259 |
260 | ASTVariable* result = [root execute];
261 | NSAssert([result.value doubleValue] == 1024, nil);
262 | }
263 |
264 | - (void)testOCStructGetterSetter9
265 | {
266 | NSString* text = @"CGSize size = CGSizeMake(1,2); return size.width;";
267 | ASTNode* root = [ASTUtil parseString:text];
268 |
269 | ASTVariable* result = [root execute];
270 | NSAssert([result.value doubleValue] == 1, nil);
271 | }
272 |
273 | - (void)testOCStructGetterSetter10
274 | {
275 | NSString* text = @"CGSize size = CGSizeMake(1,2); return size.height;";
276 | ASTNode* root = [ASTUtil parseString:text];
277 |
278 | ASTVariable* result = [root execute];
279 | NSAssert([result.value doubleValue] == 2, nil);
280 | }
281 |
282 | - (void)testOCStructGetterSetter11
283 | {
284 | NSString* text = @"CGSize size = CGSizeMake(1,2); size.width = 1024; return size.width;";
285 | ASTNode* root = [ASTUtil parseString:text];
286 |
287 | ASTVariable* result = [root execute];
288 | NSAssert([result.value doubleValue] == 1024, nil);
289 | }
290 |
291 | - (void)testOCStructGetterSetter12
292 | {
293 | NSString* text = @"CGSize size = CGSizeMake(1,2); size.height = 1024; return size.height;";
294 | ASTNode* root = [ASTUtil parseString:text];
295 |
296 | ASTVariable* result = [root execute];
297 | NSAssert([result.value doubleValue] == 1024, nil);
298 | }
299 |
300 | - (void)testOCStructGetterSetter13
301 | {
302 | NSString* text = @"CGSize size = CGSizeMake(1,2); size = CGSizeMake(1024,2048); return size;";
303 | ASTNode* root = [ASTUtil parseString:text];
304 |
305 | ASTVariable* result = [root execute];
306 | NSAssert(CGSizeEqualToSize(CGSizeMake(1024, 2048), [result.value CGSizeValue]), nil);
307 | }
308 |
309 | - (void)testOCStructGetterSetter14
310 | {
311 | NSString* text = @"UIEdgeInsets inset = UIEdgeInsetsMake(1, 2, 3, 4); return inset;";
312 | ASTNode* root = [ASTUtil parseString:text];
313 |
314 | ASTVariable* result = [root execute];
315 | NSAssert(UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsMake(1, 2, 3, 4), [result.value UIEdgeInsetsValue]), nil);
316 | }
317 |
318 | - (void)testOCStructGetterSetter15
319 | {
320 | NSString* text = @"UIEdgeInsets inset = UIEdgeInsetsMake(1, 2, 3, 4); inset.top=1024; return inset.top;";
321 | ASTNode* root = [ASTUtil parseString:text];
322 |
323 | ASTVariable* result = [root execute];
324 | NSAssert([result.value doubleValue] == 1024, nil);
325 | }
326 |
327 | - (void)testOCStructGetterSetter16
328 | {
329 | NSString* text = @"UIEdgeInsets inset = UIEdgeInsetsMake(1, 2, 3, 4); inset.left=1024; return inset.left;";
330 | ASTNode* root = [ASTUtil parseString:text];
331 |
332 | ASTVariable* result = [root execute];
333 | NSAssert([result.value doubleValue] == 1024, nil);
334 | }
335 |
336 | - (void)testNSString
337 | {
338 | NSString* text = @"NSString* str = @\"abcdefgh\"; return str.length;";
339 | ASTNode* root = [ASTUtil parseString:text];
340 |
341 | ASTVariable* result = [root execute];
342 | NSAssert([result.value doubleValue] == [@"abcdefgh" length], nil);
343 | }
344 |
345 | - (void)testNSNumber
346 | {
347 | NSString* text = @"NSNumber* ival = @(1024); return ival;";
348 | ASTNode* root = [ASTUtil parseString:text];
349 |
350 | ASTVariable* result = [root execute];
351 | NSAssert([result.value doubleValue] == 1024, nil);
352 | }
353 |
354 |
355 | @end
356 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOCUITests/OCWhileControlTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // OCWhileControlTest.m
3 | // DynamicOCUITests
4 | //
5 | // Created by dKingbin on 2019/7/23.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "ASTHeader.h"
12 | #import "ASTUtil.h"
13 | #import "OCCfuntionHelper.h"
14 |
15 | @interface OCWhileControlTest : XCTestCase
16 |
17 | @end
18 |
19 | @implementation OCWhileControlTest
20 |
21 | - (void)testWhile
22 | {
23 | NSString* text = @"int i=1;while(i<10){ i++; } return i;";
24 | ASTNode* root = [ASTUtil parseString:text];
25 |
26 | ASTVariable* result = [root execute];
27 | NSAssert([result.value doubleValue] == 10, nil);
28 | }
29 |
30 | - (void)testWhile1
31 | {
32 | NSString* text = @"NSNumber* ival = @(0); int i=1;while(ival){ i++; if(i==10) return i; }";
33 | ASTNode* root = [ASTUtil parseString:text];
34 |
35 | ASTVariable* result = [root execute];
36 | NSAssert([result.value doubleValue] == 10, nil);
37 | }
38 |
39 | - (void)testWhile2
40 | {
41 | NSString* text = @"NSNumber* ival = @(0); int i=1;while(ival){ i++; if(i==10) break; } return i;";
42 | ASTNode* root = [ASTUtil parseString:text];
43 |
44 | ASTVariable* result = [root execute];
45 | NSAssert([result.value doubleValue] == 10, nil);
46 | }
47 |
48 | - (void)testWhile3
49 | {
50 | NSString* text = @"int count = 1; int i=1;while(count < 10){ count++; if(i==5) continue; i++; } return i;";
51 | ASTNode* root = [ASTUtil parseString:text];
52 |
53 | ASTVariable* result = [root execute];
54 | NSAssert([result.value doubleValue] == 5, nil);
55 | }
56 |
57 | - (void)testWhile4
58 | {
59 | NSString* text = @"int i=0; do { i=1024;} while(0); return i;";
60 | ASTNode* root = [ASTUtil parseString:text];
61 |
62 | ASTVariable* result = [root execute];
63 | NSAssert([result.value doubleValue] == 1024, nil);
64 | }
65 |
66 | - (void)testWhile5
67 | {
68 | NSString* text = @"int i=1; do { i= i + 1;} while(i<10); return i;";
69 | ASTNode* root = [ASTUtil parseString:text];
70 |
71 | ASTVariable* result = [root execute];
72 | NSAssert([result.value doubleValue] == 10, nil);
73 | }
74 |
75 | - (void)testWhile6
76 | {
77 | NSString* text = @"int i=1; do { i= i + 1; if(i==10) break;} while(i<1000); return i;";
78 | ASTNode* root = [ASTUtil parseString:text];
79 |
80 | ASTVariable* result = [root execute];
81 | NSAssert([result.value doubleValue] == 10, nil);
82 | }
83 |
84 | - (void)testWhile7
85 | {
86 | NSString* text = @"int i=1; do { i= i + 1; if(i==10) return 1024;} while(i<1000);";
87 | ASTNode* root = [ASTUtil parseString:text];
88 |
89 | ASTVariable* result = [root execute];
90 | NSAssert([result.value doubleValue] == 1024, nil);
91 | }
92 |
93 | - (void)testWhile8
94 | {
95 | NSString* text = @"int count = 1; int i=1;do{ count++; if(i==5) continue; i++; }while(count<10); return i;";
96 | ASTNode* root = [ASTUtil parseString:text];
97 |
98 | ASTVariable* result = [root execute];
99 | NSAssert([result.value doubleValue] == 5, nil);
100 | }
101 |
102 | @end
103 |
--------------------------------------------------------------------------------
/DynamicOC/DynamicOCUITests/UnaryOperationTest.m:
--------------------------------------------------------------------------------
1 | //
2 | // UnaryOperationTest.m
3 | // DynamicOCUITests
4 | //
5 | // Created by dKingbin on 2019/7/23.
6 | // Copyright © 2019 dKingbin. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "ASTHeader.h"
12 | #import "ASTUtil.h"
13 | #import "OCCfuntionHelper.h"
14 |
15 | @interface UnaryOperationTest : XCTestCase
16 |
17 | @end
18 |
19 | @implementation UnaryOperationTest
20 |
21 | - (void)testUnaryPrefixInc
22 | {
23 | NSString* text = @"int i=1;int j=++i; return j;";
24 | ASTNode* root = [ASTUtil parseString:text];
25 |
26 | ASTVariable* result = [root execute];
27 | NSAssert([result.value doubleValue] == 2, nil);
28 | }
29 |
30 | - (void)testUnaryPrefixDec
31 | {
32 | NSString* text = @"int i=1;int j=--i; return j;";
33 | ASTNode* root = [ASTUtil parseString:text];
34 |
35 | ASTVariable* result = [root execute];
36 | NSAssert([result.value doubleValue] == 0, nil);
37 | }
38 |
39 | - (void)testUnaryPostInc
40 | {
41 | NSString* text = @"int i=1;int j=i++; return j;";
42 | ASTNode* root = [ASTUtil parseString:text];
43 |
44 | ASTVariable* result = [root execute];
45 | NSAssert([result.value doubleValue] == 1, nil);
46 | }
47 |
48 | - (void)testUnaryPostInc1
49 | {
50 | NSString* text = @"int i=1;int j=i++; return i;";
51 | ASTNode* root = [ASTUtil parseString:text];
52 |
53 | ASTVariable* result = [root execute];
54 | NSAssert([result.value doubleValue] == 2, nil);
55 | }
56 |
57 | - (void)testUnaryPostDec
58 | {
59 | NSString* text = @"int i=1;int j=i--; return j;";
60 | ASTNode* root = [ASTUtil parseString:text];
61 |
62 | ASTVariable* result = [root execute];
63 | NSAssert([result.value doubleValue] == 1, nil);
64 | }
65 |
66 | - (void)testUnaryPostDec1
67 | {
68 | NSString* text = @"int i=1;int j=i--; return i;";
69 | ASTNode* root = [ASTUtil parseString:text];
70 |
71 | ASTVariable* result = [root execute];
72 | NSAssert([result.value doubleValue] == 0, nil);
73 | }
74 |
75 | - (void)testUnaryPlus
76 | {
77 | NSString* text = @"int i=1;int j=+i; return j;";
78 | ASTNode* root = [ASTUtil parseString:text];
79 |
80 | ASTVariable* result = [root execute];
81 | NSAssert([result.value doubleValue] == 1, nil);
82 | }
83 |
84 | - (void)testUnaryMinus
85 | {
86 | NSString* text = @"int i=1;int j=-i; return j;";
87 | ASTNode* root = [ASTUtil parseString:text];
88 |
89 | ASTVariable* result = [root execute];
90 | NSAssert([result.value doubleValue] == -1, nil);
91 | }
92 |
93 | - (void)testUnaryMinus1
94 | {
95 | NSString* text = @"int i=1;int j=-(-i); return j;";
96 | ASTNode* root = [ASTUtil parseString:text];
97 |
98 | ASTVariable* result = [root execute];
99 | NSAssert([result.value doubleValue] == 1, nil);
100 | }
101 |
102 | - (void)testUnaryNOT
103 | {
104 | NSString* text = @"int i=0; i = !i; return i;";
105 | ASTNode* root = [ASTUtil parseString:text];
106 |
107 | ASTVariable* result = [root execute];
108 | NSAssert([result.value doubleValue] == 1, nil);
109 | }
110 |
111 | - (void)testUnaryNOT1
112 | {
113 | NSString* text = @"NSNumber* ival = @(0); BOOL ok = !ival; return ok;";
114 | ASTNode* root = [ASTUtil parseString:text];
115 | ASTVariable* result = [root execute];
116 | NSAssert([result.value doubleValue] == NO, nil);
117 | }
118 |
119 | - (void)testUnaryNOT2
120 | {
121 | NSString* text = @"NSNumber* ival = nil; BOOL ok = !ival; return ok;";
122 | ASTNode* root = [ASTUtil parseString:text];
123 | ASTVariable* result = [root execute];
124 | NSAssert([result.value doubleValue] == YES, nil);
125 | }
126 |
127 | - (void)testUnaryNOT3
128 | {
129 | NSString* text = @"NSNumber* ival = nil; !ival; return ival;";
130 | ASTNode* root = [ASTUtil parseString:text];
131 | ASTVariable* result = [root execute];
132 | NSAssert(result.value == nil, nil);
133 | }
134 |
135 | @end
136 |
--------------------------------------------------------------------------------
/README-chs.md:
--------------------------------------------------------------------------------
1 |
2 | [English README](https://github.com/letqingbin/DynamicOC/blob/master/README.md) | [原理介绍](https://github.com/letqingbin/DynamicOC/blob/master/principle_chs.md)
3 |
4 | # DynamicOC
5 | DynamicOC是一个功能上与[JSPath](https://github.com/bang590/JSPatch)类似,但是仅需要编写原生OC语法就能实现热更新(hotfix)的功能。
6 |
7 | ## 功能特点
8 |
9 | - 动态执行OC代码
10 | - 动态执行C函数和block异步调用
11 | - 动态添加属性
12 | - 动态替换方法
13 | - 动态添加方法
14 | - 有完善的单元测试
15 | - flex/yacc实现强大的OC语法解析器
16 | - 支持CGRect/CGSize/CGPoint/NSRange/UIEdgeInsets/CGAffineTransform常用结构体
17 | ...
18 |
19 | ## 基本用法
20 |
21 | #### 动态执行block
22 |
23 | ```
24 | NSString* text = @" \
25 | __block int result = 0;\
26 | UIView* view = [[UIView alloc]init];\
27 | void(^blk)(int value) = ^(int value){\
28 | view.tag = value;\
29 | };\
30 | blk(1024);\
31 | return view.tag;";
32 |
33 | ASTNode* root = [ASTUtil parseString:text];
34 | ASTVariable* result = [root execute];
35 | NSAssert([result.value doubleValue] == 1024, nil);
36 | ```
37 |
38 | #### 动态执行C函数
39 |
40 | ```
41 | int echo(int value) {
42 | return value;
43 | }
44 |
45 | NSString* text = @" \
46 | [OCCfuntionHelper defineCFunction:@\"echo\" types:@\"int, int\"]; \
47 | return echo(1024);";
48 |
49 | ASTNode* root = [ASTUtil parseString:text];
50 | ASTVariable* result = [root execute];
51 | NSAssert([result.value doubleValue] == 1024, nil);
52 | ```
53 |
54 | #### 动态添加Property
55 |
56 | ```
57 | NSString* text = @" \
58 | [OCCfuntionHelper defineCFunction:@\"objc_setAssociatedObject\" types:@\"void,id,void *,id,unsigned int\"];\
59 | [OCCfuntionHelper defineCFunction:@\"objc_getAssociatedObject\" types:@\"id,id,void *\"];\
60 | NSString* key = @\"key\"; \
61 | objc_setAssociatedObject(self, key, @(1024), 1);\
62 | return objc_getAssociatedObject(self, key);";
63 |
64 | ASTNode* root = [ASTUtil parseString:text];
65 | ASTVariable* result = [root execute];
66 | NSAssert([result.value doubleValue] == 1024, nil);
67 | ```
68 |
69 | #### 已支持语法
70 |
71 | * [x] if/else while do/while for
72 | * [x] return break continue
73 | * [x] i++ i-- ++i --i
74 | * [x] +i -i !i
75 | * [x] + - * / %等四则运算
76 | * [x] >> << & | ^ 等位运算
77 | * [x] && || >= <= != > < 等比较运算
78 | * [x] ?:
79 | * [x] __block
80 | * [x] array[i] dict[@""]
81 | * [x] @666 @() @[] @{}
82 | * [x] self super
83 | * [x] self.property
84 | * [x] self->_property
85 | * [x] most of objective-c keyword
86 |
87 | ## TODO
88 | * [ ] @available()
89 | * [ ] [NSString stringWithFormat:"%d",value] : use [NSString stringWithFormat:"%@",@(value)] instead。
90 | * [ ] dispatch_async / dispatch_after ...
91 | * [ ] *stop =YES, in block
92 | * [ ] fix bugs
93 |
94 | ## 联系方式
95 |
96 | - GitHub : [letqingbin](https://github.com/letqingbin)
97 | - Email : letqingbin@163.com
98 |
99 | ### Warnning
100 |
101 | ```
102 | 纯粹是技术分享,鉴于JSPath的被禁,不建议用于上架Appstore。
103 | ```
104 |
105 | ### License
106 |
107 | ```
108 | Copyright (c) 2019 letqingbin
109 | Licensed under MIT or later
110 | ```
111 |
112 | DynamicOC required features are based on or derives from projects below:
113 | - MIT
114 | - [JSPatch](https://github.com/bang590/JSPatch)
115 | - [Aspects](https://github.com/steipete/Aspects)
116 | - [OCEval](https://github.com/lilidan/OCEval)
117 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [中文介绍](https://github.com/letqingbin/DynamicOC/blob/master/README-chs.md) | [原理介绍](https://github.com/letqingbin/DynamicOC/blob/master/principle_chs.md)
2 |
3 | # DynamicOC
4 | A hotfix library based on flex/yacc. You can call any Objective-C class and method using DynamicOC.
5 | DynamicOC is functionally similar to [JSPath](https://github.com/bang590/JSPatch), but it only needs to write native OC syntax to implement hotfix.
6 |
7 | ## Features
8 |
9 | - dynamically execute Objective-C code
10 | - dynamically execute C function and block
11 | - dynamically add property
12 | - dynamically replace method
13 | - dynamically add method
14 | - Completed and detailed unit test
15 | - powerful OC syntax parser based on flex/yacc
16 | - support CGRect/CGSize/CGPoint/NSRange/UIEdgeInsets/CGAffineTransform C-struct
17 | ...
18 |
19 | ## Basic Usage
20 |
21 | #### dynamically execute block
22 |
23 | ```
24 | NSString* text = @" \
25 | __block int result = 0;\
26 | UIView* view = [[UIView alloc]init];\
27 | void(^blk)(int value) = ^(int value){\
28 | view.tag = value;\
29 | };\
30 | blk(1024);\
31 | return view.tag;";
32 |
33 | ASTNode* root = [ASTUtil parseString:text];
34 | ASTVariable* result = [root execute];
35 | NSAssert([result.value doubleValue] == 1024, nil);
36 | ```
37 |
38 | #### dynamically execute C function
39 |
40 | ```
41 | int echo(int value) {
42 | return value;
43 | }
44 |
45 | NSString* text = @" \
46 | [OCCfuntionHelper defineCFunction:@\"echo\" types:@\"int, int\"]; \
47 | return echo(1024);";
48 |
49 | ASTNode* root = [ASTUtil parseString:text];
50 | ASTVariable* result = [root execute];
51 | NSAssert([result.value doubleValue] == 1024, nil);
52 | ```
53 |
54 | #### dynamically add property
55 |
56 | ```
57 | NSString* text = @" \
58 | [OCCfuntionHelper defineCFunction:@\"objc_setAssociatedObject\" types:@\"void,id,void *,id,unsigned int\"];\
59 | [OCCfuntionHelper defineCFunction:@\"objc_getAssociatedObject\" types:@\"id,id,void *\"];\
60 | NSString* key = @\"key\"; \
61 | objc_setAssociatedObject(self, key, @(1024), 1);\
62 | return objc_getAssociatedObject(self, key);";
63 |
64 | ASTNode* root = [ASTUtil parseString:text];
65 | ASTVariable* result = [root execute];
66 | NSAssert([result.value doubleValue] == 1024, nil);
67 | ```
68 |
69 | #### Supported Syntax
70 |
71 | * [x] if/else while do/while for
72 | * [x] return break continue
73 | * [x] i++ i-- ++i --i
74 | * [x] +i -i !i
75 | * [x] + - * / % Arithmetic operation
76 | * [x] >> << & | ^ Bit operation
77 | * [x] && || >= <= != > < Compare operation
78 | * [x] ?:
79 | * [x] __block
80 | * [x] array[i] dict[@""]
81 | * [x] @666 @() @[] @{}
82 | * [x] self super
83 | * [x] self.property
84 | * [x] self->_property
85 | * [x] most of objective-c keyword
86 |
87 | ## TODO
88 | * [ ] @available()
89 | * [ ] [NSString stringWithFormat:"%d",value] : use [NSString stringWithFormat:"%@",@(value)] instead。
90 | * [ ] dispatch_async / dispatch_after ...
91 | * [ ] *stop =YES, in block
92 | * [ ] fix bugs
93 |
94 | ## Communication
95 |
96 | - GitHub : [letqingbin](https://github.com/letqingbin)
97 | - Email : letqingbin@163.com
98 |
99 | ### Warnning
100 |
101 | ```
102 | Purely technology sharing, DO NOT Sheld to appstore!
103 | ```
104 |
105 | ### License
106 |
107 | ```
108 | Copyright (c) 2019 letqingbin
109 | Licensed under MIT or later
110 | ```
111 |
112 | DynamicOC required features are based on or derives from projects below:
113 | - MIT
114 | - [JSPatch](https://github.com/bang590/JSPatch)
115 | - [Aspects](https://github.com/steipete/Aspects)
116 | - [OCEval](https://github.com/lilidan/OCEval)
117 |
--------------------------------------------------------------------------------
/principle_chs.md:
--------------------------------------------------------------------------------
1 | # iOS 动态化热修复方案
2 |
3 | ### 前言
4 |
5 | iOS热修复方案经过JSPatch事件后,也消停了很久。bang神在[《JSPatch – 动态更新iOS APP》](http://blog.cnbang.net/works/2767/)中曾提到,为了更符合Apple的规则,即[《Apple Developer Program License Agreement》 ](http://dev.hel.fi/paatokset/media/att/9a/9aa5692b91f2b538eeb352c425b3e66c09e6b1a5.pdf)里3.3.2提到的不可动态下发可执行代码。
6 | JSPatch特地绕了js的圈子,从而实现曲线救国、实现热更新的方案。但是事实证明了Apple对于这种方案也是不认可的,根本的原因还是在于JSPath做得太过极致--支持绝大部分的OC/C语法。
7 |
8 | ### 思考
9 |
10 | 既然JSPatch绕道js的方法,已经被Apple拒绝了,那么就再次回到原点,重新出发。新的框架或者新的方案我觉得至少有一个充分条件,就是不能太极致。
11 | Objective-C作为一种动态的语言,因此能够动态执行所有OC语法是正常的,Aspects类似的框架也是被Apple认可的。至于是否需要运行所有的C函数,这个有待商榷。
12 | 第二个方面,则是放弃javascript/lua等类似语言作为更新的脚本,而是采用原生的Objective-C作为更新的脚本语言。
13 |
14 | #### 动态运行C函数
15 |
16 | C语言是没有反射机制的,作为一门编译型语言,在编译期间就已经生成机器码。因此如果要从字符串中获取到对应的函数指针,那么大概有两种方法:
17 |
18 | - 建立映射表, 将函数名和函数指针建立一个映射表。
19 | - dlsym, 根据动态链接库操作句柄与符号,返回符号对应的地址。
20 |
21 | 第二种是目前JSPatch采用的办法,当然也被Apple警告了。dlsym功能非常强悍,是获取函数指针的最优解。
22 | 第一种局限性非常大,但是没有用到黑魔法。
23 |
24 | #### 采用Objective-C作为更新的脚本语言
25 | 通过flex/yacc,直接解析Objective-C语法,不再采取js/lua等脚本语言。
26 |
27 | ### DynamicOC
28 | 经过上面的思考,在最近业余中做了[DynamicOC](https://github.com/letqingbin/DynamicOC)的项目,百分百原生支持采用Objective-C作为更新的脚本语言。
29 | 当然动态运行C函数还是采用dlsym获取函数指针的办法,后面会逐步改为映射表的做法。
30 |
31 | #### 原理
32 |
33 | [DynamicOC](https://github.com/letqingbin/DynamicOC)使用flex/yacc进行词法解析和语法分析,转为一颗语法生成树AST。
34 | 然后通过解析每个节点,从而执行相应的代码。因为采用的是Objective-C作为脚本语言,因此极容易适配。
35 |
36 | #### 功能特点
37 |
38 | - 动态执行OC代码
39 | - 动态执行C函数和block异步调用
40 | - 动态添加属性
41 | - 动态替换方法
42 | - 动态添加方法
43 | - 有完善的单元测试
44 | - flex/yacc实现强大的OC语法解析器
45 | - 支持CGRect/CGSize/CGPoint/NSRange/UIEdgeInsets/CGAffineTransform常用结构体
46 | ...
47 |
48 | ### 基本用法
49 |
50 | #### 动态执行block
51 |
52 | ```
53 | NSString* text = @" \
54 | __block int result = 0;\
55 | UIView* view = [[UIView alloc]init];\
56 | void(^blk)(int value) = ^(int value){\
57 | view.tag = value;\
58 | };\
59 | blk(1024);\
60 | return view.tag;";
61 |
62 | ASTNode* root = [ASTUtil parseString:text];
63 | ASTVariable* result = [root execute];
64 | NSAssert([result.value doubleValue] == 1024, nil);
65 | ```
66 |
67 | #### 动态执行C函数
68 |
69 | ```
70 | int echo(int value) {
71 | return value;
72 | }
73 |
74 | NSString* text = @" \
75 | [OCCfuntionHelper defineCFunction:@\"echo\" types:@\"int, int\"]; \
76 | return echo(1024);";
77 |
78 | ASTNode* root = [ASTUtil parseString:text];
79 | ASTVariable* result = [root execute];
80 | NSAssert([result.value doubleValue] == 1024, nil);
81 | ```
82 |
83 | #### 动态添加Property
84 |
85 | ```
86 | NSString* text = @" \
87 | [OCCfuntionHelper defineCFunction:@\"objc_setAssociatedObject\" types:@\"void,id,void *,id,unsigned int\"];\
88 | [OCCfuntionHelper defineCFunction:@\"objc_getAssociatedObject\" types:@\"id,id,void *\"];\
89 | NSString* key = @\"key\"; \
90 | objc_setAssociatedObject(self, key, @(1024), 1);\
91 | return objc_getAssociatedObject(self, key);";
92 |
93 | ASTNode* root = [ASTUtil parseString:text];
94 | ASTVariable* result = [root execute];
95 | NSAssert([result.value doubleValue] == 1024, nil);
96 | ```
97 |
98 | #### 已支持语法
99 |
100 | * [x] if/else while do/while for
101 | * [x] return break continue
102 | * [x] i++ i-- ++i --i
103 | * [x] +i -i !i
104 | * [x] + - * / %等四则运算
105 | * [x] >> << & | ^ 等位运算
106 | * [x] && || >= <= != > < 等比较运算
107 | * [x] ?:
108 | * [x] __block
109 | * [x] array[i] dict[@""]
110 | * [x] @666 @() @[] @{}
111 | * [x] self super
112 | * [x] self.property
113 | * [x] self->_property
114 | * [x] most of objective-c keyword
115 |
116 | ### TODO
117 | * [ ] @available()
118 | * [ ] [NSString stringWithFormat:"%d",value] : use [NSString stringWithFormat:"%@",@(value)] instead。
119 | * [ ] dispatch_async / dispatch_after ...
120 | * [ ] *stop =YES, in block
121 | * [ ] fix bugs
122 |
123 |
124 | ### Warnning
125 |
126 | ```
127 | 纯粹是技术分享,鉴于JSPath的被禁,不建议用于上架Appstore。
128 | ```
129 |
130 | ## 参考链接
131 | [JSPatch – 动态更新iOS APP](http://blog.cnbang.net/works/2767/)
132 |
133 | [iOS 动态化的故事](http://blog.cnbang.net/tech/3286/)
134 |
135 | [Apple Developer Program License Agreement ](http://dev.hel.fi/paatokset/media/att/9a/9aa5692b91f2b538eeb352c425b3e66c09e6b1a5.pdf)
136 |
137 | [滴滴 iOS 动态化方案 DynamicCocoa 的诞生与起航](http://www.cocoachina.com/articles/18400)
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
--------------------------------------------------------------------------------