├── README.markdown ├── Statec.xcodeproj └── project.pbxproj ├── Statec ├── Builder │ ├── StatecArgument.h │ ├── StatecArgument.m │ ├── StatecClass.h │ ├── StatecClass.m │ ├── StatecCodeStatement.h │ ├── StatecCodeStatement.m │ ├── StatecCompilationUnit.h │ ├── StatecCompilationUnit.m │ ├── StatecConditionalStatement.h │ ├── StatecConditionalStatement.m │ ├── StatecEnumeration.h │ ├── StatecEnumeration.m │ ├── StatecGVBuilder.h │ ├── StatecGVBuilder.m │ ├── StatecHTMLBuilder.h │ ├── StatecHTMLBuilder.m │ ├── StatecMethod.h │ ├── StatecMethod.m │ ├── StatecProperty.h │ ├── StatecProperty.m │ ├── StatecStatement.h │ ├── StatecStatement.m │ ├── StatecStatementGroup.h │ ├── StatecStatementGroup.m │ ├── StatecType.h │ ├── StatecType.m │ ├── StatecTypedef.h │ ├── StatecTypedef.m │ ├── StatecVariable.h │ └── StatecVariable.m ├── Categories │ ├── NSString+StatecExtensions.h │ └── NSString+StatecExtensions.m ├── Compiler │ ├── StatecCompiler.h │ └── StatecCompiler.m ├── Parser │ ├── StatecEnter.h │ ├── StatecEnter.m │ ├── StatecExit.h │ ├── StatecExit.m │ ├── StatecInitial.h │ ├── StatecInitial.m │ ├── StatecMachine.h │ ├── StatecMachine.m │ ├── StatecParser.h │ ├── StatecParser.m │ ├── StatecState.h │ ├── StatecState.m │ ├── StatecTransition.h │ └── StatecTransition.m ├── Statec-Prefix.pch ├── Statec.1 ├── Statec.h ├── StatecEvent.h ├── StatecEvent.m └── main.m └── StatecRunner ├── StatecAppDelegate.h ├── StatecAppDelegate.m ├── StatecRunner-Info.plist ├── StatecRunner-Prefix.pch ├── en.lproj ├── Credits.rtf ├── InfoPlist.strings └── MainMenu.xib └── main.m /README.markdown: -------------------------------------------------------------------------------- 1 | # statec 2 | 3 | ## introduction 4 | 5 | Pronounced "static", statec is an Objective-C/Foundation tool to compile Obj-C state machine classes from a little language that describes them. 6 | 7 | The goal was to have a simple, clear, language to express a state machine that compiles into an easy to use class to operate them. There are other, similar, tools available for example [SMC](http://smc.sourceforge.net/) or [Ragel](http://www.complang.org/ragel/) which are more comprehensive, support a wide range of languages, and so forth. They are good tools but they did not immediately fit my needs and thus began a monumental exercise in Yak shaving. 8 | 9 | Two days later and I have a "little language" for expressing state machines that is parsed - using a parser built with Tom Davie's [CoreParse](https://github.com/beelsebob/CoreParse) framework (itself quite young but promising) - into an intermediate representation of a machine and then converted directly into Objective-C source using an Objective-C code generator framework built as part of the framework. 10 | 11 | Similar to the approach taken by Rentzsch's [mogenerator](https://github.com/rentzsch/mogenerator) statec generates two classes for each machine, a completely generated implementation class and a user-managed class that subclasses it. The implementation provides methods to respond to state changes that the user-managed class can override to provide context specific processing. 12 | 13 | ## language 14 | 15 | The statec language is a little language for describing state machines. It has a few keywords and a simple structure, here's an example: 16 | 17 |
18 | @machine "TrafficLight" {
19 |   @initial "off"
20 | 	@state "off" {
21 | 		@event "on" => "green"
22 | 	}
23 | 	@state "green" {
24 | 		@enter
25 | 		@exit
26 | 		@event "amber" => "amber"
27 | 		@event "off" => "off"
28 | 	}
29 | 	@state "amber" {
30 | 		@enter
31 | 		@exit
32 | 		@event "green" => "green"
33 | 		@event "red" => "red"
34 | 	}
35 | 	@state "red" {
36 | 		@enter
37 | 		@exit
38 | 		@event "amber" => "amber"
39 | 	}
40 | }
41 | 
42 | 43 |
44 |
@machine
45 |
names the machine and contains its states. The name is used as the basis of the classes generated, in our example they would be _TrafficLightMachine (the implementation class) and TrafficLightMachine (the user class).
46 |
@initial
47 |
defines the initial state of the machine (an enter event is not generated for the machine being started in this state).
48 |
@state
49 |
defines a named state
50 |
@enter
51 |
specifies that a callback (e.g. enterGreenState) should be generated and invoked when the machine enters this state.
52 |
@exit
53 |
specifies than a callback (e.g. exitAmberState) should be generated and invoked before the machine leaves this state.
54 |
@event
55 |
defines a named event and the state the event transitions the machine into. The event name is used to name the event method in the machine (e.g. amberEvent) to cause the transition.
56 |
57 | 58 | The current behaviour is to raise an exception when an event is invoked that is not legal in the current state. In the future this might - optionally - return a condition & NSError instead. 59 | 60 | ## running 61 | 62 | The statec command line tool requires the CoreParse.framework be installed in /Library/Frameworks. 63 | 64 | The statec command line tool has three arguments: 65 | 66 | * -i <machine file> 67 | * e.g. trafficlight.smd 68 | * -d <target folder> 69 | * e.g. ~/Projects/TrafficLightSim/ 70 | * -g 71 | * Generate a GraphViz digraph of the machine and, if the `dot` command is available convert it into a PNG image. 72 | 73 | The generated files should be added to your Xcode project. The *\_<Name>Machine.m* file should not be edited as this will be regenerated every time the statec command is generated. The *<Name>Machine.m* is intended for the user to edit and will not be regenerated if it exists. 74 | 75 | ## machine 76 | 77 | The generated machine does not employ a switch statement or lookup table but, rather, stateless classes that represent the states in the machine and that have methods that represent the available transitions. 78 | 79 | In our example a class `TrafficLightState` is generated along with a subclass for each state, e.g. `TrafficLightOnState`. The `TrafficLightMachine` has a state variable that points at an instance representing the current state. When an event method e.g. `greenEvent` is called on the machine it is passed to the current state class that either transitions the calling machine into a new state (optionally invoking exit & enter callbacks), or raises an exception if the transition is not legal from that state. 80 | -------------------------------------------------------------------------------- /Statec.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C93DC584150296B400007F09 /* StatecCompiler.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743F214D774FC003E2DBA /* StatecCompiler.m */; }; 11 | C93DC5861502971200007F09 /* StatecParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743BE14D6ED3A003E2DBA /* StatecParser.m */; }; 12 | C93DC5871502972A00007F09 /* StatecClass.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743C714D6EE25003E2DBA /* StatecClass.m */; }; 13 | C93DC5881502972A00007F09 /* StatecMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743CD14D6F178003E2DBA /* StatecMethod.m */; }; 14 | C93DC5891502972A00007F09 /* StatecVariable.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743D014D6F189003E2DBA /* StatecVariable.m */; }; 15 | C93DC58A1502972A00007F09 /* StatecProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743D314D6F210003E2DBA /* StatecProperty.m */; }; 16 | C93DC58B1502972A00007F09 /* StatecArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743D714D7326E003E2DBA /* StatecArgument.m */; }; 17 | C93DC58C1502972A00007F09 /* StatecTypedef.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743F814D802E1003E2DBA /* StatecTypedef.m */; }; 18 | C93DC58D1502972A00007F09 /* StatecEnumeration.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743FB14D805C6003E2DBA /* StatecEnumeration.m */; }; 19 | C93DC58E1502972A00007F09 /* StatecType.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743FE14D807A1003E2DBA /* StatecType.m */; }; 20 | C93DC58F1502972A00007F09 /* StatecCompilationUnit.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A7440114D8096A003E2DBA /* StatecCompilationUnit.m */; }; 21 | C93DC5901502972A00007F09 /* StatecCodeStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A7440414D826E3003E2DBA /* StatecCodeStatement.m */; }; 22 | C93DC5911502972A00007F09 /* StatecStatementGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A7440714D8282F003E2DBA /* StatecStatementGroup.m */; }; 23 | C93DC5921502972A00007F09 /* StatecStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A7440A14D82897003E2DBA /* StatecStatement.m */; }; 24 | C93DC5931502972A00007F09 /* StatecConditionalStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = C98F6BD014D844530019E817 /* StatecConditionalStatement.m */; }; 25 | C93DC5941502972A00007F09 /* StatecGVBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = C9ED4AC314DB14C60044BE00 /* StatecGVBuilder.m */; }; 26 | C93DC5951502972A00007F09 /* StatecHTMLBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = C9ED4AC914DB25090044BE00 /* StatecHTMLBuilder.m */; }; 27 | C93DC5961502973400007F09 /* NSString+StatecExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = C9ED4ABD14DAF2620044BE00 /* NSString+StatecExtensions.m */; }; 28 | C93DC5971502974100007F09 /* StatecMachine.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743DF14D765AC003E2DBA /* StatecMachine.m */; }; 29 | C93DC5981502974100007F09 /* StatecInitial.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743E214D76BF2003E2DBA /* StatecInitial.m */; }; 30 | C93DC5991502974100007F09 /* StatecState.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743E514D76C02003E2DBA /* StatecState.m */; }; 31 | C93DC59A1502974100007F09 /* StatecEnter.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743E814D76C13003E2DBA /* StatecEnter.m */; }; 32 | C93DC59B1502974100007F09 /* StatecExit.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743EB14D76C22003E2DBA /* StatecExit.m */; }; 33 | C93DC59C1502974100007F09 /* StatecEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743EE14D76C2E003E2DBA /* StatecEvent.m */; }; 34 | C93DC59D1502974100007F09 /* StatecTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743F514D77826003E2DBA /* StatecTransition.m */; }; 35 | C94349871503983000705EB0 /* CoreParse.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C94349861503983000705EB0 /* CoreParse.framework */; }; 36 | C94349881503983600705EB0 /* CoreParse.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C94349861503983000705EB0 /* CoreParse.framework */; }; 37 | C98F6BD114D844530019E817 /* StatecConditionalStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = C98F6BD014D844530019E817 /* StatecConditionalStatement.m */; }; 38 | C9A743AA14D6ECDE003E2DBA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9A743A914D6ECDE003E2DBA /* Foundation.framework */; }; 39 | C9A743AD14D6ECDE003E2DBA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743AC14D6ECDE003E2DBA /* main.m */; }; 40 | C9A743B114D6ECDE003E2DBA /* Statec.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C9A743B014D6ECDE003E2DBA /* Statec.1 */; }; 41 | C9A743BF14D6ED3A003E2DBA /* StatecParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743BE14D6ED3A003E2DBA /* StatecParser.m */; }; 42 | C9A743C814D6EE25003E2DBA /* StatecClass.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743C714D6EE25003E2DBA /* StatecClass.m */; }; 43 | C9A743CE14D6F178003E2DBA /* StatecMethod.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743CD14D6F178003E2DBA /* StatecMethod.m */; }; 44 | C9A743D114D6F189003E2DBA /* StatecVariable.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743D014D6F189003E2DBA /* StatecVariable.m */; }; 45 | C9A743D414D6F210003E2DBA /* StatecProperty.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743D314D6F210003E2DBA /* StatecProperty.m */; }; 46 | C9A743D814D7326E003E2DBA /* StatecArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743D714D7326E003E2DBA /* StatecArgument.m */; }; 47 | C9A743E014D765AC003E2DBA /* StatecMachine.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743DF14D765AC003E2DBA /* StatecMachine.m */; }; 48 | C9A743E314D76BF2003E2DBA /* StatecInitial.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743E214D76BF2003E2DBA /* StatecInitial.m */; }; 49 | C9A743E614D76C02003E2DBA /* StatecState.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743E514D76C02003E2DBA /* StatecState.m */; }; 50 | C9A743E914D76C13003E2DBA /* StatecEnter.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743E814D76C13003E2DBA /* StatecEnter.m */; }; 51 | C9A743EC14D76C22003E2DBA /* StatecExit.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743EB14D76C22003E2DBA /* StatecExit.m */; }; 52 | C9A743EF14D76C2F003E2DBA /* StatecEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743EE14D76C2E003E2DBA /* StatecEvent.m */; }; 53 | C9A743F314D774FC003E2DBA /* StatecCompiler.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743F214D774FC003E2DBA /* StatecCompiler.m */; }; 54 | C9A743F614D77827003E2DBA /* StatecTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743F514D77826003E2DBA /* StatecTransition.m */; }; 55 | C9A743F914D802E1003E2DBA /* StatecTypedef.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743F814D802E1003E2DBA /* StatecTypedef.m */; }; 56 | C9A743FC14D805C7003E2DBA /* StatecEnumeration.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743FB14D805C6003E2DBA /* StatecEnumeration.m */; }; 57 | C9A743FF14D807A2003E2DBA /* StatecType.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A743FE14D807A1003E2DBA /* StatecType.m */; }; 58 | C9A7440214D8096B003E2DBA /* StatecCompilationUnit.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A7440114D8096A003E2DBA /* StatecCompilationUnit.m */; }; 59 | C9A7440514D826E4003E2DBA /* StatecCodeStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A7440414D826E3003E2DBA /* StatecCodeStatement.m */; }; 60 | C9A7440814D82830003E2DBA /* StatecStatementGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A7440714D8282F003E2DBA /* StatecStatementGroup.m */; }; 61 | C9A7440B14D82897003E2DBA /* StatecStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = C9A7440A14D82897003E2DBA /* StatecStatement.m */; }; 62 | C9ED4A9414DACD7D0044BE00 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9ED4A9314DACD7D0044BE00 /* Cocoa.framework */; }; 63 | C9ED4A9E14DACD7D0044BE00 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C9ED4A9C14DACD7D0044BE00 /* InfoPlist.strings */; }; 64 | C9ED4AA014DACD7D0044BE00 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C9ED4A9F14DACD7D0044BE00 /* main.m */; }; 65 | C9ED4AA414DACD7D0044BE00 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = C9ED4AA214DACD7D0044BE00 /* Credits.rtf */; }; 66 | C9ED4AA714DACD7D0044BE00 /* StatecAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C9ED4AA614DACD7D0044BE00 /* StatecAppDelegate.m */; }; 67 | C9ED4AAA14DACD7D0044BE00 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = C9ED4AA814DACD7D0044BE00 /* MainMenu.xib */; }; 68 | C9ED4ABE14DAF2620044BE00 /* NSString+StatecExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = C9ED4ABD14DAF2620044BE00 /* NSString+StatecExtensions.m */; }; 69 | C9ED4AC414DB14C60044BE00 /* StatecGVBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = C9ED4AC314DB14C60044BE00 /* StatecGVBuilder.m */; }; 70 | C9ED4ACA14DB25090044BE00 /* StatecHTMLBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = C9ED4AC914DB25090044BE00 /* StatecHTMLBuilder.m */; }; 71 | /* End PBXBuildFile section */ 72 | 73 | /* Begin PBXContainerItemProxy section */ 74 | C9ED4AAF14DACD8C0044BE00 /* PBXContainerItemProxy */ = { 75 | isa = PBXContainerItemProxy; 76 | containerPortal = C9A7439C14D6ECDE003E2DBA /* Project object */; 77 | proxyType = 1; 78 | remoteGlobalIDString = C9A743A414D6ECDE003E2DBA; 79 | remoteInfo = Statec; 80 | }; 81 | /* End PBXContainerItemProxy section */ 82 | 83 | /* Begin PBXCopyFilesBuildPhase section */ 84 | C9A743A314D6ECDE003E2DBA /* CopyFiles */ = { 85 | isa = PBXCopyFilesBuildPhase; 86 | buildActionMask = 2147483647; 87 | dstPath = /usr/share/man/man1/; 88 | dstSubfolderSpec = 0; 89 | files = ( 90 | C9A743B114D6ECDE003E2DBA /* Statec.1 in CopyFiles */, 91 | ); 92 | runOnlyForDeploymentPostprocessing = 1; 93 | }; 94 | C9A743B914D6ECF9003E2DBA /* Copy Frameworks */ = { 95 | isa = PBXCopyFilesBuildPhase; 96 | buildActionMask = 2147483647; 97 | dstPath = ""; 98 | dstSubfolderSpec = 10; 99 | files = ( 100 | ); 101 | name = "Copy Frameworks"; 102 | runOnlyForDeploymentPostprocessing = 0; 103 | }; 104 | C9ED4AB114DACDC40044BE00 /* Copy Frameworks */ = { 105 | isa = PBXCopyFilesBuildPhase; 106 | buildActionMask = 2147483647; 107 | dstPath = ""; 108 | dstSubfolderSpec = 10; 109 | files = ( 110 | ); 111 | name = "Copy Frameworks"; 112 | runOnlyForDeploymentPostprocessing = 0; 113 | }; 114 | C9ED4AB314DACDE60044BE00 /* CopyFiles */ = { 115 | isa = PBXCopyFilesBuildPhase; 116 | buildActionMask = 2147483647; 117 | dstPath = ""; 118 | dstSubfolderSpec = 7; 119 | files = ( 120 | ); 121 | runOnlyForDeploymentPostprocessing = 0; 122 | }; 123 | /* End PBXCopyFilesBuildPhase section */ 124 | 125 | /* Begin PBXFileReference section */ 126 | C94349861503983000705EB0 /* CoreParse.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreParse.framework; path = Library/Frameworks/CoreParse.framework; sourceTree = SDKROOT; }; 127 | C98F6BCF14D844520019E817 /* StatecConditionalStatement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecConditionalStatement.h; path = Builder/StatecConditionalStatement.h; sourceTree = ""; }; 128 | C98F6BD014D844530019E817 /* StatecConditionalStatement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecConditionalStatement.m; path = Builder/StatecConditionalStatement.m; sourceTree = ""; }; 129 | C9A743A514D6ECDE003E2DBA /* Statec */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Statec; sourceTree = BUILT_PRODUCTS_DIR; }; 130 | C9A743A914D6ECDE003E2DBA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 131 | C9A743AC14D6ECDE003E2DBA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 132 | C9A743AF14D6ECDE003E2DBA /* Statec-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Statec-Prefix.pch"; sourceTree = ""; }; 133 | C9A743B014D6ECDE003E2DBA /* Statec.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = Statec.1; sourceTree = ""; }; 134 | C9A743BD14D6ED3A003E2DBA /* StatecParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecParser.h; path = Parser/StatecParser.h; sourceTree = ""; }; 135 | C9A743BE14D6ED3A003E2DBA /* StatecParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecParser.m; path = Parser/StatecParser.m; sourceTree = ""; }; 136 | C9A743C614D6EE25003E2DBA /* StatecClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecClass.h; path = Builder/StatecClass.h; sourceTree = ""; }; 137 | C9A743C714D6EE25003E2DBA /* StatecClass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecClass.m; path = Builder/StatecClass.m; sourceTree = ""; }; 138 | C9A743CC14D6F178003E2DBA /* StatecMethod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecMethod.h; path = Builder/StatecMethod.h; sourceTree = ""; }; 139 | C9A743CD14D6F178003E2DBA /* StatecMethod.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecMethod.m; path = Builder/StatecMethod.m; sourceTree = ""; }; 140 | C9A743CF14D6F189003E2DBA /* StatecVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecVariable.h; path = Builder/StatecVariable.h; sourceTree = ""; }; 141 | C9A743D014D6F189003E2DBA /* StatecVariable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecVariable.m; path = Builder/StatecVariable.m; sourceTree = ""; }; 142 | C9A743D214D6F210003E2DBA /* StatecProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecProperty.h; path = Builder/StatecProperty.h; sourceTree = ""; }; 143 | C9A743D314D6F210003E2DBA /* StatecProperty.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecProperty.m; path = Builder/StatecProperty.m; sourceTree = ""; }; 144 | C9A743D514D70BB0003E2DBA /* Statec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Statec.h; sourceTree = ""; }; 145 | C9A743D614D7326E003E2DBA /* StatecArgument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecArgument.h; path = Builder/StatecArgument.h; sourceTree = ""; }; 146 | C9A743D714D7326E003E2DBA /* StatecArgument.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecArgument.m; path = Builder/StatecArgument.m; sourceTree = ""; }; 147 | C9A743DE14D765AC003E2DBA /* StatecMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecMachine.h; path = Parser/StatecMachine.h; sourceTree = ""; }; 148 | C9A743DF14D765AC003E2DBA /* StatecMachine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecMachine.m; path = Parser/StatecMachine.m; sourceTree = ""; }; 149 | C9A743E114D76BF2003E2DBA /* StatecInitial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecInitial.h; path = Parser/StatecInitial.h; sourceTree = ""; }; 150 | C9A743E214D76BF2003E2DBA /* StatecInitial.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecInitial.m; path = Parser/StatecInitial.m; sourceTree = ""; }; 151 | C9A743E414D76C02003E2DBA /* StatecState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecState.h; path = Parser/StatecState.h; sourceTree = ""; }; 152 | C9A743E514D76C02003E2DBA /* StatecState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecState.m; path = Parser/StatecState.m; sourceTree = ""; }; 153 | C9A743E714D76C13003E2DBA /* StatecEnter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecEnter.h; path = Parser/StatecEnter.h; sourceTree = ""; }; 154 | C9A743E814D76C13003E2DBA /* StatecEnter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecEnter.m; path = Parser/StatecEnter.m; sourceTree = ""; }; 155 | C9A743EA14D76C22003E2DBA /* StatecExit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecExit.h; path = Parser/StatecExit.h; sourceTree = ""; }; 156 | C9A743EB14D76C22003E2DBA /* StatecExit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecExit.m; path = Parser/StatecExit.m; sourceTree = ""; }; 157 | C9A743ED14D76C2E003E2DBA /* StatecEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatecEvent.h; sourceTree = ""; }; 158 | C9A743EE14D76C2E003E2DBA /* StatecEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatecEvent.m; sourceTree = ""; }; 159 | C9A743F114D774FC003E2DBA /* StatecCompiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecCompiler.h; path = Compiler/StatecCompiler.h; sourceTree = ""; }; 160 | C9A743F214D774FC003E2DBA /* StatecCompiler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecCompiler.m; path = Compiler/StatecCompiler.m; sourceTree = ""; }; 161 | C9A743F414D77826003E2DBA /* StatecTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecTransition.h; path = Parser/StatecTransition.h; sourceTree = ""; }; 162 | C9A743F514D77826003E2DBA /* StatecTransition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecTransition.m; path = Parser/StatecTransition.m; sourceTree = ""; }; 163 | C9A743F714D802E1003E2DBA /* StatecTypedef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecTypedef.h; path = Builder/StatecTypedef.h; sourceTree = ""; }; 164 | C9A743F814D802E1003E2DBA /* StatecTypedef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecTypedef.m; path = Builder/StatecTypedef.m; sourceTree = ""; }; 165 | C9A743FA14D805C6003E2DBA /* StatecEnumeration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecEnumeration.h; path = Builder/StatecEnumeration.h; sourceTree = ""; }; 166 | C9A743FB14D805C6003E2DBA /* StatecEnumeration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecEnumeration.m; path = Builder/StatecEnumeration.m; sourceTree = ""; }; 167 | C9A743FD14D807A1003E2DBA /* StatecType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecType.h; path = Builder/StatecType.h; sourceTree = ""; }; 168 | C9A743FE14D807A1003E2DBA /* StatecType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecType.m; path = Builder/StatecType.m; sourceTree = ""; }; 169 | C9A7440014D8096A003E2DBA /* StatecCompilationUnit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecCompilationUnit.h; path = Builder/StatecCompilationUnit.h; sourceTree = ""; }; 170 | C9A7440114D8096A003E2DBA /* StatecCompilationUnit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecCompilationUnit.m; path = Builder/StatecCompilationUnit.m; sourceTree = ""; }; 171 | C9A7440314D826E2003E2DBA /* StatecCodeStatement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecCodeStatement.h; path = Builder/StatecCodeStatement.h; sourceTree = ""; }; 172 | C9A7440414D826E3003E2DBA /* StatecCodeStatement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecCodeStatement.m; path = Builder/StatecCodeStatement.m; sourceTree = ""; }; 173 | C9A7440614D8282E003E2DBA /* StatecStatementGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecStatementGroup.h; path = Builder/StatecStatementGroup.h; sourceTree = ""; }; 174 | C9A7440714D8282F003E2DBA /* StatecStatementGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecStatementGroup.m; path = Builder/StatecStatementGroup.m; sourceTree = ""; }; 175 | C9A7440914D82896003E2DBA /* StatecStatement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecStatement.h; path = Builder/StatecStatement.h; sourceTree = ""; }; 176 | C9A7440A14D82897003E2DBA /* StatecStatement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecStatement.m; path = Builder/StatecStatement.m; sourceTree = ""; }; 177 | C9ED4A9114DACD7D0044BE00 /* StatecRunner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StatecRunner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 178 | C9ED4A9314DACD7D0044BE00 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 179 | C9ED4A9614DACD7D0044BE00 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 180 | C9ED4A9714DACD7D0044BE00 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 181 | C9ED4A9814DACD7D0044BE00 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 182 | C9ED4A9B14DACD7D0044BE00 /* StatecRunner-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "StatecRunner-Info.plist"; sourceTree = ""; }; 183 | C9ED4A9D14DACD7D0044BE00 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 184 | C9ED4A9F14DACD7D0044BE00 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 185 | C9ED4AA114DACD7D0044BE00 /* StatecRunner-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "StatecRunner-Prefix.pch"; sourceTree = ""; }; 186 | C9ED4AA314DACD7D0044BE00 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 187 | C9ED4AA514DACD7D0044BE00 /* StatecAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StatecAppDelegate.h; sourceTree = ""; }; 188 | C9ED4AA614DACD7D0044BE00 /* StatecAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = StatecAppDelegate.m; sourceTree = ""; }; 189 | C9ED4AA914DACD7D0044BE00 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 190 | C9ED4ABC14DAF2620044BE00 /* NSString+StatecExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+StatecExtensions.h"; path = "Categories/NSString+StatecExtensions.h"; sourceTree = ""; }; 191 | C9ED4ABD14DAF2620044BE00 /* NSString+StatecExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSString+StatecExtensions.m"; path = "Categories/NSString+StatecExtensions.m"; sourceTree = ""; }; 192 | C9ED4AC214DB14C60044BE00 /* StatecGVBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecGVBuilder.h; path = Builder/StatecGVBuilder.h; sourceTree = ""; }; 193 | C9ED4AC314DB14C60044BE00 /* StatecGVBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecGVBuilder.m; path = Builder/StatecGVBuilder.m; sourceTree = ""; }; 194 | C9ED4AC814DB25090044BE00 /* StatecHTMLBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatecHTMLBuilder.h; path = Builder/StatecHTMLBuilder.h; sourceTree = ""; }; 195 | C9ED4AC914DB25090044BE00 /* StatecHTMLBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatecHTMLBuilder.m; path = Builder/StatecHTMLBuilder.m; sourceTree = ""; }; 196 | /* End PBXFileReference section */ 197 | 198 | /* Begin PBXFrameworksBuildPhase section */ 199 | C9A743A214D6ECDE003E2DBA /* Frameworks */ = { 200 | isa = PBXFrameworksBuildPhase; 201 | buildActionMask = 2147483647; 202 | files = ( 203 | C94349881503983600705EB0 /* CoreParse.framework in Frameworks */, 204 | C9A743AA14D6ECDE003E2DBA /* Foundation.framework in Frameworks */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | C9ED4A8E14DACD7D0044BE00 /* Frameworks */ = { 209 | isa = PBXFrameworksBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | C94349871503983000705EB0 /* CoreParse.framework in Frameworks */, 213 | C9ED4A9414DACD7D0044BE00 /* Cocoa.framework in Frameworks */, 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | /* End PBXFrameworksBuildPhase section */ 218 | 219 | /* Begin PBXGroup section */ 220 | C9A7439A14D6ECDE003E2DBA = { 221 | isa = PBXGroup; 222 | children = ( 223 | C94349861503983000705EB0 /* CoreParse.framework */, 224 | C9A743AB14D6ECDE003E2DBA /* Statec */, 225 | C9ED4A9914DACD7D0044BE00 /* StatecRunner */, 226 | C9A743A814D6ECDE003E2DBA /* Frameworks */, 227 | C9A743A614D6ECDE003E2DBA /* Products */, 228 | ); 229 | sourceTree = ""; 230 | }; 231 | C9A743A614D6ECDE003E2DBA /* Products */ = { 232 | isa = PBXGroup; 233 | children = ( 234 | C9A743A514D6ECDE003E2DBA /* Statec */, 235 | C9ED4A9114DACD7D0044BE00 /* StatecRunner.app */, 236 | ); 237 | name = Products; 238 | sourceTree = ""; 239 | }; 240 | C9A743A814D6ECDE003E2DBA /* Frameworks */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | C9A743A914D6ECDE003E2DBA /* Foundation.framework */, 244 | C9ED4A9314DACD7D0044BE00 /* Cocoa.framework */, 245 | C9ED4A9514DACD7D0044BE00 /* Other Frameworks */, 246 | ); 247 | name = Frameworks; 248 | sourceTree = ""; 249 | }; 250 | C9A743AB14D6ECDE003E2DBA /* Statec */ = { 251 | isa = PBXGroup; 252 | children = ( 253 | C9ED4ABB14DAF2470044BE00 /* Categories */, 254 | C9A743F014D774E2003E2DBA /* Compiler */, 255 | C9A743BC14D6ED14003E2DBA /* Builder */, 256 | C9A743BB14D6ED0C003E2DBA /* Parser */, 257 | C9A743AC14D6ECDE003E2DBA /* main.m */, 258 | C9A743B014D6ECDE003E2DBA /* Statec.1 */, 259 | C9A743AE14D6ECDE003E2DBA /* Supporting Files */, 260 | C9A743D514D70BB0003E2DBA /* Statec.h */, 261 | ); 262 | path = Statec; 263 | sourceTree = ""; 264 | }; 265 | C9A743AE14D6ECDE003E2DBA /* Supporting Files */ = { 266 | isa = PBXGroup; 267 | children = ( 268 | C9A743AF14D6ECDE003E2DBA /* Statec-Prefix.pch */, 269 | ); 270 | name = "Supporting Files"; 271 | sourceTree = ""; 272 | }; 273 | C9A743BB14D6ED0C003E2DBA /* Parser */ = { 274 | isa = PBXGroup; 275 | children = ( 276 | C9A743BD14D6ED3A003E2DBA /* StatecParser.h */, 277 | C9A743BE14D6ED3A003E2DBA /* StatecParser.m */, 278 | C9A743DE14D765AC003E2DBA /* StatecMachine.h */, 279 | C9A743DF14D765AC003E2DBA /* StatecMachine.m */, 280 | C9A743E114D76BF2003E2DBA /* StatecInitial.h */, 281 | C9A743E214D76BF2003E2DBA /* StatecInitial.m */, 282 | C9A743E414D76C02003E2DBA /* StatecState.h */, 283 | C9A743E514D76C02003E2DBA /* StatecState.m */, 284 | C9A743E714D76C13003E2DBA /* StatecEnter.h */, 285 | C9A743E814D76C13003E2DBA /* StatecEnter.m */, 286 | C9A743EA14D76C22003E2DBA /* StatecExit.h */, 287 | C9A743EB14D76C22003E2DBA /* StatecExit.m */, 288 | C9A743ED14D76C2E003E2DBA /* StatecEvent.h */, 289 | C9A743EE14D76C2E003E2DBA /* StatecEvent.m */, 290 | C9A743F414D77826003E2DBA /* StatecTransition.h */, 291 | C9A743F514D77826003E2DBA /* StatecTransition.m */, 292 | ); 293 | name = Parser; 294 | sourceTree = ""; 295 | }; 296 | C9A743BC14D6ED14003E2DBA /* Builder */ = { 297 | isa = PBXGroup; 298 | children = ( 299 | C9A743C614D6EE25003E2DBA /* StatecClass.h */, 300 | C9A743C714D6EE25003E2DBA /* StatecClass.m */, 301 | C9A743CC14D6F178003E2DBA /* StatecMethod.h */, 302 | C9A743CD14D6F178003E2DBA /* StatecMethod.m */, 303 | C9A743CF14D6F189003E2DBA /* StatecVariable.h */, 304 | C9A743D014D6F189003E2DBA /* StatecVariable.m */, 305 | C9A743D214D6F210003E2DBA /* StatecProperty.h */, 306 | C9A743D314D6F210003E2DBA /* StatecProperty.m */, 307 | C9A743D614D7326E003E2DBA /* StatecArgument.h */, 308 | C9A743D714D7326E003E2DBA /* StatecArgument.m */, 309 | C9A743F714D802E1003E2DBA /* StatecTypedef.h */, 310 | C9A743F814D802E1003E2DBA /* StatecTypedef.m */, 311 | C9A743FA14D805C6003E2DBA /* StatecEnumeration.h */, 312 | C9A743FB14D805C6003E2DBA /* StatecEnumeration.m */, 313 | C9A743FD14D807A1003E2DBA /* StatecType.h */, 314 | C9A743FE14D807A1003E2DBA /* StatecType.m */, 315 | C9A7440014D8096A003E2DBA /* StatecCompilationUnit.h */, 316 | C9A7440114D8096A003E2DBA /* StatecCompilationUnit.m */, 317 | C9A7440314D826E2003E2DBA /* StatecCodeStatement.h */, 318 | C9A7440414D826E3003E2DBA /* StatecCodeStatement.m */, 319 | C9A7440614D8282E003E2DBA /* StatecStatementGroup.h */, 320 | C9A7440714D8282F003E2DBA /* StatecStatementGroup.m */, 321 | C9A7440914D82896003E2DBA /* StatecStatement.h */, 322 | C9A7440A14D82897003E2DBA /* StatecStatement.m */, 323 | C98F6BCF14D844520019E817 /* StatecConditionalStatement.h */, 324 | C98F6BD014D844530019E817 /* StatecConditionalStatement.m */, 325 | C9ED4AC214DB14C60044BE00 /* StatecGVBuilder.h */, 326 | C9ED4AC314DB14C60044BE00 /* StatecGVBuilder.m */, 327 | C9ED4AC814DB25090044BE00 /* StatecHTMLBuilder.h */, 328 | C9ED4AC914DB25090044BE00 /* StatecHTMLBuilder.m */, 329 | ); 330 | name = Builder; 331 | sourceTree = ""; 332 | }; 333 | C9A743F014D774E2003E2DBA /* Compiler */ = { 334 | isa = PBXGroup; 335 | children = ( 336 | C9A743F114D774FC003E2DBA /* StatecCompiler.h */, 337 | C9A743F214D774FC003E2DBA /* StatecCompiler.m */, 338 | ); 339 | name = Compiler; 340 | sourceTree = ""; 341 | }; 342 | C9ED4A9514DACD7D0044BE00 /* Other Frameworks */ = { 343 | isa = PBXGroup; 344 | children = ( 345 | C9ED4A9614DACD7D0044BE00 /* AppKit.framework */, 346 | C9ED4A9714DACD7D0044BE00 /* CoreData.framework */, 347 | C9ED4A9814DACD7D0044BE00 /* Foundation.framework */, 348 | ); 349 | name = "Other Frameworks"; 350 | sourceTree = ""; 351 | }; 352 | C9ED4A9914DACD7D0044BE00 /* StatecRunner */ = { 353 | isa = PBXGroup; 354 | children = ( 355 | C9ED4AA514DACD7D0044BE00 /* StatecAppDelegate.h */, 356 | C9ED4AA614DACD7D0044BE00 /* StatecAppDelegate.m */, 357 | C9ED4AA814DACD7D0044BE00 /* MainMenu.xib */, 358 | C9ED4A9A14DACD7D0044BE00 /* Supporting Files */, 359 | ); 360 | path = StatecRunner; 361 | sourceTree = ""; 362 | }; 363 | C9ED4A9A14DACD7D0044BE00 /* Supporting Files */ = { 364 | isa = PBXGroup; 365 | children = ( 366 | C9ED4A9B14DACD7D0044BE00 /* StatecRunner-Info.plist */, 367 | C9ED4A9C14DACD7D0044BE00 /* InfoPlist.strings */, 368 | C9ED4A9F14DACD7D0044BE00 /* main.m */, 369 | C9ED4AA114DACD7D0044BE00 /* StatecRunner-Prefix.pch */, 370 | C9ED4AA214DACD7D0044BE00 /* Credits.rtf */, 371 | ); 372 | name = "Supporting Files"; 373 | sourceTree = ""; 374 | }; 375 | C9ED4ABB14DAF2470044BE00 /* Categories */ = { 376 | isa = PBXGroup; 377 | children = ( 378 | C9ED4ABC14DAF2620044BE00 /* NSString+StatecExtensions.h */, 379 | C9ED4ABD14DAF2620044BE00 /* NSString+StatecExtensions.m */, 380 | ); 381 | name = Categories; 382 | sourceTree = ""; 383 | }; 384 | /* End PBXGroup section */ 385 | 386 | /* Begin PBXNativeTarget section */ 387 | C9A743A414D6ECDE003E2DBA /* Statec */ = { 388 | isa = PBXNativeTarget; 389 | buildConfigurationList = C9A743B414D6ECDE003E2DBA /* Build configuration list for PBXNativeTarget "Statec" */; 390 | buildPhases = ( 391 | C9A743A114D6ECDE003E2DBA /* Sources */, 392 | C9A743A214D6ECDE003E2DBA /* Frameworks */, 393 | C9A743A314D6ECDE003E2DBA /* CopyFiles */, 394 | C9A743B914D6ECF9003E2DBA /* Copy Frameworks */, 395 | ); 396 | buildRules = ( 397 | ); 398 | dependencies = ( 399 | ); 400 | name = Statec; 401 | productName = Statec; 402 | productReference = C9A743A514D6ECDE003E2DBA /* Statec */; 403 | productType = "com.apple.product-type.tool"; 404 | }; 405 | C9ED4A9014DACD7D0044BE00 /* StatecRunner */ = { 406 | isa = PBXNativeTarget; 407 | buildConfigurationList = C9ED4AAD14DACD7D0044BE00 /* Build configuration list for PBXNativeTarget "StatecRunner" */; 408 | buildPhases = ( 409 | C9ED4A8D14DACD7D0044BE00 /* Sources */, 410 | C9ED4A8E14DACD7D0044BE00 /* Frameworks */, 411 | C9ED4A8F14DACD7D0044BE00 /* Resources */, 412 | C9ED4AB114DACDC40044BE00 /* Copy Frameworks */, 413 | C9ED4AB314DACDE60044BE00 /* CopyFiles */, 414 | ); 415 | buildRules = ( 416 | ); 417 | dependencies = ( 418 | C9ED4AB014DACD8C0044BE00 /* PBXTargetDependency */, 419 | ); 420 | name = StatecRunner; 421 | productName = StatecRunner; 422 | productReference = C9ED4A9114DACD7D0044BE00 /* StatecRunner.app */; 423 | productType = "com.apple.product-type.application"; 424 | }; 425 | /* End PBXNativeTarget section */ 426 | 427 | /* Begin PBXProject section */ 428 | C9A7439C14D6ECDE003E2DBA /* Project object */ = { 429 | isa = PBXProject; 430 | attributes = { 431 | LastUpgradeCheck = 0430; 432 | }; 433 | buildConfigurationList = C9A7439F14D6ECDE003E2DBA /* Build configuration list for PBXProject "Statec" */; 434 | compatibilityVersion = "Xcode 3.2"; 435 | developmentRegion = English; 436 | hasScannedForEncodings = 0; 437 | knownRegions = ( 438 | en, 439 | ); 440 | mainGroup = C9A7439A14D6ECDE003E2DBA; 441 | productRefGroup = C9A743A614D6ECDE003E2DBA /* Products */; 442 | projectDirPath = ""; 443 | projectRoot = ""; 444 | targets = ( 445 | C9ED4A9014DACD7D0044BE00 /* StatecRunner */, 446 | C9A743A414D6ECDE003E2DBA /* Statec */, 447 | ); 448 | }; 449 | /* End PBXProject section */ 450 | 451 | /* Begin PBXResourcesBuildPhase section */ 452 | C9ED4A8F14DACD7D0044BE00 /* Resources */ = { 453 | isa = PBXResourcesBuildPhase; 454 | buildActionMask = 2147483647; 455 | files = ( 456 | C9ED4A9E14DACD7D0044BE00 /* InfoPlist.strings in Resources */, 457 | C9ED4AA414DACD7D0044BE00 /* Credits.rtf in Resources */, 458 | C9ED4AAA14DACD7D0044BE00 /* MainMenu.xib in Resources */, 459 | ); 460 | runOnlyForDeploymentPostprocessing = 0; 461 | }; 462 | /* End PBXResourcesBuildPhase section */ 463 | 464 | /* Begin PBXSourcesBuildPhase section */ 465 | C9A743A114D6ECDE003E2DBA /* Sources */ = { 466 | isa = PBXSourcesBuildPhase; 467 | buildActionMask = 2147483647; 468 | files = ( 469 | C9A743AD14D6ECDE003E2DBA /* main.m in Sources */, 470 | C9A743BF14D6ED3A003E2DBA /* StatecParser.m in Sources */, 471 | C9A743C814D6EE25003E2DBA /* StatecClass.m in Sources */, 472 | C9A743CE14D6F178003E2DBA /* StatecMethod.m in Sources */, 473 | C9A743D114D6F189003E2DBA /* StatecVariable.m in Sources */, 474 | C9A743D414D6F210003E2DBA /* StatecProperty.m in Sources */, 475 | C9A743D814D7326E003E2DBA /* StatecArgument.m in Sources */, 476 | C9A743E014D765AC003E2DBA /* StatecMachine.m in Sources */, 477 | C9A743E314D76BF2003E2DBA /* StatecInitial.m in Sources */, 478 | C9A743E614D76C02003E2DBA /* StatecState.m in Sources */, 479 | C9A743E914D76C13003E2DBA /* StatecEnter.m in Sources */, 480 | C9A743EC14D76C22003E2DBA /* StatecExit.m in Sources */, 481 | C9A743EF14D76C2F003E2DBA /* StatecEvent.m in Sources */, 482 | C9A743F314D774FC003E2DBA /* StatecCompiler.m in Sources */, 483 | C9A743F614D77827003E2DBA /* StatecTransition.m in Sources */, 484 | C9A743F914D802E1003E2DBA /* StatecTypedef.m in Sources */, 485 | C9A743FC14D805C7003E2DBA /* StatecEnumeration.m in Sources */, 486 | C9A743FF14D807A2003E2DBA /* StatecType.m in Sources */, 487 | C9A7440214D8096B003E2DBA /* StatecCompilationUnit.m in Sources */, 488 | C9A7440514D826E4003E2DBA /* StatecCodeStatement.m in Sources */, 489 | C9A7440814D82830003E2DBA /* StatecStatementGroup.m in Sources */, 490 | C9A7440B14D82897003E2DBA /* StatecStatement.m in Sources */, 491 | C98F6BD114D844530019E817 /* StatecConditionalStatement.m in Sources */, 492 | C9ED4ABE14DAF2620044BE00 /* NSString+StatecExtensions.m in Sources */, 493 | C9ED4AC414DB14C60044BE00 /* StatecGVBuilder.m in Sources */, 494 | C9ED4ACA14DB25090044BE00 /* StatecHTMLBuilder.m in Sources */, 495 | ); 496 | runOnlyForDeploymentPostprocessing = 0; 497 | }; 498 | C9ED4A8D14DACD7D0044BE00 /* Sources */ = { 499 | isa = PBXSourcesBuildPhase; 500 | buildActionMask = 2147483647; 501 | files = ( 502 | C9ED4AA014DACD7D0044BE00 /* main.m in Sources */, 503 | C9ED4AA714DACD7D0044BE00 /* StatecAppDelegate.m in Sources */, 504 | C93DC584150296B400007F09 /* StatecCompiler.m in Sources */, 505 | C93DC5861502971200007F09 /* StatecParser.m in Sources */, 506 | C93DC5871502972A00007F09 /* StatecClass.m in Sources */, 507 | C93DC5881502972A00007F09 /* StatecMethod.m in Sources */, 508 | C93DC5891502972A00007F09 /* StatecVariable.m in Sources */, 509 | C93DC58A1502972A00007F09 /* StatecProperty.m in Sources */, 510 | C93DC58B1502972A00007F09 /* StatecArgument.m in Sources */, 511 | C93DC58C1502972A00007F09 /* StatecTypedef.m in Sources */, 512 | C93DC58D1502972A00007F09 /* StatecEnumeration.m in Sources */, 513 | C93DC58E1502972A00007F09 /* StatecType.m in Sources */, 514 | C93DC58F1502972A00007F09 /* StatecCompilationUnit.m in Sources */, 515 | C93DC5901502972A00007F09 /* StatecCodeStatement.m in Sources */, 516 | C93DC5911502972A00007F09 /* StatecStatementGroup.m in Sources */, 517 | C93DC5921502972A00007F09 /* StatecStatement.m in Sources */, 518 | C93DC5931502972A00007F09 /* StatecConditionalStatement.m in Sources */, 519 | C93DC5941502972A00007F09 /* StatecGVBuilder.m in Sources */, 520 | C93DC5951502972A00007F09 /* StatecHTMLBuilder.m in Sources */, 521 | C93DC5961502973400007F09 /* NSString+StatecExtensions.m in Sources */, 522 | C93DC5971502974100007F09 /* StatecMachine.m in Sources */, 523 | C93DC5981502974100007F09 /* StatecInitial.m in Sources */, 524 | C93DC5991502974100007F09 /* StatecState.m in Sources */, 525 | C93DC59A1502974100007F09 /* StatecEnter.m in Sources */, 526 | C93DC59B1502974100007F09 /* StatecExit.m in Sources */, 527 | C93DC59C1502974100007F09 /* StatecEvent.m in Sources */, 528 | C93DC59D1502974100007F09 /* StatecTransition.m in Sources */, 529 | ); 530 | runOnlyForDeploymentPostprocessing = 0; 531 | }; 532 | /* End PBXSourcesBuildPhase section */ 533 | 534 | /* Begin PBXTargetDependency section */ 535 | C9ED4AB014DACD8C0044BE00 /* PBXTargetDependency */ = { 536 | isa = PBXTargetDependency; 537 | target = C9A743A414D6ECDE003E2DBA /* Statec */; 538 | targetProxy = C9ED4AAF14DACD8C0044BE00 /* PBXContainerItemProxy */; 539 | }; 540 | /* End PBXTargetDependency section */ 541 | 542 | /* Begin PBXVariantGroup section */ 543 | C9ED4A9C14DACD7D0044BE00 /* InfoPlist.strings */ = { 544 | isa = PBXVariantGroup; 545 | children = ( 546 | C9ED4A9D14DACD7D0044BE00 /* en */, 547 | ); 548 | name = InfoPlist.strings; 549 | sourceTree = ""; 550 | }; 551 | C9ED4AA214DACD7D0044BE00 /* Credits.rtf */ = { 552 | isa = PBXVariantGroup; 553 | children = ( 554 | C9ED4AA314DACD7D0044BE00 /* en */, 555 | ); 556 | name = Credits.rtf; 557 | sourceTree = ""; 558 | }; 559 | C9ED4AA814DACD7D0044BE00 /* MainMenu.xib */ = { 560 | isa = PBXVariantGroup; 561 | children = ( 562 | C9ED4AA914DACD7D0044BE00 /* en */, 563 | ); 564 | name = MainMenu.xib; 565 | sourceTree = ""; 566 | }; 567 | /* End PBXVariantGroup section */ 568 | 569 | /* Begin XCBuildConfiguration section */ 570 | C9A743B214D6ECDE003E2DBA /* Debug */ = { 571 | isa = XCBuildConfiguration; 572 | buildSettings = { 573 | ALWAYS_SEARCH_USER_PATHS = NO; 574 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 575 | CLANG_ENABLE_OBJC_ARC = YES; 576 | COPY_PHASE_STRIP = NO; 577 | GCC_C_LANGUAGE_STANDARD = gnu99; 578 | GCC_DYNAMIC_NO_PIC = NO; 579 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 580 | GCC_OPTIMIZATION_LEVEL = 0; 581 | GCC_PREPROCESSOR_DEFINITIONS = ( 582 | "DEBUG=1", 583 | "$(inherited)", 584 | ); 585 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 586 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 587 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 588 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 589 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 590 | GCC_WARN_UNUSED_VARIABLE = YES; 591 | MACOSX_DEPLOYMENT_TARGET = 10.7; 592 | ONLY_ACTIVE_ARCH = YES; 593 | SDKROOT = macosx; 594 | }; 595 | name = Debug; 596 | }; 597 | C9A743B314D6ECDE003E2DBA /* Release */ = { 598 | isa = XCBuildConfiguration; 599 | buildSettings = { 600 | ALWAYS_SEARCH_USER_PATHS = NO; 601 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 602 | CLANG_ENABLE_OBJC_ARC = YES; 603 | COPY_PHASE_STRIP = YES; 604 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 605 | GCC_C_LANGUAGE_STANDARD = gnu99; 606 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 607 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 608 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 609 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 610 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 611 | GCC_WARN_UNUSED_VARIABLE = YES; 612 | MACOSX_DEPLOYMENT_TARGET = 10.7; 613 | SDKROOT = macosx; 614 | }; 615 | name = Release; 616 | }; 617 | C9A743B514D6ECDE003E2DBA /* Debug */ = { 618 | isa = XCBuildConfiguration; 619 | buildSettings = { 620 | FRAMEWORK_SEARCH_PATHS = ( 621 | "$(inherited)", 622 | "\"$(SRCROOT)\"", 623 | ); 624 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 625 | GCC_PREFIX_HEADER = "Statec/Statec-Prefix.pch"; 626 | PRODUCT_NAME = "$(TARGET_NAME)"; 627 | }; 628 | name = Debug; 629 | }; 630 | C9A743B614D6ECDE003E2DBA /* Release */ = { 631 | isa = XCBuildConfiguration; 632 | buildSettings = { 633 | FRAMEWORK_SEARCH_PATHS = ( 634 | "$(inherited)", 635 | "\"$(SRCROOT)\"", 636 | ); 637 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 638 | GCC_PREFIX_HEADER = "Statec/Statec-Prefix.pch"; 639 | PRODUCT_NAME = "$(TARGET_NAME)"; 640 | }; 641 | name = Release; 642 | }; 643 | C9ED4AAB14DACD7D0044BE00 /* Debug */ = { 644 | isa = XCBuildConfiguration; 645 | buildSettings = { 646 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 647 | GCC_PREFIX_HEADER = "StatecRunner/StatecRunner-Prefix.pch"; 648 | INFOPLIST_FILE = "StatecRunner/StatecRunner-Info.plist"; 649 | PRODUCT_NAME = "$(TARGET_NAME)"; 650 | WRAPPER_EXTENSION = app; 651 | }; 652 | name = Debug; 653 | }; 654 | C9ED4AAC14DACD7D0044BE00 /* Release */ = { 655 | isa = XCBuildConfiguration; 656 | buildSettings = { 657 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 658 | GCC_PREFIX_HEADER = "StatecRunner/StatecRunner-Prefix.pch"; 659 | INFOPLIST_FILE = "StatecRunner/StatecRunner-Info.plist"; 660 | PRODUCT_NAME = "$(TARGET_NAME)"; 661 | WRAPPER_EXTENSION = app; 662 | }; 663 | name = Release; 664 | }; 665 | /* End XCBuildConfiguration section */ 666 | 667 | /* Begin XCConfigurationList section */ 668 | C9A7439F14D6ECDE003E2DBA /* Build configuration list for PBXProject "Statec" */ = { 669 | isa = XCConfigurationList; 670 | buildConfigurations = ( 671 | C9A743B214D6ECDE003E2DBA /* Debug */, 672 | C9A743B314D6ECDE003E2DBA /* Release */, 673 | ); 674 | defaultConfigurationIsVisible = 0; 675 | defaultConfigurationName = Release; 676 | }; 677 | C9A743B414D6ECDE003E2DBA /* Build configuration list for PBXNativeTarget "Statec" */ = { 678 | isa = XCConfigurationList; 679 | buildConfigurations = ( 680 | C9A743B514D6ECDE003E2DBA /* Debug */, 681 | C9A743B614D6ECDE003E2DBA /* Release */, 682 | ); 683 | defaultConfigurationIsVisible = 0; 684 | defaultConfigurationName = Release; 685 | }; 686 | C9ED4AAD14DACD7D0044BE00 /* Build configuration list for PBXNativeTarget "StatecRunner" */ = { 687 | isa = XCConfigurationList; 688 | buildConfigurations = ( 689 | C9ED4AAB14DACD7D0044BE00 /* Debug */, 690 | C9ED4AAC14DACD7D0044BE00 /* Release */, 691 | ); 692 | defaultConfigurationIsVisible = 0; 693 | defaultConfigurationName = Release; 694 | }; 695 | /* End XCConfigurationList section */ 696 | }; 697 | rootObject = C9A7439C14D6ECDE003E2DBA /* Project object */; 698 | } 699 | -------------------------------------------------------------------------------- /Statec/Builder/StatecArgument.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecArgument.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface StatecArgument : NSObject 12 | 13 | @property (strong) NSString *type; 14 | @property (strong) NSString *name; 15 | 16 | - (id)initWithType:(NSString *)type name:(NSString *)name; 17 | 18 | - (NSString *)argumentString; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Statec/Builder/StatecArgument.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecArgument.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecArgument.h" 10 | 11 | @implementation StatecArgument 12 | 13 | @synthesize type = _type; 14 | @synthesize name = _name; 15 | 16 | - (id)initWithType:(NSString *)type name:(NSString *)name { 17 | self = [super init]; 18 | if( self ) { 19 | _type = type; 20 | _name = name; 21 | } 22 | return self; 23 | } 24 | 25 | 26 | - (NSString *)argumentString { 27 | return [NSString stringWithFormat:@"(%@)%@", [self type], [self name]]; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Statec/Builder/StatecClass.h: -------------------------------------------------------------------------------- 1 | // 2 | // SFClassModel.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class StatecMethod; 12 | @class StatecVariable; 13 | @class StatecProperty; 14 | 15 | @interface StatecClass : NSObject 16 | 17 | @property (strong) NSString *name; 18 | @property (strong) StatecClass *baseClass; 19 | 20 | @property (strong) NSMutableArray *initializers; 21 | @property (strong) NSMutableArray *properties; 22 | @property (strong) NSMutableArray *variables; 23 | @property (strong) NSMutableArray *methods; 24 | 25 | @property (strong) NSMutableArray *classDeclarations; 26 | @property (strong) NSMutableArray *headerImports; 27 | @property (strong) NSMutableArray *classImports; 28 | 29 | - (id)initWithName:(NSString *)name; 30 | - (id)initWithname:(NSString *)name baseClass:(StatecClass *)baseClass; 31 | 32 | - (void)addVariable:(StatecVariable *)variable; 33 | - (void)addProperty:(StatecProperty *)property; 34 | - (void)addInitializer:(StatecMethod *)method; 35 | - (void)addMethod:(StatecMethod *)method; 36 | - (void)addMethods:(NSArray *)methods; 37 | 38 | 39 | - (NSString *)declarationString; 40 | - (NSString *)definitionString; 41 | 42 | - (NSString *)pointerType; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Statec/Builder/StatecClass.m: -------------------------------------------------------------------------------- 1 | // 2 | // SFClassModel.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecClass.h" 10 | 11 | #import "StatecMethod.h" 12 | #import "StatecProperty.h" 13 | #import "StatecVariable.h" 14 | 15 | @implementation StatecClass 16 | 17 | @synthesize name = _name; 18 | @synthesize baseClass = _baseClass; 19 | 20 | @synthesize classDeclarations = _classDeclarations; 21 | @synthesize headerImports = _headerImports; 22 | @synthesize classImports = _classImports; 23 | 24 | @synthesize initializers = _initializers; 25 | @synthesize properties = _properties; 26 | @synthesize variables = _variables; 27 | @synthesize methods = _methods; 28 | 29 | 30 | - (id)initWithName:(NSString *)name { 31 | self = [super init]; 32 | if( self ) { 33 | _name = name; 34 | _classDeclarations = [NSMutableArray array]; 35 | _initializers = [NSMutableArray array]; 36 | _properties = [NSMutableArray array]; 37 | _variables = [NSMutableArray array]; 38 | _methods = [NSMutableArray array]; 39 | } 40 | return self; 41 | } 42 | 43 | 44 | - (id)initWithname:(NSString *)name baseClass:(StatecClass *)baseClass { 45 | self = [self initWithName:name]; 46 | if( self ) { 47 | _baseClass = baseClass; 48 | } 49 | return self; 50 | } 51 | 52 | 53 | - (NSString *)pointerType { 54 | return [NSString stringWithFormat:@"%@*", [self name]]; 55 | } 56 | 57 | 58 | - (void)addVariable:(StatecVariable *)variable { 59 | [[self variables] addObject:variable]; 60 | } 61 | 62 | 63 | - (void)addProperty:(StatecProperty *)property { 64 | [[self properties] addObject:property]; 65 | } 66 | 67 | 68 | - (void)addInitializer:(StatecMethod *)method { 69 | [[self initializers] addObject:method]; 70 | } 71 | 72 | 73 | - (void)addMethod:(StatecMethod *)method { 74 | [[self methods] addObject:method]; 75 | } 76 | 77 | 78 | - (void)addMethods:(NSArray *)methods { 79 | [[self methods] addObjectsFromArray:methods]; 80 | } 81 | 82 | 83 | - (NSString *)baseClassName { 84 | if( [self baseClass] ) { 85 | return [[self baseClass] name]; 86 | } else { 87 | return @"NSObject"; 88 | } 89 | } 90 | 91 | 92 | - (NSString *)classMethodsDeclarationString { 93 | NSMutableString *content = [NSMutableString string]; 94 | 95 | for( StatecMethod *method in [self methods] ) { 96 | if( [method isClassScope] ) { 97 | [content appendString:[method declarationString]]; 98 | } 99 | } 100 | 101 | return content; 102 | } 103 | 104 | 105 | - (NSString *)classMethodsDefinitionString { 106 | NSMutableString *content = [NSMutableString string]; 107 | 108 | for( StatecMethod *method in [self methods] ) { 109 | if( [method isClassScope] ) { 110 | [content appendString:[method definitionString]]; 111 | } 112 | } 113 | 114 | return content; 115 | } 116 | 117 | 118 | - (NSString *)instanceVariablesDeclarationString { 119 | NSMutableString *content = [NSMutableString string]; 120 | 121 | for( StatecVariable *variable in [self variables] ) { 122 | if( [variable isInstanceScope] ) { 123 | [content appendString:[variable declarationString]]; 124 | } 125 | } 126 | 127 | return content; 128 | } 129 | 130 | 131 | - (NSString *)initializersDeclarationString { 132 | NSMutableString *content = [NSMutableString string]; 133 | 134 | for( StatecMethod *method in [self initializers] ) { 135 | [content appendString:[method declarationString]]; 136 | } 137 | 138 | return content; 139 | } 140 | 141 | 142 | - (NSString *)initializersDefinitionString { 143 | NSMutableString *content = [NSMutableString string]; 144 | 145 | for( StatecMethod *method in [self initializers] ) { 146 | [content appendFormat:@"%@\n",[method definitionString]]; 147 | } 148 | 149 | return content; 150 | } 151 | 152 | 153 | - (NSString *)instanceMethodsDeclarationString { 154 | NSMutableString *content = [NSMutableString string]; 155 | 156 | for( StatecMethod *method in [self methods] ) { 157 | if( [method isInstanceScope] ) { 158 | [content appendString:[method declarationString]]; 159 | } 160 | } 161 | 162 | return content; 163 | } 164 | 165 | 166 | - (NSString *)instanceMethodsDefinitionString { 167 | NSMutableString *content = [NSMutableString string]; 168 | 169 | for( StatecMethod *method in [self methods] ) { 170 | if( [method isInstanceScope] ) { 171 | [content appendFormat:@"%@\n",[method definitionString]]; 172 | } 173 | } 174 | 175 | return content; 176 | } 177 | 178 | 179 | - (NSString *)propertiesDeclarationString { 180 | NSMutableString *content = [NSMutableString string]; 181 | 182 | for( StatecProperty *property in [self properties] ) { 183 | [content appendString:[property declarationString]]; 184 | } 185 | 186 | return content; 187 | } 188 | 189 | 190 | - (NSString *)propertiesDefinitionString { 191 | NSMutableString *content = [NSMutableString string]; 192 | 193 | for( StatecProperty *property in [self properties] ) { 194 | [content appendString:[property definitionString]]; 195 | } 196 | 197 | return content; 198 | } 199 | 200 | 201 | - (NSString *)declarationString { 202 | NSMutableString *content = [NSMutableString string]; 203 | 204 | for( NSString *declaration in [self classDeclarations] ) { 205 | [content appendFormat:@"@class %@;",declaration]; 206 | } 207 | [content appendString:@"\n"]; 208 | 209 | [content appendFormat:@"@interface %@ : %@ {\n", [self name], [self baseClassName]]; 210 | [content appendFormat:@"%@\n}\n", [self instanceVariablesDeclarationString]]; 211 | [content appendFormat:@"%@\n", [self classMethodsDeclarationString]]; 212 | [content appendFormat:@"%@\n", [self propertiesDeclarationString]]; 213 | [content appendFormat:@"%@\n", [self initializersDeclarationString]]; 214 | [content appendFormat:@"%@\n", [self instanceMethodsDeclarationString]]; 215 | [content appendString:@"@end\n\n\n"]; 216 | 217 | return content; 218 | } 219 | 220 | 221 | - (NSString *)definitionString { 222 | NSMutableString *content = [NSMutableString string]; 223 | 224 | [content appendFormat:@"@implementation %@\n", [self name], [self baseClassName]]; 225 | [content appendFormat:@"%@\n", [self classMethodsDefinitionString]]; 226 | [content appendFormat:@"%@\n", [self propertiesDefinitionString]]; 227 | [content appendFormat:@"%@\n", [self initializersDefinitionString]]; 228 | [content appendFormat:@"%@\n", [self instanceMethodsDefinitionString]]; 229 | [content appendString:@"@end\n\n\n"]; 230 | 231 | return content; 232 | } 233 | 234 | 235 | @end 236 | -------------------------------------------------------------------------------- /Statec/Builder/StatecCodeStatement.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecCodeStatement.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "StatecStatement.h" 12 | 13 | @interface StatecCodeStatement : StatecStatement 14 | 15 | @property (strong) NSString *body; 16 | 17 | - (id)initWithBody:(NSString *)body; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Statec/Builder/StatecCodeStatement.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecCodeStatement.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecCodeStatement.h" 10 | 11 | @implementation StatecCodeStatement 12 | 13 | @synthesize body = _body; 14 | 15 | - (id)initWithBody:(NSString *)body { 16 | self = [self init]; 17 | if( self ) { 18 | _body = body; 19 | } 20 | return self; 21 | } 22 | 23 | - (NSString *)statementString { 24 | return [NSString stringWithFormat:@"%@;",[self body]]; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Statec/Builder/StatecCompilationUnit.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecCompilationUnit.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class StatecType; 12 | @class StatecClass; 13 | @class StatecVariable; 14 | 15 | @interface StatecCompilationUnit : NSObject 16 | 17 | @property (strong) NSString *name; 18 | @property (strong) NSString *comment; 19 | @property (strong) NSMutableArray *declarationImports; 20 | @property (strong) NSMutableArray *definitionImports; 21 | @property (strong) NSMutableArray *forwardDeclarations; 22 | @property (strong) NSMutableArray *variables; 23 | @property (strong) NSMutableArray *types; 24 | @property (strong) NSMutableArray *classes; 25 | @property (strong) StatecClass *principalClass; 26 | 27 | - (id)initWithName:(NSString *)name; 28 | 29 | - (void)addDeclarationImport:(NSString *)import; 30 | - (void)addDefinitionImport:(NSString *)import; 31 | - (void)addForwardDeclaration:(NSString *)class; 32 | - (void)addVariable:(StatecVariable *)variable; 33 | - (void)addClass:(StatecClass *)class; 34 | - (void)addType:(StatecType *)type; 35 | 36 | - (NSString *)headerFileName; 37 | - (NSString *)classFileName; 38 | 39 | - (BOOL)writeDefinitions:(NSString *)path error:(NSError **)error; 40 | - (BOOL)writeDeclarations:(NSString *)path error:(NSError **)error; 41 | - (BOOL)writeFilesTo:(NSString *)folder error:(NSError **)error; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Statec/Builder/StatecCompilationUnit.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecCompilationUnit.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecCompilationUnit.h" 10 | 11 | #import "Statec.h" 12 | 13 | @implementation StatecCompilationUnit 14 | 15 | @synthesize name = _name; 16 | @synthesize comment = _comment; 17 | @synthesize declarationImports = _declarationImports; 18 | @synthesize definitionImports = _definitionImports; 19 | @synthesize forwardDeclarations = _forwardDeclarations; 20 | @synthesize variables = _variables; 21 | @synthesize types = _types; 22 | @synthesize classes = _classes; 23 | @synthesize principalClass = _principalClass; 24 | 25 | 26 | - (id)initWithName:(NSString *)name { 27 | self = [self init]; 28 | if( self ) { 29 | _name = name; 30 | _comment = @""; 31 | _declarationImports = [NSMutableArray arrayWithObject:@""]; 32 | _definitionImports = [NSMutableArray arrayWithObject:[NSString stringWithFormat:@"%@.h",name]]; 33 | _forwardDeclarations = [NSMutableArray array]; 34 | _variables = [NSMutableArray array]; 35 | _classes = [NSMutableArray array]; 36 | _types = [NSMutableArray array]; 37 | } 38 | return self; 39 | } 40 | 41 | 42 | - (void)addVariable:(StatecVariable *)variable { 43 | [_variables addObject:variable]; 44 | } 45 | 46 | 47 | - (void)addClass:(StatecClass *)class { 48 | [_classes addObject:class]; 49 | } 50 | 51 | 52 | - (void)addType:(StatecType *)type { 53 | [_types addObject:type]; 54 | } 55 | 56 | 57 | - (void)addDeclarationImport:(NSString *)import { 58 | [[self declarationImports] addObject:import]; 59 | } 60 | 61 | 62 | - (void)addDefinitionImport:(NSString *)import { 63 | [[self definitionImports] addObject:import]; 64 | } 65 | 66 | 67 | - (void)addForwardDeclaration:(NSString *)class { 68 | [[self forwardDeclarations] addObject:class]; 69 | } 70 | 71 | 72 | - (NSString *)headerFileName { 73 | return [NSString stringWithFormat:@"%@.h",[self name]]; 74 | } 75 | 76 | 77 | - (NSString *)classFileName { 78 | return [NSString stringWithFormat:@"%@.m",[self name]]; 79 | } 80 | 81 | 82 | - (NSString *)typeStatementString { 83 | NSMutableString *content = [NSMutableString string]; 84 | for( StatecType *type in [self types] ) { 85 | [content appendString:[type statementString]]; 86 | } 87 | 88 | return content; 89 | } 90 | 91 | 92 | - (NSString *)importStatementString:(NSArray *)imports { 93 | NSMutableString *content = [NSMutableString string]; 94 | 95 | for( NSString *import in imports ) { 96 | if( [import hasPrefix:@"<"] ) { 97 | [content appendFormat:@"#import %@\n",import]; 98 | } else { 99 | [content appendFormat:@"#import \"%@\"\n",import]; 100 | } 101 | [content appendString:@"\n"]; 102 | } 103 | 104 | return content; 105 | } 106 | 107 | 108 | - (NSString *)forwardDeclarationsString { 109 | NSMutableString *content = [NSMutableString string]; 110 | 111 | for( NSString *class in [self forwardDeclarations] ) { 112 | [content appendFormat:@"@class %@;\n", class]; 113 | } 114 | 115 | [content appendString:@"\n"]; 116 | 117 | return content; 118 | } 119 | 120 | 121 | - (NSString *)variablesDeclarationString { 122 | NSMutableString *content = [NSMutableString string]; 123 | for( StatecVariable *variable in [self variables] ) { 124 | if( [variable isGlobalScope] && ![variable isStaticScope] ) { 125 | [content appendString:[variable declarationString]]; 126 | } 127 | } 128 | [content appendString:@"\n\n"]; 129 | return content; 130 | } 131 | 132 | 133 | - (NSString *)variablesDefinitionString { 134 | NSMutableString *content = [NSMutableString string]; 135 | for( StatecVariable *variable in [self variables] ) { 136 | if( [variable isGlobalScope] ) { 137 | [content appendString:[variable definitionString]]; 138 | } 139 | } 140 | [content appendString:@"\n\n"]; 141 | return content; 142 | } 143 | 144 | 145 | - (NSString *)declarationsString { 146 | NSMutableString *content = [NSMutableString string]; 147 | 148 | if( ![[self comment] isEqualToString:@""] ) { 149 | [content appendFormat:@"%@\n\n", [self comment]]; 150 | } 151 | 152 | [content appendString:[self importStatementString:[self declarationImports]]]; 153 | [content appendString:[self forwardDeclarationsString]]; 154 | 155 | [content appendString:[self variablesDeclarationString]]; 156 | 157 | [content appendString:[self typeStatementString]]; 158 | 159 | for( StatecClass *class in _classes ) { 160 | [content appendString:[class declarationString]]; 161 | } 162 | [content appendString:@"\n"]; 163 | 164 | return content; 165 | } 166 | 167 | 168 | - (NSString *)definitionsString { 169 | NSMutableString *content = [NSMutableString string]; 170 | 171 | if( ![[self comment] isEqualToString:@""] ) { 172 | [content appendFormat:@"%@\n\n", [self comment]]; 173 | } 174 | 175 | [content appendString:[self importStatementString:[self definitionImports]]]; 176 | 177 | [content appendString:[self variablesDefinitionString]]; 178 | 179 | for( StatecClass *class in [self classes] ) { 180 | [content appendString:[class definitionString]]; 181 | } 182 | [content appendString:@"\n"]; 183 | 184 | return content; 185 | } 186 | 187 | 188 | - (BOOL)writeDefinitions:(NSString *)path error:(NSError **)error { 189 | return [[self definitionsString] writeToFile:path atomically:NO encoding:NSUTF8StringEncoding error:error]; 190 | } 191 | 192 | 193 | - (BOOL)writeDeclarations:(NSString *)path error:(NSError **)error { 194 | return [[self declarationsString] writeToFile:path atomically:NO encoding:NSUTF8StringEncoding error:error]; 195 | } 196 | 197 | 198 | - (BOOL)writeFilesTo:(NSString *)folder error:(NSError **)error { 199 | if( ![self writeDeclarations:[folder stringByAppendingPathComponent:[self headerFileName]] error:error] ) { 200 | return NO; 201 | } 202 | if( ![self writeDefinitions:[folder stringByAppendingPathComponent:[self classFileName]] error:error] ) { 203 | return NO; 204 | } 205 | 206 | return YES; 207 | } 208 | 209 | 210 | @end 211 | -------------------------------------------------------------------------------- /Statec/Builder/StatecConditionalStatement.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecConditionalStatement.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "StatecStatement.h" 12 | 13 | @interface StatecConditionalStatement : StatecStatement 14 | 15 | @property (strong) NSString *condition; 16 | @property (strong) StatecStatement *ifTrue; 17 | @property (strong) StatecStatement *ifFalse; 18 | 19 | - (id)initWithCondition:(NSString *)condition; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Statec/Builder/StatecConditionalStatement.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecConditionalStatement.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecConditionalStatement.h" 10 | 11 | @implementation StatecConditionalStatement 12 | 13 | @synthesize condition = _condition; 14 | @synthesize ifTrue = _ifTrue; 15 | @synthesize ifFalse = _ifFalse; 16 | 17 | - (id)initWithCondition:(NSString *)condition { 18 | self = [self init]; 19 | if( self ) { 20 | _condition = condition; 21 | } 22 | return self; 23 | } 24 | 25 | 26 | - (NSString *)statementString { 27 | NSMutableString *content = [NSMutableString string]; 28 | 29 | [content appendFormat:@"if( ( %@ ) )", [self condition]]; 30 | [content appendString:[[self ifTrue] statementString]]; 31 | if( _ifFalse ) { 32 | [content appendString:@" else "]; 33 | [content appendString:[[self ifFalse] statementString]]; 34 | } 35 | 36 | return content; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Statec/Builder/StatecEnumeration.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecEnumeration.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "StatecType.h" 12 | 13 | @interface StatecEnumeration : StatecType { 14 | NSMutableArray *_elements; 15 | } 16 | 17 | - (void)addElement:(NSString *)element; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Statec/Builder/StatecEnumeration.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecEnumeration.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecEnumeration.h" 10 | 11 | @implementation StatecEnumeration 12 | 13 | - (id)init { 14 | self = [super init]; 15 | if( self ) { 16 | _elements = [NSMutableArray array]; 17 | } 18 | return self; 19 | } 20 | 21 | 22 | - (void)addElement:(NSString *)element { 23 | [_elements addObject:element]; 24 | } 25 | 26 | 27 | - (NSString *)statementString { 28 | NSMutableString *content = [NSMutableString string]; 29 | 30 | if( [self name] ) { 31 | [content appendFormat:@"enum %@ {\n",[self name]]; 32 | } else { 33 | [content appendString:@"enum {\n"]; 34 | } 35 | 36 | for( NSString *element in _elements ) { 37 | [content appendFormat:@"\t%@,\n",element]; 38 | } 39 | 40 | [content deleteCharactersInRange:NSMakeRange( [content length]-2, 2 )]; 41 | 42 | [content appendString:@"\n}"]; 43 | 44 | return content; 45 | } 46 | 47 | 48 | 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Statec/Builder/StatecGVBuilder.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecGVBuilder.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 02/02/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class StatecMachine; 12 | 13 | @interface StatecGVBuilder : NSObject 14 | 15 | - (NSString *)gvSourceFromMachine:(StatecMachine *)machine; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Statec/Builder/StatecGVBuilder.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecGVBuilder.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 02/02/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "StatecGVBuilder.h" 10 | 11 | #import "Statec.h" 12 | 13 | @implementation StatecGVBuilder 14 | 15 | - (NSString *)gvTransitions:(StatecMachine *)machine { 16 | NSMutableString *gv = [NSMutableString string]; 17 | 18 | for( StatecState *state in [[machine states] allValues] ) { 19 | for( StatecEvent *event in [state events] ) { 20 | [gv appendFormat: 21 | @"%@ -> %@ [label = \"%@\"];\n", 22 | [state name], 23 | [event targetState], 24 | [event name] 25 | ]; 26 | } 27 | } 28 | 29 | return gv; 30 | } 31 | 32 | 33 | - (NSString *)gvSourceFromMachine:(StatecMachine *)machine { 34 | NSMutableString *gv = [NSMutableString string]; 35 | 36 | [gv appendFormat: 37 | @"digraph %@ {\n" 38 | @" rankdir=LR;\n" 39 | // @" size=\"16,8\";\n" 40 | @" node [shape = circle];\n" 41 | @" node [fontsize = 15];\n" 42 | @" node [fontfamily = inconsolata];\n" 43 | @" edge [fontsize = 15];\n" 44 | @" edge [fontfamily = inconsolata];\n" 45 | @"%@" 46 | @"}", 47 | [machine name], 48 | [self gvTransitions:machine] 49 | ]; 50 | 51 | return gv; 52 | } 53 | 54 | 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Statec/Builder/StatecHTMLBuilder.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecHTMLBuilder.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 02/02/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class StatecMachine; 12 | 13 | @interface StatecHTMLBuilder : NSObject { 14 | StatecMachine *_machine; 15 | } 16 | 17 | 18 | - (id)initWithMachine:(StatecMachine *)machine; 19 | 20 | - (BOOL)writeToFolder:(NSString *)folderPath error:(NSError **)error; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Statec/Builder/StatecHTMLBuilder.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecHTMLBuilder.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 02/02/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "StatecHTMLBuilder.h" 10 | 11 | #import "Statec.h" 12 | 13 | @implementation StatecHTMLBuilder 14 | 15 | - (id)initWithMachine:(StatecMachine *)machine { 16 | self = [super init]; 17 | if( self ) { 18 | _machine = machine; 19 | } 20 | return self; 21 | } 22 | 23 | 24 | - (NSString *)htmlForMachine { 25 | NSMutableString *content = [NSMutableString string]; 26 | 27 | [content appendFormat: 28 | @"\n\n%@\n\n\n

