PageRenderTime 42ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/FScriptFramework/FSBlock.m

https://github.com/DottedGecko/F-Script
Objective C | 865 lines | 669 code | 142 blank | 54 comment | 102 complexity | 128059954dee32ecdd2367d321c2a563 MD5 | raw file
  1. /* FSBlock.m Copyright (c) 1998-2009 Philippe Mougin. */
  2. /* This software is open source. See the license. */
  3. #import "build_config.h"
  4. #import "FSBlock.h"
  5. #import "BlockPrivate.h"
  6. #import "BlockRep.h"
  7. #import "FSExecEngine.h"
  8. #import "FSCompiler.h"
  9. #import "FSArray.h"
  10. #import "FSNSArrayPrivate.h"
  11. #import "ArrayPrivate.h"
  12. #import <Foundation/Foundation.h>
  13. #import "FSBooleanPrivate.h"
  14. #import "BlockInspector.h"
  15. #import "FScriptFunctions.h"
  16. #import "FSNumber.h"
  17. #import "FSVoid.h"
  18. #import "FSMiscTools.h"
  19. #import "FSNSString.h"
  20. #import "FSInterpreterResultPrivate.h"
  21. #import "FSReturnSignal.h"
  22. #import "Block_fscript.h"
  23. void __attribute__ ((constructor)) initializeFSBlock(void)
  24. {
  25. [NSKeyedUnarchiver setClass:[FSBlock class] forClassName:@"Block"];
  26. [NSUnarchiver decodeClassName:@"Block" asClassName:@"FSBlock"];
  27. }
  28. NSString *FS_Block_keyOfSetValueForKeyMessage(FSBlock *s)
  29. {
  30. if (s == nil) return nil;
  31. @try
  32. {
  33. [s compilIfNeeded];
  34. }
  35. @catch (id exception)
  36. {
  37. return nil;
  38. }
  39. return [[s blockRep] keyOfSetValueForKeyMessage];
  40. }
  41. @implementation FSBlock
  42. /////////////////// Experimental
  43. /*-(NSString *)generateApplication:(NSString *)applicationName
  44. {
  45. NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"blockExec" ofType:@"app"];
  46. NSString *destinationPath = [[NSHomeDirectory() stringByAppendingPathComponent:applicationName] stringByAppendingPathExtension:@"app"];
  47. NSString *blockSourceCodePath = [[[destinationPath stringByAppendingPathComponent:@"Contents"] stringByAppendingPathComponent:@"Resources"] stringByAppendingPathComponent:@"block.txt"];
  48. [[NSFileManager defaultManager] copyPath:sourcePath toPath:destinationPath handler:nil];
  49. [[self printString] writeToFile:blockSourceCodePath atomically:YES];
  50. return nil;
  51. }*/
  52. ///////////////////
  53. + (id) alloc
  54. {
  55. return NSAllocateObject(self, 0, NULL);
  56. }
  57. + (id)allocWithZone:(NSZone *)zone
  58. {
  59. return NSAllocateObject(self, 0, NULL);
  60. }
  61. + (id)blockWithSelector:(SEL)theSelector
  62. {
  63. return [[@"#" stringByAppendingString:[FSCompiler stringFromSelector:theSelector]] asBlock];
  64. }
  65. + (id)blockWithSource:(NSString *)source parentSymbolTable:(FSSymbolTable *)parentSymbolTable
  66. {
  67. return [self blockWithSource:source parentSymbolTable:parentSymbolTable onError:nil];
  68. }
  69. + (id)blockWithSource:(NSString *)source parentSymbolTable:(FSSymbolTable *)parentSymbolTable onError:(FSBlock *)errorBlock
  70. {
  71. struct BlockSignature signature = {0,NO};
  72. FSBlock *r = [[[self alloc] initWithCode:nil symbolTable:parentSymbolTable signature:signature source:[[source copy] autorelease] isCompiled:NO isCompact:NO sel:(SEL)0 selStr:nil] autorelease];
  73. return [r compilOnError:errorBlock];
  74. }
  75. + (void)initialize
  76. {
  77. static BOOL tooLate = NO;
  78. if ( !tooLate ) {
  79. tooLate = YES;
  80. }
  81. }
  82. - (NSArray *)argumentsNames
  83. {
  84. return [blockRep argumentsNames];
  85. }
  86. - (id)ast
  87. {
  88. [self compilIfNeeded];
  89. return [blockRep ast];
  90. }
  91. - (void) compilIfNeeded {[self compilOnError:nil];} // May raise
  92. - (id)compilOnError:(FSBlock *)errorBlock // May raise
  93. {
  94. [self sync];
  95. return [blockRep compilForBlock:self onError:errorBlock];
  96. }
  97. - (id)copy
  98. { return [self copyWithZone:NULL]; }
  99. - (id)copyWithZone:(NSZone *)zone
  100. {
  101. [self compilIfNeeded];
  102. // Blocks can share the same BlockRep only if they have no local symbols.
  103. if ([blockRep signature].hasLocals)
  104. {
  105. // The block has local symbols
  106. BlockRep *new = [blockRep copyWithZone:zone];
  107. FSBlock *r =[[FSBlock allocWithZone:zone] initWithBlockRep:new];
  108. [new release];
  109. return r;
  110. }
  111. else
  112. {
  113. //NSLog(@"no copy of %@",self);
  114. return [[FSBlock allocWithZone:zone] initWithBlockRep:blockRep];
  115. }
  116. }
  117. - (void)dealloc
  118. {
  119. //NSLog(@"FSBlock dealloc");
  120. [blockRep useRelease];
  121. [blockRep release];
  122. [inspector release];
  123. [super dealloc];
  124. }
  125. - (void)encodeWithCoder:(NSCoder *)coder
  126. {
  127. [self sync];
  128. if ( [coder allowsKeyedCoding] )
  129. {
  130. [coder encodeObject:blockRep forKey:@"FSBlock blockRep"];
  131. }
  132. else
  133. {
  134. [coder encodeObject:blockRep];
  135. }
  136. }
  137. - (FSInterpreterResult *)executeWithArguments:(NSArray *)arguments
  138. {
  139. [self sync];
  140. if (![arguments isKindOfClass:[NSArray class]])
  141. [NSException raise:NSInvalidArgumentException format:@"argument of method \"executeWithArguments:\" must be an NSArray"];
  142. return [blockRep executeWithArguments:arguments block:self];
  143. }
  144. - (NSUInteger) hash
  145. {
  146. BOOL isCompact = NO;
  147. @try
  148. {
  149. isCompact = [self isCompact]; // will cause the block to be compiled if needed and thus may raise.
  150. }
  151. @catch (id exception) {}
  152. if (isCompact) return [[blockRep selectorStr] hash];
  153. else return [super hash];
  154. }
  155. - (id) initWithBlockRep:(BlockRep *)theBlockRep
  156. {
  157. if ((self = [super init]))
  158. {
  159. retainCount = 1;
  160. blockRep = [[theBlockRep retain] useRetain];
  161. inspector = nil;
  162. return self;
  163. }
  164. return nil;
  165. }
  166. - (id)initWithCoder:(NSCoder *)coder
  167. {
  168. self = [super init];
  169. retainCount = 1; // It is important that this initialization is made before decoding
  170. // the blockRep because in decoding blockRep, some retain may be sent to this block
  171. if ( [coder allowsKeyedCoding] )
  172. {
  173. blockRep = [[[coder decodeObjectForKey:@"FSBlock blockRep"] retain] useRetain];
  174. if (blockRep == nil)
  175. // Use the old key name
  176. blockRep = [[[coder decodeObjectForKey:@"Block blockRep"] retain] useRetain];
  177. }
  178. else
  179. {
  180. blockRep = [[[coder decodeObject] retain] useRetain];
  181. }
  182. inspector = nil;
  183. return self;
  184. }
  185. - (id)initWithCode:(FSCNBase *)theCode symbolTable:(FSSymbolTable*)theSymbolTable signature:(struct BlockSignature)theSignature source:(NSString*)theSource isCompiled:(BOOL)is_comp isCompact:(BOOL)isCompactArg sel:(SEL)theSel selStr:(NSString*)theSelStr
  186. {
  187. if ((self = [super init]))
  188. {
  189. blockRep = [[BlockRep alloc] initWithCode:theCode symbolTable:theSymbolTable signature:theSignature source:theSource isCompiled:is_comp isCompact:isCompactArg sel:theSel selStr:theSelStr];
  190. [blockRep useRetain];
  191. inspector = nil;
  192. retainCount = 1;
  193. return self;
  194. }
  195. return nil;
  196. }
  197. - (BOOL) isCompact
  198. {
  199. [self compilIfNeeded]; // may raise
  200. return [blockRep isCompact];
  201. }
  202. - (BOOL) isEqual:anObject
  203. {
  204. BOOL r = NO;
  205. if (self == anObject)
  206. return YES;
  207. else if ([anObject isKindOfClass:[FSBlock class]])
  208. {
  209. @try
  210. {
  211. r = [self isCompact] && [(FSBlock *)anObject isCompact] && // may raise
  212. [blockRep selector] == [((FSBlock *)anObject)->blockRep selector];
  213. }
  214. @catch (id exception) {}
  215. }
  216. return r;
  217. }
  218. - (BOOL)isKindOfClass:(Class)aClass // For backward compatibility with code referencing the old Block class, we pretend to be a Block
  219. {
  220. if (aClass == [Block class])
  221. return YES;
  222. else
  223. return [super isKindOfClass:aClass];
  224. }
  225. - (BOOL)isMemberOfClass:(Class)aClass // For backward compatibility with code referencing the old Block class, we pretend to be a Block
  226. {
  227. if (aClass == [Block class])
  228. return YES;
  229. else
  230. return [super isMemberOfClass:aClass];
  231. }
  232. - (FSMsgContext *)msgContext
  233. {
  234. [self compilIfNeeded]; // may raise
  235. return [blockRep msgContext];
  236. }
  237. - (id)retain
  238. {
  239. retainCount++;
  240. return self;
  241. }
  242. - (NSUInteger)retainCount
  243. {
  244. return retainCount;
  245. }
  246. - (void)release
  247. {
  248. if (--retainCount == 0) [self dealloc];
  249. }
  250. - (SEL) selector
  251. {
  252. [self compilIfNeeded]; // may raise
  253. return [blockRep selector];
  254. }
  255. - (NSString *)selectorStr
  256. {
  257. [self compilIfNeeded]; // may raise
  258. return [blockRep selectorStr];
  259. }
  260. - (void) setInterpreter:(FSInterpreter *)theInterpreter
  261. {
  262. [blockRep setInterpreter:theInterpreter];
  263. }
  264. - (void)showError:(NSString*)errorMessage
  265. {
  266. [[self inspector] showError:errorMessage];
  267. }
  268. - (void)showError:(NSString*)errorMessage start:(NSInteger)firstCharacterIndex end:(NSInteger)lastCharacterIndex
  269. {
  270. [[self inspector] showError:errorMessage start:firstCharacterIndex end:lastCharacterIndex];
  271. }
  272. -(FSSymbolTable *) symbolTable
  273. { return [blockRep symbolTable];}
  274. -(id) valueArgs:(id*)args count:(NSUInteger)count
  275. {
  276. [self compilIfNeeded];
  277. return [blockRep valueArgs:args count:count block:self];
  278. }
  279. //////////////////////////////// USER METHODS ////////////////////////////
  280. - (NSInteger) argumentCount { [self compilIfNeeded]; return [blockRep argumentCount];}
  281. /*- (void) bind:(NSString *)name to:(id)anObject
  282. {
  283. if (![name isKindOfClass:[NSString class]]) FSArgumentError(name,1,@"NSString",@"bind:to:");
  284. [self compilIfNeeded];
  285. [blockRep bind:name to:anObject];
  286. }
  287. - (id) binding:(NSString*)name
  288. {
  289. if (![name isKindOfClass:[NSString class]]) FSArgumentError(name,1,@"NSString",@"binding:");
  290. [self compilIfNeeded];
  291. return [blockRep binding:name];
  292. }*/
  293. - (id)blockFromString:(NSString *)source // May raise
  294. {
  295. FSVerifClassArgsNoNil(@"blockFromString:",1,source,[NSString class]);
  296. [self compilIfNeeded];
  297. return [FSBlock blockWithSource:source parentSymbolTable:[blockRep symbolTable]];
  298. }
  299. - (id)blockFromString:(NSString *)source onError:(FSBlock *)errorBlock // May raise
  300. {
  301. FSVerifClassArgsNoNil(@"blockFromString:onError",2,source,[NSString class],errorBlock,[FSBlock class]);
  302. [self compilIfNeeded];
  303. return [FSBlock blockWithSource:source parentSymbolTable:[blockRep symbolTable] onError:errorBlock];
  304. }
  305. - (FSBlock *) clone
  306. { return [[self copy] autorelease]; }
  307. - (NSString *)description
  308. {
  309. [self sync];
  310. return [[[blockRep source] copy] autorelease];
  311. }
  312. - (id) guardedValue:(id)arg1
  313. {
  314. FSInterpreterResult *interpreterResult = [self executeWithArguments:[FSArray arrayWithObject:arg1]]; // We use an FSArray instead of NSArray because arg1 might be nil
  315. if ([interpreterResult isOk])
  316. {
  317. return [interpreterResult result];
  318. }
  319. else
  320. {
  321. [self showError:[interpreterResult errorMessage]]; // usefull if the call stack is empty
  322. [interpreterResult inspectBlocksInCallStack];
  323. return nil;
  324. }
  325. }
  326. - (void) inspect
  327. {
  328. [[self inspector] activate];
  329. }
  330. - (id)onException:(FSBlock *)handler
  331. {
  332. FSVerifClassArgs(@"onException:",1,handler,[FSBlock class],(NSInteger)1);
  333. if ([self argumentCount] != 0) FSExecError(@"receiver of message \"onException:\" must be a block with no argument");
  334. if ([handler argumentCount] > 1) FSExecError(@"argument of method \"onException:\" must be a block with zero or one argument (the actual argument will be the exception)");
  335. @try
  336. {
  337. return [self value];
  338. }
  339. @catch (FSReturnSignal *returnSignal)
  340. {
  341. @throw;
  342. }
  343. @catch (id exception)
  344. {
  345. return [handler value:exception];
  346. }
  347. assert(0); // we'll never reach this code.
  348. return nil; // to disable a warning
  349. }
  350. - (FSBoolean *)operator_equal:(id)operand
  351. {
  352. return ([self isEqual:operand] ? fsTrue : fsFalse);
  353. }
  354. - (FSBoolean *)operator_tilde_equal:(id)operand
  355. {
  356. return (![self isEqual:operand] ? fsTrue : fsFalse);
  357. }
  358. - (void) return { [self return:[FSVoid fsVoid]]; }
  359. - (void) return:(id)rv
  360. {
  361. @throw [FSReturnSignal returnSignalWithBlock:self result:rv];
  362. }
  363. - (void) setValue:(FSBlock*)val
  364. {
  365. BlockRep *oldRep;
  366. FSVerifClassArgsNoNil(@"setValue:",1,val,[FSBlock class]);
  367. if (val == self) return;
  368. [val compilIfNeeded];
  369. oldRep = blockRep;
  370. // Blocks can share the same BlockRep only if they have no local symbols.
  371. if ([[val blockRep] signature].hasLocals)
  372. // The block val has local symbols
  373. blockRep = [[[val blockRep] copyWithZone:[self zone]] useRetain];
  374. else
  375. blockRep = [[[val blockRep] retain] useRetain];
  376. [oldRep useRelease];
  377. [oldRep release];
  378. [inspector update];
  379. [[NSNotificationQueue defaultQueue] enqueueNotification:[NSNotification notificationWithName:@"BlockDidChangeNotification" object:self] postingStyle:NSPostWhenIdle];
  380. }
  381. - (id) value
  382. { return [self valueArgs:(id*)nil count:1];}
  383. - (id) value:(id)arg1
  384. {
  385. id args[2] = {arg1,nil};
  386. return [self valueArgs:args count:2];
  387. }
  388. - (id) value:(id)arg1 value:(id)arg2
  389. {
  390. id args[3] = {arg1,nil,arg2};
  391. return [self valueArgs:args count:3];
  392. }
  393. - (id) value:(id)arg1 value:(id)arg2 value:(id)arg3
  394. {
  395. id args[4] = {arg1,nil,arg2,arg3};
  396. return [self valueArgs:args count:4];
  397. }
  398. - (id) value:(id)arg1 value:(id)arg2 value:(id)arg3 value:(id)arg4
  399. {
  400. id args[5] = {arg1,nil,arg2,arg3,arg4};
  401. return [self valueArgs:args count:5];
  402. }
  403. - (id) value:(id)arg1 value:(id)arg2 value:(id)arg3 value:(id)arg4 value:(id)arg5
  404. {
  405. id args[6] = {arg1,nil,arg2,arg3,arg4,arg5};
  406. return [self valueArgs:args count:6];
  407. }
  408. - (id) value:(id)arg1 value:(id)arg2 value:(id)arg3 value:(id)arg4 value:(id)arg5 value:(id)arg6
  409. {
  410. id args[7] = {arg1,nil,arg2,arg3,arg4,arg5,arg6};
  411. return [self valueArgs:args count:7];
  412. }
  413. - (id) value:(id)arg1 value:(id)arg2 value:(id)arg3 value:(id)arg4 value:(id)arg5 value:(id)arg6 value:(id)arg7
  414. {
  415. id args[8] = {arg1,nil,arg2,arg3,arg4,arg5,arg6,arg7};
  416. return [self valueArgs:args count:8];
  417. }
  418. - (id) value:(id)arg1 value:(id)arg2 value:(id)arg3 value:(id)arg4 value:(id)arg5 value:(id)arg6 value:(id)arg7 value:(id)arg8
  419. {
  420. id args[9] = {arg1,nil,arg2,arg3,arg4,arg5,arg6,arg7,arg8};
  421. return [self valueArgs:args count:9];
  422. }
  423. - (id) value:(id)arg1 value:(id)arg2 value:(id)arg3 value:(id)arg4 value:(id)arg5 value:(id)arg6 value:(id)arg7 value:(id)arg8 value:(id)arg9
  424. {
  425. id args[10] = {arg1,nil,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9};
  426. return [self valueArgs:args count:10];
  427. }
  428. - (id) value:(id)arg1 value:(id)arg2 value:(id)arg3 value:(id)arg4 value:(id)arg5 value:(id)arg6 value:(id)arg7 value:(id)arg8 value:(id)arg9 value:(id)arg10
  429. {
  430. id args[11] = {arg1,nil,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10};
  431. return [self valueArgs:args count:11];
  432. }
  433. - (id) value:(id)arg1 value:(id)arg2 value:(id)arg3 value:(id)arg4 value:(id)arg5 value:(id)arg6 value:(id)arg7 value:(id)arg8 value:(id)arg9 value:(id)arg10 value:(id)arg11
  434. {
  435. id args[12] = {arg1,nil,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11};
  436. return [self valueArgs:args count:12];
  437. }
  438. - (id) value:(id)arg1 value:(id)arg2 value:(id)arg3 value:(id)arg4 value:(id)arg5 value:(id)arg6 value:(id)arg7 value:(id)arg8 value:(id)arg9 value:(id)arg10 value:(id)arg11 value:(id)arg12
  439. {
  440. id args[13] = {arg1,nil,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12};
  441. return [self valueArgs:args count:13];
  442. }
  443. - (id) valueWithArguments:(NSArray *)operand
  444. {
  445. VERIF_OP_NSARRAY(@"valueWithArguments:");
  446. [self compilIfNeeded];
  447. return [blockRep valueWithArguments:operand block:self];
  448. }
  449. - (void) whileFalse
  450. {
  451. NSAutoreleasePool *pool;
  452. short i;
  453. BOOL cond = NO; // initialization of cond in order to avoid a warning
  454. id resEval;
  455. [self compilIfNeeded];
  456. if ([self argumentCount] != 0) FSExecError(@"method \"whileFalse\" must be sent to a block with no arguments");
  457. while (1)
  458. {
  459. pool = [[NSAutoreleasePool alloc] init];
  460. i = 0;
  461. while (i < 300 && (cond = ((resEval = [self body_notCompact_valueArgs:(id*)nil count:1]) == fsFalse || ([resEval isKindOfClass:[FSBoolean class]] && ![resEval isTrue]))))
  462. {
  463. i++;
  464. }
  465. [pool release];
  466. if (!cond) break;
  467. }
  468. }
  469. - (void) whileFalse:(FSBlock*)iterationBlock
  470. {
  471. NSAutoreleasePool *pool;
  472. short i;
  473. BOOL cond = NO; //initialization of cond in order to avoid a warning
  474. id resEval;
  475. FSVerifClassArgsNoNil(@"whileFalse:",1,iterationBlock,[FSBlock class]);
  476. [self compilIfNeeded];
  477. if ([self argumentCount] != 0)
  478. FSExecError(@"method \"whileFalse:\" must be called on a block with no arguments");
  479. if ([iterationBlock argumentCount] != 0)
  480. FSExecError(@"argument 1 of method \"whileFalse:\" must be a block with no arguments");
  481. while (1)
  482. {
  483. pool = [[NSAutoreleasePool alloc] init];
  484. i = 0;
  485. while (i < 300 && (cond = ((resEval = [self body_notCompact_valueArgs:(id*)nil count:1]) == fsFalse || ([resEval isKindOfClass:[FSBoolean class]] && ![resEval isTrue]))))
  486. {
  487. i++;
  488. [iterationBlock body_notCompact_valueArgs:(id*)nil count:1];
  489. }
  490. [pool release];
  491. if (!cond) break;
  492. }
  493. }
  494. - (void) whileTrue
  495. {
  496. NSAutoreleasePool *pool;
  497. short i;
  498. BOOL cond = NO; // initialization of cond in order to avoid a warning
  499. id resEval;
  500. [self compilIfNeeded];
  501. if ([self argumentCount] != 0) FSExecError(@"method \"whileTrue\" must be sent to a block with no arguments");
  502. while (1)
  503. {
  504. pool = [[NSAutoreleasePool alloc] init];
  505. i = 0;
  506. while (i < 300 && (cond = ((resEval = [self body_notCompact_valueArgs:(id*)nil count:1]) == fsTrue || ([resEval isKindOfClass:[FSBoolean class]] && [resEval isTrue]))))
  507. {
  508. i++;
  509. }
  510. [pool release];
  511. if (!cond) break;
  512. }
  513. }
  514. - (void) whileTrue:(FSBlock*)iterationBlock
  515. {
  516. NSAutoreleasePool *pool;
  517. short i;
  518. BOOL cond = NO; // initialization of cond in order to avoid a warning
  519. id resEval;
  520. FSVerifClassArgsNoNil(@"whileTrue:",1,iterationBlock,[FSBlock class]);
  521. [self compilIfNeeded];
  522. if ([self argumentCount] != 0)
  523. FSExecError(@"method \"whileTrue:\" must be called on a block with no arguments");
  524. if ([iterationBlock argumentCount] != 0)
  525. FSExecError(@"argument 1 of method \"whileTrue:\" must be a block with no arguments");
  526. while (1)
  527. {
  528. pool = [[NSAutoreleasePool alloc] init];
  529. i = 0;
  530. while (i < 300 && (cond = ((resEval = [self body_notCompact_valueArgs:(id*)nil count:1]) == fsTrue || ([resEval isKindOfClass:[FSBoolean class]] && [resEval isTrue]))))
  531. {
  532. i++;
  533. [iterationBlock body_notCompact_valueArgs:(id*)nil count:1];
  534. }
  535. [pool release];
  536. if (!cond) break;
  537. }
  538. /*while ([self body_notCompact_valueArgs:(id*)nil count:1] == fsTrue)
  539. {
  540. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  541. //short i = 0;
  542. [iterationBlock body_notCompact_valueArgs:(id*)nil count:1];
  543. [pool release];
  544. // i++;
  545. //if (i == 30)
  546. //{
  547. // if (NXUserAborted()) FSUserAborted();
  548. // else i = 0;
  549. //}
  550. } */
  551. }
  552. @end
  553. @implementation FSBlock (FSBlockPrivate)
  554. - (BlockRep *)blockRep { return blockRep;}
  555. -(id)body_compact_valueArgs:(id*)args count:(NSUInteger)count
  556. {
  557. return [blockRep body_compact_valueArgs:args count:count block:self];
  558. }
  559. -(id)body_notCompact_valueArgs:(id*)args count:(NSUInteger)count
  560. {
  561. return [blockRep body_notCompact_valueArgs:args count:count block:self];
  562. }
  563. - (FSBlockCompilationResult *) compilation // Compil the receiver if needed. Return the result of the compilation.
  564. {
  565. [self sync];
  566. return [blockRep compilForBlock:self];
  567. }
  568. - (void)evaluateWithDoubleFrom:(double)start to:(double)stop by:(double)step
  569. // precondition: step != 0
  570. {
  571. FSNumber *args[2]; // In fact an array with the special layout needed for methods
  572. // body_compact_valueArgs:count:block: and body_notCompact_valueArgs:count:block:
  573. double newValue;
  574. NSAutoreleasePool *pool = nil;
  575. if ((start < stop && step < 0) || (start > stop && step > 0)) return;
  576. if (start == stop)
  577. {
  578. [self value:[FSNumber numberWithDouble:start]];
  579. return;
  580. }
  581. [self compilIfNeeded];
  582. @try
  583. {
  584. args[0] = [[FSNumber alloc] initWithDouble:start];
  585. while (1)
  586. {
  587. short i = 0;
  588. pool = [[NSAutoreleasePool alloc] init];
  589. if ([blockRep isCompact])
  590. {
  591. if (start < stop)
  592. {
  593. while (i < 1000 && args[0]->value <= stop)
  594. {
  595. [blockRep body_compact_valueArgs:args count:2 block:self]; // may raise
  596. i++;
  597. newValue = args[0]->value + step;
  598. [args[0] release];
  599. args[0] = [[FSNumber alloc] initWithDouble:newValue];
  600. }
  601. if (args[0]->value > stop)
  602. {
  603. [args[0] release];
  604. break;
  605. }
  606. }
  607. else if (start > stop)
  608. {
  609. while (i < 1000 && args[0]->value >= stop)
  610. {
  611. [blockRep body_compact_valueArgs:args count:2 block:self]; // may raise
  612. i++;
  613. newValue = args[0]->value + step;
  614. [args[0] release];
  615. args[0] = [[FSNumber alloc] initWithDouble:newValue];
  616. }
  617. if (args[0]->value < stop)
  618. {
  619. [args[0] release];
  620. break;
  621. }
  622. }
  623. }
  624. else
  625. {
  626. if (start < stop)
  627. {
  628. while (i < 1000 && args[0]->value <= stop)
  629. {
  630. [blockRep body_notCompact_valueArgs:args count:2 block:self]; // may raise
  631. i++;
  632. newValue = args[0]->value + step;
  633. [args[0] release];
  634. args[0] = [[FSNumber alloc] initWithDouble:newValue];
  635. }
  636. if (args[0]->value > stop)
  637. {
  638. [args[0] release];
  639. break;
  640. }
  641. }
  642. else if (start > stop)
  643. {
  644. while (i < 1000 && args[0]->value >= stop)
  645. {
  646. [blockRep body_notCompact_valueArgs:args count:2 block:self]; // may raise
  647. i++;
  648. newValue = args[0]->value + step;
  649. [args[0] release];
  650. args[0] = [[FSNumber alloc] initWithDouble:newValue];
  651. }
  652. if (args[0]->value < stop)
  653. {
  654. [args[0] release];
  655. break;
  656. }
  657. }
  658. }
  659. [pool release];
  660. }
  661. }
  662. @catch (id exception)
  663. {
  664. [exception retain];
  665. [pool release];
  666. [args[0] release];
  667. [exception autorelease];
  668. @throw;
  669. }
  670. }
  671. - (BlockInspector *)inspector
  672. {
  673. if (!inspector) inspector = [[BlockInspector alloc] initWithBlock:self];
  674. return inspector;
  675. }
  676. - (SEL)messageToArgumentSelector
  677. {
  678. @try
  679. {
  680. [self compilIfNeeded];
  681. }
  682. @catch (id exception)
  683. {
  684. return (SEL)0;
  685. }
  686. return [blockRep messageToArgumentSelector];
  687. }
  688. -(FSBlock *) totalCopy
  689. {
  690. BlockRep *new;
  691. FSBlock *r;
  692. [self sync];
  693. new = [blockRep copy];
  694. r =[[FSBlock alloc] initWithBlockRep:new];
  695. [new release];
  696. return r;
  697. }
  698. - (void) setNewRepAfterCompilation:(BlockRep*)newRep
  699. {
  700. [newRep retain]; [newRep useRetain];
  701. [blockRep useRelease]; [blockRep release];
  702. blockRep = newRep;
  703. }
  704. - (id)sync
  705. {
  706. if ([inspector edited])
  707. {
  708. BlockRep * new = [blockRep copy];
  709. [new newSource:[inspector source]];
  710. [blockRep useRelease];
  711. [blockRep release];
  712. blockRep = new;
  713. [blockRep useRetain];
  714. [inspector setEdited:NO];
  715. }
  716. return self;
  717. }
  718. @end