├── .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 | --------------------------------------------------------------------------------