States

\n\n", 29 | [_machine name] 30 | ]; 31 | 32 | for( StatecState *state in [[_machine states] allValues] ) { 33 | [content appendFormat: 34 | @"\n", 35 | [state name] 36 | ]; 37 | 38 | NSString *enterMethodName = @"", *exitMethodName = @""; 39 | if( [state wantsEnter] ) { 40 | enterMethodName = [state enterStateMethodName]; 41 | } 42 | if( [state wantsExit] ) { 43 | exitMethodName = [state exitStateMethodName]; 44 | } 45 | 46 | [content appendFormat: 47 | @"", 48 | enterMethodName, 49 | exitMethodName 50 | ]; 51 | 52 | for( StatecEvent *event in [state events] ) { 53 | [content appendFormat: 54 | @"", 55 | [event callbackMethodName], 56 | [event targetState] 57 | ]; 58 | } 59 | } 60 | 61 | [content appendString: 62 | @"
State: %@
%@%@
%@-> %@
\n\n\n" 63 | ]; 64 | 65 | 66 | return content; 67 | } 68 | 69 | 70 | - (BOOL)writeToFolder:(NSString *)folderPath error:(NSError **)error { 71 | return [[self htmlForMachine] writeToFile:[folderPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.html",[_machine name]]] 72 | atomically:NO 73 | encoding:NSUTF8StringEncoding error:error]; 74 | } 75 | 76 | 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /Statec/Builder/StatecMethod.h: -------------------------------------------------------------------------------- 1 | // 2 | // SFClassMethod.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "Statec.h" 12 | 13 | @class StatecArgument; 14 | @class StatecStatementGroup; 15 | 16 | @interface StatecMethod : NSObject 17 | 18 | @property (assign) StatecScope scope; 19 | @property (strong) NSString *returnType; 20 | @property (assign) SEL selector; 21 | @property (strong) StatecStatementGroup *body; 22 | @property (strong) NSMutableArray *arguments; 23 | 24 | - (id)initWithScope:(StatecScope)scope returnType:(NSString *)returnType selector:(SEL)selector; 25 | - (id)initWithScope:(StatecScope)scope returnType:(NSString *)returnType selectorFormat:(NSString *)format, ...; 26 | 27 | - (void)addArgument:(StatecArgument *)argument; 28 | 29 | - (BOOL)isInstanceScope; 30 | - (BOOL)isClassScope; 31 | 32 | - (NSString *)declarationString; 33 | - (NSString *)definitionString; 34 | 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Statec/Builder/StatecMethod.m: -------------------------------------------------------------------------------- 1 | // 2 | // SFClassMethod.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecMethod.h" 10 | 11 | @implementation StatecMethod 12 | 13 | @synthesize scope = _scope; 14 | @synthesize returnType = _returnType; 15 | @synthesize selector = _selector; 16 | @synthesize body = _body; 17 | @synthesize arguments = _arguments; 18 | 19 | 20 | - (id)init { 21 | self = [super init]; 22 | if( self ) { 23 | _arguments = [NSMutableArray array]; 24 | _body = [StatecStatementGroup group]; 25 | } 26 | return self; 27 | } 28 | 29 | 30 | - (id)initWithScope:(StatecScope)scope returnType:(NSString *)returnType selector:(SEL)selector { 31 | self = [self init]; 32 | if( self ) { 33 | _scope = scope; 34 | _returnType = returnType; 35 | _selector = selector; 36 | } 37 | return self; 38 | } 39 | 40 | 41 | - (id)initWithScope:(StatecScope)scope returnType:(NSString *)returnType selectorFormat:(NSString *)format, ... { 42 | va_list args; 43 | va_start( args, format ); 44 | NSString *selectorString = (__bridge_transfer NSString *)CFStringCreateWithFormatAndArguments( kCFAllocatorDefault, NULL, (__bridge CFStringRef)format, args ); 45 | va_end( args ); 46 | return [self initWithScope:scope returnType:returnType selector:NSSelectorFromString(selectorString)]; 47 | } 48 | 49 | 50 | - (void)addArgument:(StatecArgument *)argument { 51 | [[self arguments] addObject:argument]; 52 | } 53 | 54 | 55 | - (BOOL)isInstanceScope { 56 | return (StatecInstanceScope & _scope) == StatecInstanceScope; 57 | } 58 | 59 | 60 | - (BOOL)isClassScope { 61 | return ( StaticClassScope & _scope ) == StaticClassScope; 62 | } 63 | 64 | 65 | - (NSString *)scopeString { 66 | if( [self isInstanceScope] ) { 67 | return @"-"; 68 | } else { 69 | return @"+"; 70 | } 71 | } 72 | 73 | 74 | - (NSString *)selectorString { 75 | return NSStringFromSelector( [self selector] ); 76 | } 77 | 78 | 79 | - (NSString *)signatuareString { 80 | NSMutableString *content = [NSMutableString string]; 81 | 82 | [content appendString:[self scopeString]]; 83 | [content appendString:@" ("]; 84 | [content appendString:[self returnType]]; 85 | [content appendString:@")"]; 86 | 87 | NSRange range = [[self selectorString] rangeOfString:@":"]; 88 | if( range.location == NSNotFound ) { 89 | [content appendString:[self selectorString]]; 90 | } else { 91 | 92 | NSArray *selectorComponents = [[self selectorString] componentsSeparatedByString:@":"]; 93 | if( [[selectorComponents objectAtIndex:[selectorComponents count]-1] isEqualToString:@""] ) { 94 | selectorComponents = [selectorComponents subarrayWithRange:NSMakeRange(0,[selectorComponents count]-1)]; 95 | } 96 | 97 | int componentIndex = 0; 98 | for( NSString *component in selectorComponents ) { 99 | if( componentIndex > 0 ) { 100 | [content appendString:@" "]; 101 | } 102 | 103 | [content appendFormat:@"%@:%@",component,[[[self arguments] objectAtIndex:componentIndex] argumentString]]; 104 | 105 | componentIndex += 1; 106 | } 107 | } 108 | 109 | return content; 110 | } 111 | 112 | 113 | - (NSString *)declarationString { 114 | return [NSString stringWithFormat:@"%@;\n",[self signatuareString]]; 115 | } 116 | 117 | 118 | - (NSString *)definitionString { 119 | return [NSString stringWithFormat:@"%@ %@\n",[self signatuareString],[[self body] statementString]]; 120 | } 121 | 122 | 123 | @end 124 | -------------------------------------------------------------------------------- /Statec/Builder/StatecProperty.h: -------------------------------------------------------------------------------- 1 | // 2 | // SFPropertyModel.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface StatecProperty : NSObject 12 | 13 | @property (strong) NSMutableArray *attributes; 14 | 15 | @property (strong) NSString *type; 16 | @property (strong) NSString *name; 17 | 18 | - (id)initWithType:(NSString *)type name:(NSString *)name; 19 | - (id)initWithType:(NSString *)type name:(NSString *)name attribute:(NSString *)attribute; 20 | 21 | - (NSString *)declarationString; 22 | - (NSString *)definitionString; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Statec/Builder/StatecProperty.m: -------------------------------------------------------------------------------- 1 | // 2 | // SFPropertyModel.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecProperty.h" 10 | 11 | @implementation StatecProperty 12 | 13 | @synthesize attributes = _attributes; 14 | @synthesize type = _type; 15 | @synthesize name = _name; 16 | 17 | 18 | - (id)init { 19 | self = [super init]; 20 | if( self ) { 21 | _attributes = [NSMutableArray array]; 22 | } 23 | return self; 24 | } 25 | 26 | - (id)initWithType:(NSString *)type name:(NSString *)name { 27 | self = [self init]; 28 | if( self ) { 29 | _type = type; 30 | _name = name; 31 | } 32 | return self; 33 | } 34 | 35 | 36 | - (id)initWithType:(NSString *)type name:(NSString *)name attribute:(NSString *)attribute { 37 | self = [self initWithType:type name:name]; 38 | if( self ) { 39 | [_attributes addObject:attribute]; 40 | } 41 | return self; 42 | } 43 | 44 | 45 | - (NSString *)attributesString { 46 | return [[self attributes] componentsJoinedByString:@","]; 47 | } 48 | 49 | 50 | - (NSString *)declarationString { 51 | return [NSString stringWithFormat:@"@property (%@) %@ %@;\n", [self attributesString], [self type], [self name]]; 52 | } 53 | 54 | 55 | - (NSString *)definitionString { 56 | return [NSString stringWithFormat:@"@synthesize %@ = _%@;\n", [self name], [self name]]; 57 | } 58 | 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /Statec/Builder/StatecStatement.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecStatement.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface StatecStatement : NSObject 12 | 13 | - (NSString *)statementString; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Statec/Builder/StatecStatement.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecStatement.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecStatement.h" 10 | 11 | @implementation StatecStatement 12 | 13 | - (NSString *)statementString { 14 | return @"// YOU SHOULD NEVER SEE THIS!"; 15 | } 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Statec/Builder/StatecStatementGroup.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecStatementGroup.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "StatecStatement.h" 12 | 13 | @interface StatecStatementGroup : StatecStatement 14 | 15 | @property (strong) NSMutableArray *statements; 16 | 17 | + (StatecStatementGroup *)group; 18 | 19 | - (id)initWithBody:(NSString *)body; 20 | - (id)initWithFormat:(NSString *)format, ...; 21 | //- (id)initWithStatement:(StatecStatement *)statement; 22 | 23 | - (void)append:(NSString *)format, ...; 24 | - (void)addStatement:(StatecStatement *)statement; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Statec/Builder/StatecStatementGroup.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecStatementGroup.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecStatementGroup.h" 10 | 11 | #import "Statec.h" 12 | 13 | @implementation StatecStatementGroup 14 | 15 | @synthesize statements = _statements; 16 | 17 | 18 | + (StatecStatementGroup *)group { 19 | return [[StatecStatementGroup alloc] init]; 20 | } 21 | 22 | - (id)init { 23 | self = [super init]; 24 | if( self ) { 25 | _statements = [[NSMutableArray alloc] init]; 26 | } 27 | return self; 28 | } 29 | 30 | 31 | - (id)initWithBody:(NSString *)body { 32 | self = [self init]; 33 | if( self ) { 34 | [self append:body]; 35 | // [self addStatement:[[StatecCodeStatement alloc] initWithBody:body]]; 36 | } 37 | return self; 38 | } 39 | 40 | 41 | - (id)initWithFormat:(NSString *)format, ... { 42 | va_list args; 43 | va_start( args, format ); 44 | NSString *body = (__bridge_transfer NSString *)CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, NULL, (__bridge CFStringRef)format, args ); 45 | va_end( args ); 46 | return [self initWithBody:body]; 47 | } 48 | 49 | 50 | //- (id)initWithStatement:(StatecStatement *)statement { 51 | // self = [self init]; 52 | // if( self ) { 53 | // [self addStatement:statement]; 54 | // } 55 | // return self; 56 | //} 57 | 58 | 59 | - (void)append:(NSString *)format, ... { 60 | va_list args; 61 | va_start( args, format ); 62 | NSString *formattedString = (__bridge_transfer NSString *)CFStringCreateWithFormatAndArguments( kCFAllocatorDefault, NULL, (__bridge CFStringRef)format, args ); 63 | va_end( args ); 64 | [[self statements] addObject:formattedString]; 65 | } 66 | 67 | 68 | //- (void)addLine:(NSString *)line { 69 | // [[self statements] addObject:line]; 70 | //} 71 | 72 | 73 | - (void)addStatement:(StatecStatement *)statement { 74 | [[self statements] addObject:statement]; 75 | } 76 | 77 | 78 | - (NSString *)statementString { 79 | NSMutableString *content = [NSMutableString string]; 80 | 81 | [content appendString:@"{\n"]; 82 | for( id statement in [self statements] ) { 83 | if( [statement isKindOfClass:[StatecStatement class]] ) { 84 | [content appendString:[statement statementString]]; 85 | } else { 86 | [content appendFormat:@"%@\n",statement]; 87 | } 88 | } 89 | [content appendString:@"}\n"]; 90 | 91 | return content; 92 | } 93 | 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /Statec/Builder/StatecType.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecType.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface StatecType : NSObject 12 | 13 | @property (strong) NSString *name; 14 | 15 | - (id)initWithName:(NSString *)name; 16 | 17 | 18 | - (NSString *)statementString; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Statec/Builder/StatecType.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecType.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecType.h" 10 | 11 | @implementation StatecType 12 | 13 | @synthesize name = _name; 14 | 15 | - (id)initWithName:(NSString *)name { 16 | self = [self init]; 17 | if( self ) { 18 | _name = name; 19 | } 20 | return self; 21 | } 22 | 23 | 24 | - (NSString *)statementString { 25 | return @""; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Statec/Builder/StatecTypedef.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecTypedef.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "StatecType.h" 12 | 13 | @interface StatecTypedef : StatecType 14 | 15 | @property (strong) NSString *name; 16 | @property (strong) StatecType *type; 17 | 18 | - (id)initWithName:(NSString *)name type:(StatecType *)type; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Statec/Builder/StatecTypedef.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecTypedef.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecTypedef.h" 10 | 11 | @implementation StatecTypedef 12 | 13 | @synthesize name = _name; 14 | @synthesize type = _type; 15 | 16 | - (id)initWithName:(NSString *)name type:(StatecType *)type { 17 | self = [self init]; 18 | if( self ) { 19 | _name = name; 20 | _type = type; 21 | } 22 | return self; 23 | } 24 | 25 | 26 | - (NSString *)statementString { 27 | NSMutableString *content = [NSMutableString string]; 28 | [content appendFormat:@"typedef %@ %@;\n",[[self type] statementString],[self name]]; 29 | return content; 30 | } 31 | 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Statec/Builder/StatecVariable.h: -------------------------------------------------------------------------------- 1 | // 2 | // SFInstanceVariable.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "Statec.h" 12 | 13 | @interface StatecVariable : NSObject { 14 | } 15 | 16 | 17 | @property (assign) StatecScope scope; 18 | @property (strong) NSString *type; 19 | @property (strong) NSString *name; 20 | 21 | - (id)initWithScope:(StatecScope)scope name:(NSString *)name type:(NSString *)type; 22 | 23 | - (BOOL)isInstanceScope; 24 | - (BOOL)isGlobalScope; 25 | - (BOOL)isStaticScope; 26 | 27 | - (NSString *)declarationString; 28 | - (NSString *)definitionString; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Statec/Builder/StatecVariable.m: -------------------------------------------------------------------------------- 1 | // 2 | // SFInstanceVariable.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecVariable.h" 10 | 11 | @implementation StatecVariable 12 | 13 | @synthesize scope = _scope; 14 | @synthesize name = _name; 15 | @synthesize type = _type; 16 | 17 | - (id)initWithScope:(StatecScope)scope name:(NSString *)name type:(NSString *)type { 18 | self = [super init]; 19 | if( self ) { 20 | _scope = scope; 21 | _name = name; 22 | _type = type; 23 | } 24 | return self; 25 | } 26 | 27 | 28 | - (BOOL)isInstanceScope { 29 | return ( _scope & StatecInstanceScope ) == StatecInstanceScope; 30 | } 31 | 32 | 33 | - (BOOL)isGlobalScope { 34 | return ( _scope & StatecGlobalScope ) == StatecGlobalScope; 35 | } 36 | 37 | 38 | - (BOOL)isStaticScope { 39 | return ( _scope & StatecStaticScope ) == StatecStaticScope; 40 | } 41 | 42 | 43 | - (NSString *)declarationString { 44 | if( [self isInstanceScope] ) { 45 | return [NSString stringWithFormat:@"\t%@ %@;\n", [self type], [self name]]; 46 | } else { 47 | if( !(_scope & StatecStaticScope) ) { 48 | return [NSString stringWithFormat:@"extern %@ %@;", [self type], [self name]]; 49 | } else { 50 | return @""; 51 | } 52 | } 53 | } 54 | 55 | 56 | - (NSString *)definitionString { 57 | if( [self isGlobalScope] ) { 58 | if( _scope & StatecStaticScope ) { 59 | return [NSString stringWithFormat:@"static %@ %@;\n", [self type], [self name]]; 60 | } else { 61 | return [NSString stringWithFormat:@"%@ %@;\n", [self type], [self name]]; 62 | } 63 | } else { 64 | return @""; 65 | } 66 | } 67 | 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Statec/Categories/NSString+StatecExtensions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+StatecExtensions.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 02/02/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (StatecExtensions) 12 | 13 | - (NSString *)statecStringByCapitalisingFirstLetter; 14 | - (NSString *)statecStringByLoweringFirstLetter; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Statec/Categories/NSString+StatecExtensions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+StatecExtensions.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 02/02/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "NSString+StatecExtensions.h" 10 | 11 | @implementation NSString (StatecExtensions) 12 | 13 | - (NSString *)statecStringByCapitalisingFirstLetter { 14 | return [self stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[self substringToIndex:1] capitalizedString]]; 15 | } 16 | 17 | 18 | - (NSString *)statecStringByLoweringFirstLetter { 19 | return [self stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[self substringToIndex:1] lowercaseString]]; 20 | } 21 | 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Statec/Compiler/StatecCompiler.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecCompiler.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class StatecParser; 12 | @class StatecMachine; 13 | @class StatecCompilationUnit; 14 | 15 | @interface StatecCompiler : NSObject { 16 | } 17 | 18 | @property (strong) StatecParser *parser; 19 | @property (strong) StatecMachine *machine; 20 | @property (strong) StatecCompilationUnit *generatedUnit; 21 | 22 | //- (id)initWithSource:(NSString *)source; 23 | 24 | - (BOOL)parse:(NSString *)source; 25 | 26 | - (BOOL)isMachineValid:(NSArray **)issues; 27 | 28 | - (StatecCompilationUnit *)generatedMachine; 29 | - (StatecCompilationUnit *)userMachine; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Statec/Compiler/StatecCompiler.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecCompiler.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecCompiler.h" 10 | 11 | #import "Statec.h" 12 | 13 | #import "NSString+StatecExtensions.h" 14 | 15 | @implementation StatecCompiler 16 | 17 | @synthesize parser = _parser; 18 | @synthesize machine = _machine; 19 | @synthesize generatedUnit = _generatedUnit; 20 | 21 | 22 | - (id)init { 23 | self = [super init]; 24 | if( self ) { 25 | _parser = [[StatecParser alloc] init]; 26 | } 27 | return self; 28 | } 29 | 30 | 31 | - (BOOL)parse:(NSString *)source { 32 | StatecMachine *machine = (StatecMachine *)[[self parser] parse:source]; 33 | if( machine ) { 34 | [self setMachine:machine]; 35 | return YES; 36 | } else { 37 | return NO; 38 | } 39 | } 40 | 41 | 42 | - (BOOL)isMachineValid:(NSArray **)issues { 43 | return [_machine isMachineValid:issues]; 44 | } 45 | 46 | 47 | /* 48 | Generate an initializer for the machine class that initializes a global instance of each of the state 49 | subclasses. Because they are stateless they can be shared by all instances of the machine. 50 | */ 51 | - (StatecMethod *)classInitializer { 52 | StatecMethod *method = [[StatecMethod alloc] initWithScope:StaticClassScope returnType:@"void" selector:@selector(initialize)]; 53 | 54 | [[method body] append: 55 | @"static dispatch_once_t onceToken;\n" 56 | @"dispatch_once(&onceToken, ^{\n"]; 57 | 58 | for( StatecState *state in [[_machine states] allValues] ) { 59 | [[method body] append:@"%@ = [[%@ alloc] init];\n", [state stateVariableName], [state stateClassNameInMachine:_machine]]; 60 | } 61 | 62 | [[method body] append: 63 | @"});"]; 64 | 65 | return method; 66 | } 67 | 68 | 69 | 70 | /* 71 | Generate the initializer for the machine class. This should initialize the current state variable to point 72 | to the global instance of the state subclass for the initial state. 73 | */ 74 | - (StatecMethod *)initializer:(StatecVariable *)stateVariable queueVariable:(StatecVariable *)queueVariable { 75 | StatecMethod *method = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"id" selector:@selector(init)]; 76 | [[method body] append: 77 | @"self = [super init];\n" 78 | @"if( self ) {\n" 79 | @"%@ = %@;\n" 80 | @"%@ = dispatch_queue_create( %@, DISPATCH_QUEUE_SERIAL );\n" 81 | @"}\n" 82 | @"return self;\n", 83 | [stateVariable name], 84 | [[_machine initialState] stateVariableName], 85 | [queueVariable name], 86 | [NSString stringWithFormat:@"[[NSString stringWithFormat:@\"%@Machine.%%p\",self] UTF8String]",[_machine name]] 87 | ]; 88 | 89 | return method; 90 | } 91 | 92 | 93 | - (StatecMethod *)deallocQueueVariable:(StatecVariable *)queueVariable { 94 | StatecMethod *method = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selectorFormat:@"dealloc"]; 95 | [[method body] append: 96 | @"dispatch_release( %@ );\n", [queueVariable name] 97 | ]; 98 | return method; 99 | } 100 | 101 | 102 | /* 103 | Generate a method, to be added to the machine class, to respond to a specific event. 104 | 105 | The method tests whether the current state class can respond to this event. If it can then the event is passed 106 | on to the current state class. Otherwise an exception is raised to report the illegal attempted transition. 107 | */ 108 | - (StatecMethod *)eventMethodForEvent:(StatecEvent *)event state:(StatecVariable *)state queue:(StatecVariable *)queue { 109 | SEL selector = NSSelectorFromString([NSString stringWithFormat:[event callbackMethodName]]); 110 | 111 | StatecMethod *method = [[StatecMethod alloc] initWithScope:StatecInstanceScope 112 | returnType:@"void" 113 | selector:selector]; 114 | 115 | NSString *stateMethodName = [NSString stringWithFormat:[event internalCallbackMethodName]]; 116 | [[method body] append: 117 | @"dispatch_async( %@, ^{\n" 118 | @" [%@ %@self];" 119 | @"});\n", 120 | [queue name], 121 | [state name], 122 | stateMethodName 123 | ]; 124 | 125 | return method; 126 | } 127 | 128 | 129 | /* 130 | Generate event methods which will be added to the machine class. 131 | 132 | A method for every event (across all states) is added here. 133 | */ 134 | - (NSArray *)eventMethods:(StatecVariable *)stateVariable queueVariable:(StatecVariable *)queueVariable { 135 | NSMutableArray *methods = [NSMutableArray array]; 136 | for( NSString *eventName in [_machine events] ) { 137 | [methods addObject:[self eventMethodForEvent:[[_machine events] objectForKey:eventName] 138 | state:stateVariable 139 | queue:queueVariable]]; 140 | } 141 | return methods; 142 | } 143 | 144 | 145 | /* 146 | Generate a subclass of State to represent a concrete state in Machine. 147 | */ 148 | - (StatecClass *)stateClass:(StatecState *)state baseClass:(StatecClass *)baseClass machineClass:(StatecClass *)machineClass { 149 | StatecClass *stateClass = [[StatecClass alloc] initWithname:[state stateClassNameInMachine:_machine] baseClass:baseClass]; 150 | 151 | StatecMethod *initializer = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"id" selector:@selector(init)]; 152 | [[initializer body] append: 153 | @"return [self initWithName:@\"%@\"];\n", 154 | [state name] 155 | ]; 156 | [stateClass addInitializer:initializer]; 157 | 158 | // For every event this state recognises define an event method 159 | // that traverses to the target state 160 | for( StatecEvent *event in [state events] ) { 161 | StatecMethod *eventMethod = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selectorFormat:[event internalCallbackMethodName]]; 162 | [eventMethod addArgument:[[StatecArgument alloc] initWithType:[machineClass pointerType] name:@"machine"]]; 163 | [[eventMethod body] append:@"[machine log:@\"Received event: %@\"];\n", [event name]]; 164 | if( [state wantsExit] ) { 165 | [[eventMethod body] append:@"[machine %@];\n", [state exitStateMethodName]]; 166 | } 167 | 168 | StatecState *targetState = [[_machine states] objectForKey:[event targetState]]; 169 | [[eventMethod body] append:@"[machine transitionToState:%@];\n", [targetState stateVariableName]]; 170 | [stateClass addMethod:eventMethod]; 171 | } 172 | 173 | if( [state wantsEnter] ) { 174 | StatecMethod *enterMethod = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selector:@selector(enterFromMachine:)]; 175 | [enterMethod addArgument:[[StatecArgument alloc] initWithType:[machineClass pointerType] name:@"machine"]]; 176 | [[enterMethod body] append: 177 | @"[machine %@];\n", [state enterStateMethodName] 178 | ]; 179 | [stateClass addMethod:enterMethod]; 180 | } 181 | 182 | return stateClass; 183 | } 184 | 185 | /* 186 | Generate the Machine class. 187 | */ 188 | - (StatecClass *)machineClassWithStateBaseClass:(StatecClass *)stateBaseClass { 189 | // Create the class Machine that will represent the machine itself 190 | StatecClass *machineClass = [[StatecClass alloc] initWithName:[NSString stringWithFormat:@"_%@Machine",[_machine name]]]; 191 | 192 | // Add the +initialize method to create the state subclasses 193 | [machineClass addMethod:[self classInitializer]]; 194 | 195 | // Add to the machine class an instance variable representing the current state 196 | StatecVariable *stateVariable = [[StatecVariable alloc] initWithScope:StatecInstanceScope 197 | name:@"_currentState" 198 | type:[stateBaseClass pointerType]]; 199 | [machineClass addVariable:stateVariable]; 200 | 201 | StatecMethod *getStateMethod = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:[stateBaseClass pointerType] selector:@selector(currentState)]; 202 | [[getStateMethod body] append: 203 | @"return %@;\n", 204 | [stateVariable name] 205 | ]; 206 | [machineClass addMethod:getStateMethod]; 207 | 208 | StatecMethod *illegalTransitionMethod = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selector:@selector(illegalTransition:from:)]; 209 | [illegalTransitionMethod addArgument:[[StatecArgument alloc] initWithType:@"NSString*" name:@"event"]]; 210 | [illegalTransitionMethod addArgument:[[StatecArgument alloc] initWithType:[stateBaseClass pointerType] name:@"from"]]; 211 | [[illegalTransitionMethod body] append: 212 | @"// Subclass can override to customise illegal transition handling\n" 213 | @"[self log:[NSString stringWithFormat:@\"Received event %%@ which is not legal in state %%@\", event, [from name]]];\n" 214 | ]; 215 | [machineClass addMethod:illegalTransitionMethod]; 216 | 217 | StatecMethod *logMethod = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selector:@selector(log:)]; 218 | [logMethod addArgument:[[StatecArgument alloc] initWithType:@"NSString*" name:@"message"]]; 219 | [[logMethod body] append: 220 | @"// Subclass can override to do the actual logging\n" 221 | ]; 222 | [machineClass addMethod:logMethod]; 223 | 224 | // Add to the machine class an instance variable represent a queue we will use to 225 | // serialize state changes 226 | StatecVariable *queueVariable = [[StatecVariable alloc] initWithScope:StatecInstanceScope 227 | name:@"_queue" 228 | type:@"dispatch_queue_t"]; 229 | [machineClass addVariable:queueVariable]; 230 | 231 | // Add to the machine class it's -init method that sets the initial state 232 | [machineClass addInitializer:[self initializer:stateVariable queueVariable:queueVariable]]; 233 | 234 | // Add the dealloc method to release the queue 235 | [machineClass addMethod:[self deallocQueueVariable:queueVariable]]; 236 | 237 | // Add an event method, for all events, to the machine class 238 | [machineClass addMethods:[self eventMethods:stateVariable queueVariable:queueVariable]]; 239 | 240 | // For every state that wanted enter notification we provide a callback that can be overridden 241 | // by the user state machine class 242 | for( NSString *stateName in [_machine states] ) { 243 | StatecState *state = [[_machine states] objectForKey:stateName]; 244 | if( [state wantsEnter] ) { 245 | StatecMethod *method = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selectorFormat:[state enterStateMethodName]]; 246 | [method setBody:[[StatecStatementGroup alloc] initWithFormat:@"// Override in user machine subclass"]]; 247 | [machineClass addMethod:method]; 248 | } 249 | if( [state wantsExit] ) { 250 | StatecMethod *method = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selectorFormat:[state exitStateMethodName]]; 251 | [method setBody:[[StatecStatementGroup alloc] initWithFormat:@"// Override in user machine subclass"]]; 252 | [machineClass addMethod:method]; 253 | } 254 | } 255 | 256 | StatecMethod *transitionMethod = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selector:@selector(transitionToState:)]; 257 | [transitionMethod addArgument:[[StatecArgument alloc] initWithType:[stateBaseClass pointerType] name:@"state"]]; 258 | [[transitionMethod body] append: 259 | @"dispatch_async( %@, ^{\n" 260 | @"%@ = state;\n" 261 | @"[state enterFromMachine:self];\n" 262 | @"});\n", 263 | [queueVariable name], 264 | [stateVariable name] 265 | ]; 266 | [machineClass addMethod:transitionMethod]; 267 | 268 | return machineClass; 269 | } 270 | 271 | /* 272 | Generate a class model for State which acts as a base-class for all the machine specific 273 | state classes. 274 | */ 275 | - (StatecClass *)stateBaseClass { 276 | // Create the base class for the states 277 | StatecClass *class = [[StatecClass alloc] initWithName:[NSString stringWithFormat:@"%@State",[_machine name]]]; 278 | 279 | // Oay this is a cheat, i shouldn't be passing two strings separated by a , for attributes 280 | [class addProperty:[[StatecProperty alloc] initWithType:@"NSString*" name:@"name" attribute:@"strong,readonly"]]; 281 | 282 | StatecMethod *initializer = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"id" selector:@selector(initWithName:)]; 283 | [initializer addArgument:[[StatecArgument alloc] initWithType:@"NSString*" name:@"name"]]; 284 | [[initializer body] append: 285 | @"self = [super init];\n" 286 | @"if( self ) {\n" 287 | @" _name = name;\n" 288 | @"}\n" 289 | @"return self;\n" 290 | ]; 291 | [class addMethod:initializer]; 292 | 293 | return class; 294 | } 295 | 296 | /* 297 | Generates an array of methods that will be added to the State base-class to represent the events 298 | in the machine. The base class implements all events to provide a consistent interface that the machine 299 | can call. A default implementation is provided that raises an exception. It is expected that each state 300 | specific subclass will override this implementation for events legal for that state and, instead, cause 301 | the machine to transition to a new state. 302 | */ 303 | - (NSArray *)baseEventMethods:(StatecClass *)machineClass { 304 | NSMutableArray *methods = [NSMutableArray array]; 305 | 306 | // Now add to State a method for each event that raises an exception if the event is 307 | // fired. Specific subclasses will override this with a method that handles the event if 308 | // the state recognises that event. 309 | for( StatecEvent *event in [[_machine events] allValues] ) { 310 | StatecMethod *eventMethod = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selectorFormat:[event internalCallbackMethodName]]; 311 | [eventMethod addArgument:[[StatecArgument alloc] initWithType:[machineClass pointerType] name:@"machine"]]; 312 | [[eventMethod body] append: 313 | @"[machine illegalTransition:@\"%@\" from:self];\n", 314 | [event name] 315 | ]; 316 | [methods addObject:eventMethod]; 317 | } 318 | 319 | return methods; 320 | } 321 | 322 | 323 | - (StatecCompilationUnit *)generatedMachine { 324 | StatecCompilationUnit *unit = [[StatecCompilationUnit alloc] initWithName:[NSString stringWithFormat:@"_%@Machine",[_machine name]]]; 325 | 326 | [unit setComment:[NSString stringWithFormat: 327 | @"// This state machine file (_%@) was generated by Statec 0.1(0)\n" 328 | @"// Copyright (c) 2012 Matt Mower \n" 329 | @"// DO NOT EDIT THIS FILE - IT IS REGENERATED EVERY TIME STATEC IS RUN\n" 330 | @"// ONLY MAKE CHANGES IN THE USER FILE %@. YOU HAVE BEEN WARNED\n", 331 | [_machine name], 332 | [_machine name] 333 | ]]; 334 | 335 | StatecClass *stateBaseClass = [self stateBaseClass]; 336 | [unit addClass:stateBaseClass]; 337 | 338 | StatecClass *machineClass = [self machineClassWithStateBaseClass:stateBaseClass]; 339 | [stateBaseClass addMethods:[self baseEventMethods:machineClass]]; 340 | 341 | // Add the generic enterFromMachine: method 342 | StatecMethod *enterMethod = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selector:@selector(enterFromMachine:)]; 343 | [enterMethod addArgument:[[StatecArgument alloc] initWithType:[machineClass pointerType] name:@"machine"]]; 344 | [enterMethod setBody:[[StatecStatementGroup alloc] initWithFormat:@"// Subclasses will redefine if enter callbacks are required for their state\n"]]; 345 | [stateBaseClass addMethod:enterMethod]; 346 | 347 | // Make the machine class available to the State classes that get declared before it 348 | [unit addForwardDeclaration:[machineClass name]]; 349 | 350 | // For each state in the machine make a state subclass and create a global 351 | // pointer for a staticly allocated instance of the class 352 | for( StatecState *state in [[_machine states] allValues] ) { 353 | [unit addClass:[self stateClass:state baseClass:stateBaseClass machineClass:machineClass]]; 354 | StatecVariable *stateGlobalVariable = [[StatecVariable alloc] initWithScope:StatecGlobalScope|StatecStaticScope 355 | name:[state stateVariableName] 356 | type:[stateBaseClass pointerType]]; 357 | [unit addVariable:stateGlobalVariable]; 358 | } 359 | 360 | [unit addClass:machineClass]; 361 | [unit setPrincipalClass:machineClass]; 362 | 363 | _generatedUnit = unit; 364 | 365 | return unit; 366 | } 367 | 368 | 369 | - (StatecCompilationUnit *)userMachine { 370 | StatecCompilationUnit *unit = [[StatecCompilationUnit alloc] initWithName:[NSString stringWithFormat:@"%@Machine",[_machine name]]]; 371 | 372 | NSMutableString *commentString = [NSMutableString string]; 373 | [commentString appendFormat: 374 | @"// State Machine %@ generated by Statec v0.1 on %@\n" 375 | @"// \n", 376 | [_machine name], 377 | [NSDate date] 378 | ]; 379 | 380 | [unit setComment:commentString]; 381 | 382 | // Import the generated machine into the user machine 383 | [[unit declarationImports] addObject:[NSString stringWithFormat:@"_%@Machine.h",[_machine name]]]; 384 | 385 | StatecClass *userClass = [[StatecClass alloc] initWithname:[NSString stringWithFormat:@"%@Machine",[_machine name]] baseClass:[[self generatedUnit] principalClass]]; 386 | 387 | // For every state that wanted enter notification we provide a callback stub the user can put their code in 388 | for( NSString *stateName in [_machine states] ) { 389 | StatecState *state = [[_machine states] objectForKey:stateName]; 390 | if( [state wantsEnter] ) { 391 | StatecMethod *method = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selectorFormat:[state enterStateMethodName]]; 392 | [method setBody:[[StatecStatementGroup alloc] initWithFormat:@"// Your code here"]]; 393 | [userClass addMethod:method]; 394 | } 395 | if( [state wantsExit] ) { 396 | StatecMethod *method = [[StatecMethod alloc] initWithScope:StatecInstanceScope returnType:@"void" selectorFormat:[state exitStateMethodName]]; 397 | [method setBody:[[StatecStatementGroup alloc] initWithFormat:@"// Your code here"]]; 398 | [userClass addMethod:method]; 399 | } 400 | } 401 | 402 | [unit addClass:userClass]; 403 | 404 | return unit; 405 | } 406 | 407 | 408 | @end 409 | -------------------------------------------------------------------------------- /Statec/Parser/StatecEnter.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecEnter.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | 14 | @interface StatecEnter : NSObject 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Statec/Parser/StatecEnter.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecEnter.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecEnter.h" 10 | 11 | @implementation StatecEnter 12 | 13 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree { 14 | self = [super init]; 15 | if( self ) { 16 | } 17 | return self; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Statec/Parser/StatecExit.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecExit.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | 14 | @interface StatecExit : NSObject 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Statec/Parser/StatecExit.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecExit.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecExit.h" 10 | 11 | @implementation StatecExit 12 | 13 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree { 14 | self = [super init]; 15 | if( self ) { 16 | } 17 | return self; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Statec/Parser/StatecInitial.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecInitial.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | 14 | @interface StatecInitial : NSObject 15 | 16 | @property (strong) NSString *name; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Statec/Parser/StatecInitial.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecInitial.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecInitial.h" 10 | 11 | @implementation StatecInitial 12 | 13 | @synthesize name = _name; 14 | 15 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree { 16 | self = [super init]; 17 | if( self ) { 18 | NSAssert( 2 == [[syntaxTree children] count], @"StatecInitial must have exactly 2 children" ); 19 | _name = [[[syntaxTree children] objectAtIndex:1] content]; 20 | } 21 | return self; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Statec/Parser/StatecMachine.h: -------------------------------------------------------------------------------- 1 | // 2 | // Machine.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | @class StatecState; 14 | 15 | @interface StatecMachine : NSObject 16 | 17 | @property (strong) NSString *name; 18 | @property (strong) StatecState *initialState; 19 | @property (strong) NSDictionary *states; 20 | @property (strong) NSDictionary *events; 21 | 22 | - (BOOL)isMachineValid:(NSArray **)issues; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Statec/Parser/StatecMachine.m: -------------------------------------------------------------------------------- 1 | // 2 | // Machine.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecMachine.h" 10 | 11 | #import "Statec.h" 12 | 13 | @implementation StatecMachine 14 | 15 | @synthesize name = _name; 16 | @synthesize initialState = _initialState; 17 | @synthesize states = _states; 18 | @synthesize events = _events; 19 | 20 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree { 21 | self = [super init]; 22 | if( self ) { 23 | NSArray *children = [syntaxTree children]; 24 | _name = [[children objectAtIndex:1] content]; 25 | 26 | NSArray *stateList = [children objectAtIndex:4]; 27 | 28 | _states = [NSMutableDictionary dictionary]; 29 | for( StatecState *state in stateList ) { 30 | [_states setValue:state forKey:[state name]]; 31 | } 32 | 33 | _initialState = [_states objectForKey:[[children objectAtIndex:3] name]]; 34 | 35 | _events = [NSMutableDictionary dictionary]; 36 | 37 | for( StatecState *state in stateList ) { 38 | for( StatecEvent *event in [state events] ) { 39 | 40 | StatecEvent *globalEvent = [_events objectForKey:[event name]]; 41 | if( !globalEvent ) { 42 | globalEvent = event; 43 | [_events setValue:globalEvent forKey:[event name]]; 44 | } 45 | 46 | // NSMutableArray *transitionList = [_events objectForKey:[event name]]; 47 | // if( !transitionList ) { 48 | // transitionList = [NSMutableArray array]; 49 | // [_events setValue:transitionList forKey:[event name]]; 50 | // } 51 | 52 | StatecTransition *transition = [[StatecTransition alloc] initWithSourceState:state targetState:[_states objectForKey:[event targetState]]]; 53 | [[globalEvent transitions] addObject:transition]; 54 | // [transitionList addObject:transition]; 55 | } 56 | } 57 | } 58 | return self; 59 | } 60 | 61 | 62 | - (NSArray *)validatesInitialStateIsDefined { 63 | for( StatecState *state in [[self states] allValues] ) { 64 | if( [[state name] isEqualToString:[[self initialState] name]] ) { 65 | return [NSArray array]; 66 | } 67 | } 68 | 69 | return [NSArray arrayWithObject:[NSString stringWithFormat:@"Initial state '%@' is not defined as a state", _initialState]]; 70 | } 71 | 72 | 73 | - (NSArray *)validatesEventTransitions { 74 | NSMutableArray *issues = [NSMutableArray array]; 75 | 76 | for( StatecEvent *event in [[self events] allValues] ) { 77 | for( StatecTransition *transition in [event transitions] ) { 78 | NSSet *matching = [[self states] keysOfEntriesPassingTest:^BOOL(id key, id state, BOOL *stop) { 79 | return [[state name] isEqualToString:[[transition targetState] name]]; 80 | }]; 81 | 82 | if( [matching count] < 1 ) { 83 | [issues addObject:[NSString stringWithFormat:@"State '%@' declares event '%@' should transition to non-existent state", [[transition sourceState] name], [event name]]]; 84 | } 85 | } 86 | } 87 | 88 | return issues; 89 | } 90 | 91 | 92 | - (BOOL)isMachineValid:(NSArray **)issues { 93 | NSMutableArray *issueList = [NSMutableArray array]; 94 | [issueList addObjectsFromArray:[self validatesInitialStateIsDefined]]; 95 | [issueList addObjectsFromArray:[self validatesEventTransitions]]; 96 | if( [issueList count] > 0 ) { 97 | *issues = issueList; 98 | NSLog( @"INVALID MACHINE" ); 99 | return NO; 100 | } else { 101 | NSLog( @"VALID MACHINE" ); 102 | return YES; 103 | } 104 | } 105 | 106 | 107 | 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /Statec/Parser/StatecParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // MMStatecParser.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | @class StatecParser; 14 | 15 | @protocol StatecParserDelegate 16 | 17 | - (void)parser:(StatecParser *)parser syntaxError:(NSString *)message token:(CPToken *)token expected:(NSSet *)expected; 18 | - (void)parser:(StatecParser *)parser unexpectedToken:(CPToken *)token expected:(NSSet *)expected; 19 | 20 | @end 21 | 22 | 23 | @interface StatecParser : NSObject 24 | 25 | - (CPTokeniser *)tokenizer; 26 | - (CPGrammar *)grammar; 27 | - (CPParser *)parser; 28 | - (CPTokenStream *)tokenStream:(NSString *)source; 29 | - (id)parse:(NSString *)source; 30 | 31 | @property id delegate; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Statec/Parser/StatecParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // MMStatecParser.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecParser.h" 10 | 11 | #import 12 | 13 | @implementation StatecParser 14 | 15 | @synthesize delegate = _delegate; 16 | 17 | 18 | - (CPTokeniser *)tokenizer { 19 | CPTokeniser *tokenizer = [[CPTokeniser alloc] init]; 20 | 21 | [tokenizer addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"{"]]; 22 | [tokenizer addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"}"]]; 23 | [tokenizer addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"=>"]]; 24 | [tokenizer addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"@machine"]]; 25 | [tokenizer addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"@initial"]]; 26 | [tokenizer addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"@state"]]; 27 | [tokenizer addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"@event"]]; 28 | [tokenizer addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"@enter"]]; 29 | [tokenizer addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"@exit"]]; 30 | [tokenizer addTokenRecogniser:[CPQuotedRecogniser quotedRecogniserWithStartQuote:@"\"" endQuote:@"\"" name:@"String"]]; 31 | [tokenizer addTokenRecogniser:[CPQuotedRecogniser quotedRecogniserWithStartQuote:@"/*" endQuote:@"*/" name:@"Comment"]]; 32 | [tokenizer addTokenRecogniser:[CPQuotedRecogniser quotedRecogniserWithStartQuote:@"//" endQuote:@"\n" name:@"Comment"]]; 33 | [tokenizer addTokenRecogniser:[CPWhiteSpaceRecogniser whiteSpaceRecogniser]]; 34 | 35 | [tokenizer setDelegate:self]; 36 | 37 | return tokenizer; 38 | } 39 | 40 | 41 | - (BOOL)tokeniser:(CPTokeniser *)tokeniser shouldConsumeToken:(CPToken *)token { 42 | return YES; 43 | } 44 | 45 | 46 | - (NSArray *)tokeniser:(CPTokeniser *)tokeniser willProduceToken:(CPToken *)token { 47 | if( [token isKindOfClass:[CPWhiteSpaceToken class]] || [[token name] isEqualToString:@"Comment"] ) { 48 | return [NSArray array]; 49 | } else { 50 | return [NSArray arrayWithObject:token]; 51 | } 52 | } 53 | 54 | 55 | - (CPGrammar *)grammar { 56 | CPGrammar *grammar = [[CPGrammar alloc] initWithStart:@"StatecMachine" 57 | backusNaurForm: 58 | @"0 StatecMachine ::= \"@machine\" \"String\" \"{\" + \"}\" ;" 59 | @"1 StatecInitial ::= \"@initial\" \"String\" ;" 60 | @"2 StatecState ::= \"@state\" \"String\" \"{\" ? ? * \"}\" ;" 61 | @"3 StatecEnter ::= \"@enter\" ;" 62 | @"4 StatecExit ::= \"@exit\" ;" 63 | @"5 StatecEvent ::= \"@event\" \"String\" \"=>\" \"String\" ;"]; 64 | 65 | return grammar; 66 | } 67 | 68 | 69 | - (CPParser *)parser { 70 | return [CPLALR1Parser parserWithGrammar:[self grammar]]; 71 | } 72 | 73 | 74 | - (NSUInteger)tokeniser:(CPTokeniser *)tokeniser didNotFindTokenOnInput:(NSString *)input position:(NSUInteger)position error:(NSString **)errorMessage { 75 | *errorMessage = [NSString stringWithFormat:@"unexpected character '%c' in input", [input characterAtIndex:0]]; 76 | return NSNotFound; 77 | } 78 | 79 | 80 | - (CPTokenStream *)tokenStream:(NSString *)source { 81 | return [[self tokenizer] tokenise:source]; 82 | } 83 | 84 | 85 | - (CPRecoveryAction *)parser:(CPParser *)parser didEncounterErrorOnInput:(CPTokenStream *)inputStream expecting:(NSSet *)acceptableTokens { 86 | CPToken *errorToken = [inputStream peekToken]; 87 | 88 | if( [errorToken isKindOfClass:[CPErrorToken class]] ) { 89 | [[self delegate] parser:self syntaxError:[(CPErrorToken*)errorToken errorMessage] token:errorToken expected:acceptableTokens]; 90 | // NSLog( @"Unexpected token at line:%ld col:%ld", [errorToken lineNumber], [errorToken columnNumber] ); 91 | // NSLog( @"Error:%@", [(CPErrorToken*)errorToken errorMessage] ); 92 | } else { 93 | [[self delegate] parser:self unexpectedToken:errorToken expected:acceptableTokens]; 94 | NSLog( @"Unexpected %@ token at line:%ld col:%ld", [errorToken name], [errorToken lineNumber], [errorToken columnNumber] ); 95 | // NSLog( @"Expecting one of: %@", [tokenNames componentsJoinedByString:@","] ); 96 | } 97 | return [CPRecoveryAction recoveryActionStop]; 98 | } 99 | 100 | 101 | 102 | - (id)parse:(NSString *)source { 103 | NSLog( @"calling parse" ); 104 | CPParser *parser = [self parser]; 105 | [parser setDelegate:self]; 106 | 107 | CPTokenStream *tokens = [self tokenStream:source]; 108 | 109 | id result = [parser parse:tokens]; 110 | return result; 111 | } 112 | 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /Statec/Parser/StatecState.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecState.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | @class StatecMachine; 14 | 15 | 16 | @interface StatecState : NSObject 17 | 18 | @property (strong) NSString *name; 19 | @property (assign) BOOL wantsEnter; 20 | @property (assign) BOOL wantsExit; 21 | @property (strong,readonly) NSArray *events; 22 | 23 | - (BOOL)respondsToEventName:(NSString *)eventName; 24 | 25 | - (NSString *)enterStateMethodName; 26 | - (NSString *)exitStateMethodName; 27 | 28 | - (NSString *)stateVariableName; 29 | 30 | - (NSString *)stateClassNameInMachine:(StatecMachine *)machine; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Statec/Parser/StatecState.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecState.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecState.h" 10 | 11 | #import "StatecEnter.h" 12 | #import "StatecExit.h" 13 | #import "StatecEvent.h" 14 | #import "StatecMachine.h" 15 | 16 | #import "NSString+StatecExtensions.h" 17 | 18 | @implementation StatecState 19 | 20 | @synthesize name = _name; 21 | @synthesize wantsEnter = _wantsEnter; 22 | @synthesize wantsExit = _wantsExit; 23 | @synthesize events = _events; 24 | 25 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree { 26 | self = [super init]; 27 | if( self ) { 28 | NSArray *children = [syntaxTree children]; 29 | 30 | _name = [[children objectAtIndex:1] content]; 31 | 32 | NSArray *enter = [children objectAtIndex:3]; 33 | if( [enter count] > 0 && [[enter objectAtIndex:0] isKindOfClass:[StatecEnter class]] ) { 34 | _wantsEnter = YES; 35 | } else { 36 | _wantsEnter = NO; 37 | } 38 | 39 | NSArray *exit = [children objectAtIndex:4]; 40 | if( [exit count] > 0 && [[exit objectAtIndex:0] isKindOfClass:[StatecExit class]] ) { 41 | _wantsExit = YES; 42 | } else { 43 | _wantsExit = NO; 44 | } 45 | 46 | _events = [children objectAtIndex:5]; 47 | } 48 | return self; 49 | } 50 | 51 | - (BOOL)respondsToEventName:(NSString *)eventName { 52 | for( StatecEvent *event in [self events] ) { 53 | if( [[event name] isEqualToString:eventName] ) { 54 | return YES; 55 | } 56 | } 57 | 58 | return NO; 59 | } 60 | 61 | 62 | - (NSString *)enterStateMethodName { 63 | return [NSString stringWithFormat:@"enter%@State", [[self name] statecStringByCapitalisingFirstLetter]]; 64 | } 65 | 66 | 67 | - (NSString *)exitStateMethodName { 68 | return [NSString stringWithFormat:@"exit%@State", [[self name] statecStringByCapitalisingFirstLetter]]; 69 | } 70 | 71 | 72 | - (NSString *)stateVariableName { 73 | return [NSString stringWithFormat:@"_%@State", [[self name] statecStringByLoweringFirstLetter]]; 74 | } 75 | 76 | 77 | - (NSString *)stateClassNameInMachine:(StatecMachine *)machine { 78 | return [NSString stringWithFormat:@"%@%@State",[machine name],[[self name] statecStringByCapitalisingFirstLetter]]; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /Statec/Parser/StatecTransition.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecTransition.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class StatecEvent; 12 | @class StatecState; 13 | 14 | @interface StatecTransition : NSObject 15 | 16 | @property (strong) StatecState *sourceState; 17 | @property (strong) StatecState *targetState; 18 | 19 | - (id)initWithSourceState:(StatecState *)sourceState targetState:(StatecState *)targetState; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Statec/Parser/StatecTransition.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecTransition.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecTransition.h" 10 | 11 | #import "Statec.h" 12 | 13 | @implementation StatecTransition 14 | 15 | @synthesize sourceState = _sourceState; 16 | @synthesize targetState = _targetState; 17 | 18 | - (id)initWithSourceState:(StatecState *)sourceState targetState:(StatecState *)targetState { 19 | self = [super init]; 20 | if( self ) { 21 | _sourceState = sourceState; 22 | _targetState = targetState; 23 | } 24 | return self; 25 | } 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Statec/Statec-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Statec' target in the 'Statec' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /Statec/Statec.1: -------------------------------------------------------------------------------- 1 | .\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. 2 | .\"See Also: 3 | .\"man mdoc.samples for a complete listing of options 4 | .\"man mdoc for the short list of editing options 5 | .\"/usr/share/misc/mdoc.template 6 | .Dd 30/01/2012 \" DATE 7 | .Dt Statec 1 \" Program name and manual section number 8 | .Os Darwin 9 | .Sh NAME \" Section Header - required - don't modify 10 | .Nm Statec, 11 | .\" The following lines are read in generating the apropos(man -k) database. Use only key 12 | .\" words here as the database is built based on the words here and in the .ND line. 13 | .Nm Other_name_for_same_program(), 14 | .Nm Yet another name for the same program. 15 | .\" Use .Nm macro to designate other names for the documented program. 16 | .Nd This line parsed for whatis database. 17 | .Sh SYNOPSIS \" Section Header - required - don't modify 18 | .Nm 19 | .Op Fl abcd \" [-abcd] 20 | .Op Fl a Ar path \" [-a path] 21 | .Op Ar file \" [file] 22 | .Op Ar \" [file ...] 23 | .Ar arg0 \" Underlined argument - use .Ar anywhere to underline 24 | arg2 ... \" Arguments 25 | .Sh DESCRIPTION \" Section Header - required - don't modify 26 | Use the .Nm macro to refer to your program throughout the man page like such: 27 | .Nm 28 | Underlining is accomplished with the .Ar macro like this: 29 | .Ar underlined text . 30 | .Pp \" Inserts a space 31 | A list of items with descriptions: 32 | .Bl -tag -width -indent \" Begins a tagged list 33 | .It item a \" Each item preceded by .It macro 34 | Description of item a 35 | .It item b 36 | Description of item b 37 | .El \" Ends the list 38 | .Pp 39 | A list of flags and their descriptions: 40 | .Bl -tag -width -indent \" Differs from above in tag removed 41 | .It Fl a \"-a flag as a list item 42 | Description of -a flag 43 | .It Fl b 44 | Description of -b flag 45 | .El \" Ends the list 46 | .Pp 47 | .\" .Sh ENVIRONMENT \" May not be needed 48 | .\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1 49 | .\" .It Ev ENV_VAR_1 50 | .\" Description of ENV_VAR_1 51 | .\" .It Ev ENV_VAR_2 52 | .\" Description of ENV_VAR_2 53 | .\" .El 54 | .Sh FILES \" File used or created by the topic of the man page 55 | .Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact 56 | .It Pa /usr/share/file_name 57 | FILE_1 description 58 | .It Pa /Users/joeuser/Library/really_long_file_name 59 | FILE_2 description 60 | .El \" Ends the list 61 | .\" .Sh DIAGNOSTICS \" May not be needed 62 | .\" .Bl -diag 63 | .\" .It Diagnostic Tag 64 | .\" Diagnostic informtion here. 65 | .\" .It Diagnostic Tag 66 | .\" Diagnostic informtion here. 67 | .\" .El 68 | .Sh SEE ALSO 69 | .\" List links in ascending order by section, alphabetically within a section. 70 | .\" Please do not reference files that do not exist without filing a bug report 71 | .Xr a 1 , 72 | .Xr b 1 , 73 | .Xr c 1 , 74 | .Xr a 2 , 75 | .Xr b 2 , 76 | .Xr a 3 , 77 | .Xr b 3 78 | .\" .Sh BUGS \" Document known, unremedied bugs 79 | .\" .Sh HISTORY \" Document history if command behaves in a unique manner -------------------------------------------------------------------------------- /Statec/Statec.h: -------------------------------------------------------------------------------- 1 | // 2 | // Statec.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #ifndef Statec_Statec_h 10 | #define Statec_Statec_h 11 | 12 | typedef enum { 13 | StatecInstanceScope = 1, 14 | StaticClassScope = 2, 15 | StatecGlobalScope = 4, 16 | StatecStaticScope = 8 17 | } StatecScope; 18 | 19 | 20 | #import "StatecCompilationUnit.h" 21 | #import "StatecEnumeration.h" 22 | #import "StatecType.h" 23 | #import "StatecTypedef.h" 24 | #import "StatecClass.h" 25 | #import "StatecMethod.h" 26 | #import "StatecArgument.h" 27 | #import "StatecProperty.h" 28 | #import "StatecVariable.h" 29 | #import "StatecStatement.h" 30 | #import "StatecCodeStatement.h" 31 | #import "StatecConditionalStatement.h" 32 | #import "StatecStatementGroup.h" 33 | 34 | #import "StatecParser.h" 35 | #import "StatecMachine.h" 36 | #import "StatecInitial.h" 37 | #import "StatecState.h" 38 | #import "StatecEnter.h" 39 | #import "StatecExit.h" 40 | #import "StatecEvent.h" 41 | #import "StatecTransition.h" 42 | 43 | #import "StatecCompiler.h" 44 | 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /Statec/StatecEvent.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecEvent.h 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | 14 | @interface StatecEvent : NSObject 15 | 16 | @property (strong) NSString *name; 17 | @property (strong) NSString *targetState; 18 | @property (strong) NSMutableArray *transitions; 19 | 20 | - (NSString *)callbackMethodName; 21 | - (NSString *)internalCallbackMethodName; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Statec/StatecEvent.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecEvent.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 31/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import "StatecEvent.h" 10 | 11 | #import "NSString+StatecExtensions.h" 12 | 13 | @implementation StatecEvent 14 | 15 | @synthesize name = _name; 16 | @synthesize targetState = _targetState; 17 | @synthesize transitions = _transitions; 18 | 19 | 20 | - (id)init { 21 | self = [super init]; 22 | if( self ) { 23 | _transitions = [NSMutableArray array]; 24 | } 25 | return self; 26 | } 27 | 28 | 29 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree { 30 | self = [self init]; 31 | if( self ) { 32 | NSAssert( 4 == [[syntaxTree children] count], @"StatecEvent must have exactly 4 children" ); 33 | _name = [[[syntaxTree children] objectAtIndex:1] content]; 34 | _targetState = [[[syntaxTree children] objectAtIndex:3] content]; 35 | } 36 | return self; 37 | } 38 | 39 | 40 | - (NSString *)callbackMethodName { 41 | return [NSString stringWithFormat:@"%@Event", [[self name] statecStringByLoweringFirstLetter]]; 42 | } 43 | 44 | 45 | - (NSString *)internalCallbackMethodName { 46 | return [NSString stringWithFormat:@"%@EventFromMachine:", [[self name] statecStringByLoweringFirstLetter]]; 47 | } 48 | 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Statec/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Statec 4 | // 5 | // Created by Matt Mower on 30/01/2012. 6 | // Copyright (c) 2012 SmartFish Software Ltd.. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | #import "Statec.h" 14 | 15 | #import "StatecGVBuilder.h" 16 | #import "StatecHTMLBuilder.h" 17 | 18 | int main (int argc, const char * argv[]) 19 | { 20 | @autoreleasepool { 21 | NSError *error; 22 | 23 | NSString *outputFolder; 24 | NSString *inputFile; 25 | 26 | BOOL overwriteUserFiles = NO, generateGraph = NO, generateHTML = NO; 27 | 28 | int ch; 29 | while( ( ch = getopt( argc, (char *const*)argv, "d:i:ogh" ) ) != -1 ) { 30 | switch( ch ) { 31 | case 'd': 32 | outputFolder = [[NSString alloc] initWithUTF8String:optarg]; 33 | break; 34 | case 'i': 35 | inputFile = [[NSString alloc] initWithUTF8String:optarg]; 36 | break; 37 | case 'o': 38 | overwriteUserFiles = YES; 39 | break; 40 | case 'g': 41 | generateGraph = YES; 42 | break; 43 | case 'h': 44 | generateHTML = YES; 45 | break; 46 | } 47 | } 48 | 49 | if( !outputFolder ) { 50 | outputFolder = @"./"; 51 | } 52 | 53 | if( !inputFile ) { 54 | NSLog( @"No input file specified." ); 55 | return -1; 56 | } 57 | 58 | inputFile = [inputFile stringByExpandingTildeInPath]; 59 | outputFolder = [outputFolder stringByExpandingTildeInPath]; 60 | 61 | NSFileManager *fileManager = [NSFileManager defaultManager]; 62 | BOOL isDirectory; 63 | if( ![fileManager fileExistsAtPath:outputFolder isDirectory:&isDirectory] || !isDirectory ) { 64 | NSLog( @"Output folder \"%@\" does not exist, or is not a directory", outputFolder ); 65 | return -1; 66 | } 67 | 68 | NSString *source = [[NSString alloc] initWithContentsOfFile:inputFile encoding:NSUTF8StringEncoding error:&error]; 69 | if( !source ) { 70 | NSLog( @"Cannot read source: \"%@\" %@", inputFile, [error localizedDescription] ); 71 | return -1; 72 | } 73 | 74 | StatecCompiler *compiler = [[StatecCompiler alloc] init]; 75 | if( !compiler ) { 76 | NSLog( @"Cannot initialize compiler" ); 77 | return -1; 78 | } 79 | 80 | if( ![compiler parse:source] ) { 81 | NSLog( @"Compiler error" ); 82 | return -1; 83 | } 84 | 85 | NSArray *issues; 86 | if( ![compiler isMachineValid:&issues] ) { 87 | NSLog( @"Machine definition is invalid (%ld issues):", [issues count] ); 88 | for( NSString *issue in issues ) { 89 | NSLog( @"\t%@", issue ); 90 | } 91 | return -1; 92 | } 93 | 94 | StatecCompilationUnit *unit = [compiler generatedMachine]; 95 | if( ![unit writeFilesTo:outputFolder error:&error] ) { 96 | NSLog( @"Cannot write class files: %@", [error localizedDescription] ); 97 | return -1; 98 | } 99 | 100 | unit = [compiler userMachine]; 101 | if( overwriteUserFiles || ![fileManager fileExistsAtPath:[outputFolder stringByAppendingPathComponent:[unit headerFileName]]] ) { 102 | NSLog( @"No user file exists, writing user machine." ); 103 | if( ![unit writeFilesTo:outputFolder error:&error] ) { 104 | NSLog( @"Cannot write class files %@", [error localizedDescription] ); 105 | return -1; 106 | } 107 | } else { 108 | NSLog( @"User machine already exists." ); 109 | } 110 | 111 | if( generateGraph ) { 112 | NSString *graphFileName = [outputFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.gv",[[compiler machine] name]]]; 113 | StatecGVBuilder *gvBuilder = [[StatecGVBuilder alloc] init]; 114 | NSString *gvSource = [gvBuilder gvSourceFromMachine:[compiler machine]]; 115 | [gvSource writeToFile:graphFileName 116 | atomically:NO 117 | encoding:NSUTF8StringEncoding error:nil]; 118 | 119 | 120 | NSString *pathEnv = [[[NSProcessInfo processInfo] environment] objectForKey:@"PATH"]; 121 | NSArray *paths = [pathEnv componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@":"]]; 122 | for( NSString *path in paths ) { 123 | if( [fileManager fileExistsAtPath:[path stringByAppendingPathComponent:@"dot"]] ) { 124 | NSLog( @"Generating image file" ); 125 | NSTask *dotTask = [NSTask launchedTaskWithLaunchPath:[path stringByAppendingPathComponent:@"dot"] 126 | arguments:[NSArray arrayWithObjects:@"-O",@"-Tpng",graphFileName,nil]]; 127 | [dotTask waitUntilExit]; 128 | } 129 | } 130 | } 131 | 132 | if( generateHTML ) { 133 | StatecHTMLBuilder *htmlBuilder = [[StatecHTMLBuilder alloc] initWithMachine:[compiler machine]]; 134 | if( ![htmlBuilder writeToFolder:outputFolder error:&error] ) { 135 | NSLog( @"Error writing HTML output: %@", [error localizedDescription] ); 136 | } 137 | } 138 | 139 | } 140 | 141 | return 0; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /StatecRunner/StatecAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatecAppDelegate.h 3 | // StatecRunner 4 | // 5 | // Created by Matt Mower on 02/02/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "StatecParser.h" 12 | 13 | @interface StatecAppDelegate : NSObject 14 | 15 | @property (assign) IBOutlet NSWindow *window; 16 | 17 | @property (assign) IBOutlet NSPanel *statusPanel; 18 | 19 | @property (strong) NSString *source; 20 | @property (strong) NSString *sourceFile; 21 | @property (strong) NSString *targetFolder; 22 | @property (strong) NSString *statusMessage; 23 | 24 | - (IBAction)pickSourceFile:(id)sender; 25 | - (IBAction)pickTargetFolder:(id)sender; 26 | - (IBAction)compile:(id)sender; 27 | - (IBAction)dismissStatus:(id)sender; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /StatecRunner/StatecAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatecAppDelegate.m 3 | // StatecRunner 4 | // 5 | // Created by Matt Mower on 02/02/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "StatecAppDelegate.h" 10 | 11 | #import "StatecParser.h" 12 | #import "StatecCompiler.h" 13 | #import "StatecCompilationUnit.h" 14 | 15 | @implementation StatecAppDelegate 16 | 17 | @synthesize window = _window; 18 | 19 | @synthesize statusPanel = _statusPanel; 20 | 21 | @synthesize source = _source; 22 | @synthesize sourceFile = _sourceFile; 23 | @synthesize targetFolder = _targetFolder; 24 | @synthesize statusMessage = _statusMessage; 25 | 26 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 27 | [self setSourceFile:@""]; 28 | [self setTargetFolder:@""]; 29 | [self setStatusMessage:@""]; 30 | } 31 | 32 | 33 | - (IBAction)pickSourceFile:(id)sender { 34 | NSOpenPanel *openPanel = [NSOpenPanel openPanel]; 35 | [openPanel setCanChooseFiles:YES]; 36 | [openPanel setCanChooseDirectories:NO]; 37 | [openPanel setAllowsMultipleSelection:NO]; 38 | [openPanel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) { 39 | if( NSFileHandlingPanelOKButton == result ) { 40 | NSURL *fileURL = [[openPanel URLs] objectAtIndex:0]; 41 | [self setSourceFile:[fileURL path]]; 42 | if( [[self targetFolder] isEqualToString:@""] ) { 43 | [self setTargetFolder:[[fileURL path] stringByDeletingLastPathComponent]]; 44 | } 45 | } 46 | }]; 47 | } 48 | 49 | 50 | 51 | - (IBAction)pickTargetFolder:(id)sender { 52 | NSOpenPanel *openPanel = [NSOpenPanel openPanel]; 53 | [openPanel setCanChooseFiles:NO]; 54 | [openPanel setCanChooseDirectories:YES]; 55 | [openPanel setAllowsMultipleSelection:NO]; 56 | [openPanel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) { 57 | if( NSFileHandlingPanelOKButton == result ) { 58 | NSURL *fileURL = [[openPanel URLs] objectAtIndex:0]; 59 | [self setTargetFolder:[fileURL path]]; 60 | } 61 | }]; 62 | } 63 | 64 | 65 | - (IBAction)compile:(id)sender { 66 | NSError *error; 67 | BOOL overwriteUserFiles = NO; 68 | 69 | if( [[self sourceFile] isEqualToString:@""] ) { 70 | NSBeep(); 71 | return; 72 | } 73 | 74 | if( [[self targetFolder] isEqualToString:@""] ) { 75 | NSBeep(); 76 | return; 77 | } 78 | 79 | [NSApp beginSheet:[self statusPanel] modalForWindow:[self window] modalDelegate:nil didEndSelector:nil contextInfo:nil]; 80 | 81 | NSFileManager *fileManager = [NSFileManager defaultManager]; 82 | BOOL isDirectory; 83 | if( ![fileManager fileExistsAtPath:[self targetFolder] isDirectory:&isDirectory] || !isDirectory ) { 84 | [self setStatusMessage:[NSString stringWithFormat:@"Output folder \"%@\" does not exist, or is not a directory", [self targetFolder]]]; 85 | NSBeep(); 86 | return; 87 | } 88 | 89 | [self setSource:[[NSString alloc] initWithContentsOfFile:[self sourceFile] encoding:NSUTF8StringEncoding error:&error]]; 90 | if( ![self source] ) { 91 | [self setStatusMessage:[NSString stringWithFormat:@"Cannot read source: \"%@\" %@", [self sourceFile], [error localizedDescription]]]; 92 | NSBeep(); 93 | return; 94 | } 95 | 96 | StatecCompiler *compiler = [[StatecCompiler alloc] init]; 97 | if( !compiler ) { 98 | [self setStatusMessage:@"Cannot initialize compiler"]; 99 | NSBeep(); 100 | return; 101 | } 102 | 103 | [[compiler parser] setDelegate:self]; 104 | 105 | if( ![compiler parse:[self source]] ) { 106 | NSBeep(); 107 | return; 108 | } 109 | 110 | 111 | NSArray *issues; 112 | if( ![compiler isMachineValid:&issues] ) { 113 | NSMutableString *errorString = [NSMutableString stringWithFormat:@"Machine definition is invalid (%ld issues):\n", [issues count]]; 114 | for( NSString *issue in issues ) { 115 | [errorString appendFormat:@"* %@\n", issue]; 116 | } 117 | [self setStatusMessage:errorString]; 118 | NSBeep(); 119 | return; 120 | } else { 121 | [self setStatusMessage:@"Compiled machine classes"]; 122 | } 123 | 124 | StatecCompilationUnit *unit = [compiler generatedMachine]; 125 | if( ![unit writeFilesTo:[self targetFolder] error:&error] ) { 126 | [self setStatusMessage:[NSString stringWithFormat:@"Cannot write class files: %@", [error localizedDescription]]]; 127 | NSBeep(); 128 | return; 129 | } else { 130 | [self setStatusMessage:@"Written machine implementation files"]; 131 | } 132 | 133 | unit = [compiler userMachine]; 134 | if( overwriteUserFiles || ![fileManager fileExistsAtPath:[[self targetFolder] stringByAppendingPathComponent:[unit headerFileName]]] ) { 135 | if( ![unit writeFilesTo:[self targetFolder] error:&error] ) { 136 | [self setStatusMessage:[NSString stringWithFormat:@"Cannot write class files %@", [error localizedDescription]]]; 137 | NSBeep(); 138 | return; 139 | } 140 | } 141 | } 142 | 143 | 144 | - (IBAction)dismissStatus:(id)sender { 145 | [NSApp endSheet:[self statusPanel]]; 146 | [[self statusPanel] orderOut:sender]; 147 | } 148 | 149 | 150 | - (NSString *)sourceLineForToken:(CPToken *)token { 151 | NSUInteger startPosition; 152 | NSUInteger endPosition; 153 | [[self source] getLineStart:&startPosition end:&endPosition contentsEnd:NULL forRange:NSMakeRange( [token characterNumber], 1 )]; 154 | return [[self source] substringWithRange:NSMakeRange( startPosition, endPosition-startPosition-1 )]; 155 | } 156 | 157 | 158 | - (NSString *)indicatorLine:(NSUInteger)characterPosition { 159 | 160 | NSMutableString *line = [NSMutableString string]; 161 | while( characterPosition-- ) { 162 | [line appendString:@"-"]; 163 | }; 164 | [line appendString:@"^"]; 165 | return line; 166 | } 167 | 168 | 169 | - (void)parser:(StatecParser *)parser syntaxError:(NSString *)message token:(CPToken *)token expected:(NSSet *)expected { 170 | [self setStatusMessage:[NSString stringWithFormat: 171 | @"Syntax error on line %ld:%ld\n%@\n%@\n%@\nExpected: %@", 172 | [token lineNumber], 173 | [token columnNumber], 174 | [self sourceLineForToken:token], 175 | [self indicatorLine:[token columnNumber]], 176 | message, 177 | [[expected allObjects] componentsJoinedByString:@","] 178 | ]]; 179 | } 180 | 181 | 182 | - (void)parser:(StatecParser *)parser unexpectedToken:(CPToken *)token expected:(NSSet *)expected { 183 | [self setStatusMessage:[NSString stringWithFormat: 184 | @"Unexpected input '%@' on line:%ld:%ld\n%@\n%@\nExpected: %@", 185 | [token name], 186 | [token lineNumber], 187 | [token columnNumber], 188 | [self sourceLineForToken:token], 189 | [self indicatorLine:[token columnNumber]], 190 | [[expected allObjects] componentsJoinedByString:@","] 191 | ]]; 192 | } 193 | 194 | 195 | @end 196 | -------------------------------------------------------------------------------- /StatecRunner/StatecRunner-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.mattmower.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 18 25 | LSApplicationCategoryType 26 | public.app-category.developer-tools 27 | LSMinimumSystemVersion 28 | ${MACOSX_DEPLOYMENT_TARGET} 29 | NSHumanReadableCopyright 30 | Copyright © 2012 SmartFish Software Ltd. All rights reserved. 31 | NSMainNibFile 32 | MainMenu 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /StatecRunner/StatecRunner-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'StatecRunner' target in the 'StatecRunner' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /StatecRunner/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /StatecRunner/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /StatecRunner/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // StatecRunner 4 | // 5 | // Created by Matt Mower on 02/02/2012. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **)argv); 14 | } 15 | --------------------------------------------------------------------------------