Browse Source

initial commit (from svn repo)

Simon Van Mierlo 9 years ago
parent
commit
04ec602b01
100 changed files with 7235 additions and 102 deletions
  1. 9 0
      .buildpath
  2. 11 59
      .gitignore
  3. 24 0
      .project
  4. 11 0
      .pydevproject
  5. 643 41
      LICENSE
  6. 51 2
      README.md
  7. 0 0
      __init__.py
  8. 77 0
      csharp_runtime/Association.cs
  9. 23 0
      csharp_runtime/AssociationException.cs
  10. 22 0
      csharp_runtime/AssociationReferenceException.cs
  11. 12 0
      csharp_runtime/AssociationWrapper.cs
  12. 38 0
      csharp_runtime/ConcurrentOutputListener.cs
  13. 89 0
      csharp_runtime/ControllerBase.cs
  14. 41 0
      csharp_runtime/Event.cs
  15. 105 0
      csharp_runtime/EventQueue.cs
  16. 22 0
      csharp_runtime/GameControllerBase.cs
  17. 11 0
      csharp_runtime/IOutputListener.cs
  18. 23 0
      csharp_runtime/InputException.cs
  19. 34 0
      csharp_runtime/InstanceWrapper.cs
  20. 12 0
      csharp_runtime/MyClass.cs
  21. 253 0
      csharp_runtime/ObjectManagerBase.cs
  22. 34 0
      csharp_runtime/OutputListener.cs
  23. 22 0
      csharp_runtime/ParameterException.cs
  24. 27 0
      csharp_runtime/Properties/AssemblyInfo.cs
  25. 22 0
      csharp_runtime/RunTimeException.cs
  26. 95 0
      csharp_runtime/RuntimeClassBase.cs
  27. 146 0
      csharp_runtime/ThreadsControllerBase.cs
  28. 55 0
      csharp_runtime/sccdlib.csproj
  29. 50 0
      csharp_runtime/sccdlib.sln
  30. 41 0
      csharp_sccd_compiler/Action.cs
  31. 96 0
      csharp_sccd_compiler/Association.cs
  32. 45 0
      csharp_sccd_compiler/Attribute.cs
  33. 104 0
      csharp_sccd_compiler/Class.cs
  34. 132 0
      csharp_sccd_compiler/ClassDiagram.cs
  35. 890 0
      csharp_sccd_compiler/Code Generation/CSharpGenerator.cs
  36. 89 0
      csharp_sccd_compiler/Code Generation/CodeGenerator.cs
  37. 55 0
      csharp_sccd_compiler/Code Generation/FileOutputer.cs
  38. 29 0
      csharp_sccd_compiler/Compiler.cs
  39. 17 0
      csharp_sccd_compiler/Constants.cs
  40. 28 0
      csharp_sccd_compiler/Constructor.cs
  41. 21 0
      csharp_sccd_compiler/Destructor.cs
  42. 51 0
      csharp_sccd_compiler/EnterExitAction.cs
  43. 22 0
      csharp_sccd_compiler/Exceptions/ActionException.cs
  44. 22 0
      csharp_sccd_compiler/Exceptions/CodeBlockException.cs
  45. 22 0
      csharp_sccd_compiler/Exceptions/CompilerException.cs
  46. 24 0
      csharp_sccd_compiler/Exceptions/LexerException.cs
  47. 22 0
      csharp_sccd_compiler/Exceptions/StateReferenceException.cs
  48. 22 0
      csharp_sccd_compiler/Exceptions/TransitionException.cs
  49. 22 0
      csharp_sccd_compiler/Exceptions/UnprocessedException.cs
  50. 87 0
      csharp_sccd_compiler/Expression/Expression.cs
  51. 12 0
      csharp_sccd_compiler/Expression/ExpressionPart.cs
  52. 20 0
      csharp_sccd_compiler/Expression/ExpressionPartString.cs
  53. 20 0
      csharp_sccd_compiler/Expression/InStateCall.cs
  54. 12 0
      csharp_sccd_compiler/Expression/LValue.cs
  55. 17 0
      csharp_sccd_compiler/Expression/SelfReference.cs
  56. 38 0
      csharp_sccd_compiler/FormalEventParameter.cs
  57. 56 0
      csharp_sccd_compiler/FormalParameter.cs
  58. 161 0
      csharp_sccd_compiler/Lexing/Lexer.cs
  59. 40 0
      csharp_sccd_compiler/Lexing/Token.cs
  60. 35 0
      csharp_sccd_compiler/Logger.cs
  61. 69 0
      csharp_sccd_compiler/Method.cs
  62. 22 0
      csharp_sccd_compiler/Properties/AssemblyInfo.cs
  63. 128 0
      csharp_sccd_compiler/StateChart.cs
  64. 337 0
      csharp_sccd_compiler/StateChartNode.cs
  65. 57 0
      csharp_sccd_compiler/StateChartTransition.cs
  66. 26 0
      csharp_sccd_compiler/StateReference.cs
  67. 30 0
      csharp_sccd_compiler/SubAction/Assign.cs
  68. 20 0
      csharp_sccd_compiler/SubAction/Log.cs
  69. 109 0
      csharp_sccd_compiler/SubAction/RaiseEvent.cs
  70. 20 0
      csharp_sccd_compiler/SubAction/Script.cs
  71. 9 0
      csharp_sccd_compiler/SubAction/SubAction.cs
  72. 73 0
      csharp_sccd_compiler/TriggerEvent.cs
  73. 104 0
      csharp_sccd_compiler/Visitors/PathCalculator.cs
  74. 197 0
      csharp_sccd_compiler/Visitors/StateLinker.cs
  75. 10 0
      csharp_sccd_compiler/Visitors/Visitable.cs
  76. 100 0
      csharp_sccd_compiler/Visitors/Visitor.cs
  77. 97 0
      csharp_sccd_compiler/csharp_sccd_compiler.csproj
  78. 50 0
      csharp_sccd_compiler/csharp_sccd_compiler.sln
  79. 42 0
      csharp_tests/CSharpTests.cs
  80. 51 0
      csharp_tests/CodeCompiler.cs
  81. 27 0
      csharp_tests/Properties/AssemblyInfo.cs
  82. 45 0
      csharp_tests/PythonTests.cs
  83. 45 0
      csharp_tests/TestEvent.cs
  84. 151 0
      csharp_tests/TestsBase.cs
  85. 68 0
      csharp_tests/csharp_tests.csproj
  86. 44 0
      csharp_tests/csharp_tests.sln
  87. 138 0
      examples/HTTP_client/classes/http_client.xml
  88. 58 0
      examples/HTTP_client/classes/prompt.xml
  89. 422 0
      examples/HTTP_client/client.py
  90. 19 0
      examples/HTTP_client/client.xml
  91. 1 0
      examples/HTTP_client/make.bat
  92. 4 0
      examples/HTTP_client/run.sh
  93. 8 0
      examples/HTTP_client/run_client.py
  94. 117 0
      examples/HTTP_client/socket2event.py
  95. 47 0
      examples/HTTP_server/classes/echo.xml
  96. 110 0
      examples/HTTP_server/classes/server.xml
  97. 157 0
      examples/HTTP_server/classes/socket.xml
  98. 1 0
      examples/HTTP_server/make.bat
  99. 8 0
      examples/HTTP_server/run_echo_server.py
  100. 0 0
      examples/HTTP_server/server.py

+ 9 - 0
.buildpath

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+	<buildpath>
+		<buildpathentry kind="src" path=""/>
+		<buildpathentry kind="con" path="org.eclipse.dltk.mod.launching.INTERPRETER_CONTAINER"/>
+		<buildpathentry kind="con" path="org.eclipse.vjet.eclipse.core.JSNATIVE_CONTAINER/JS Native Types"/>
+		<buildpathentry kind="con" path="org.eclipse.vjet.eclipse.core.BROWSER_CONTAINER/Browser SDK"/>
+		<buildpathentry kind="con" path="org.eclipse.vjet.eclipse.core.VJO_CONTAINER/VJO LIB"/>
+	</buildpath>
+

+ 11 - 59
.gitignore

@@ -1,60 +1,12 @@
-# ---> Python
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
-*.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-#  Usually these files are written by a python script from a template
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*,cover
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
+*.pyc
+.metadata*
+*.dll
+*.dll.mdb
+*.userprefs
+*~
+RemoteSystemsTempFiles
+csharp_tests/test-results
+csharp_tests/bin
+tanks/python_runtime
+python_sccd_compiler/python_runtime
 

+ 24 - 0
.project

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>SCCDXML</name>
+	<comment></comment>
+	<projects>
+		<project>MvK_HUTN</project>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.vjet.eclipse.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.python.pydev.PyDevBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.vjet.core.nature</nature>
+		<nature>org.python.pydev.pythonNature</nature>
+	</natures>
+</projectDescription>

+ 11 - 0
.pydevproject

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?eclipse-pydev version="1.0"?><pydev_project>
+<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
+<path>/${PROJECT_DIR_NAME}</path>
+</pydev_pathproperty>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
+<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
+<pydev_pathproperty name="org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH">
+<path>N:\workspace\MvK_HUTN</path>
+</pydev_pathproperty>
+</pydev_project>

File diff suppressed because it is too large
+ 643 - 41
LICENSE


+ 51 - 2
README.md

@@ -1,3 +1,52 @@
-# SCCD
+This is a fork of https://github.com/gl3nn/sccd_compiler
 
-The SCCD (Statecharts + Class Diagrams) compiler and runtime.
+Statecharts and Class Diagram Compiler
+======================================
+
+Usage
+-------------
+Manual for the compiler written in Python :
+```sh
+$python sccdc.py --help
+usage: sccdc.py [-h] [-o OUTPUT] [-v VERBOSE] [-p PROTOCOL] [-l LANGUAGE]
+                input
+
+positional arguments:
+  input                 The path to the XML file to be compiled.
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -o OUTPUT, --output OUTPUT
+                        The path to the generated code. Defaults to the same
+                        name as the input file but with matching extension.
+  -v VERBOSE, --verbose VERBOSE
+                        2 = all output; 1 = only warnings and errors; 0 = only
+                        errors; -1 = no output. Defaults to 2.
+  -p PLATFORM, --platform PLATFORM
+                        Let the compiled code run on top of threads or
+                        gameloop. The default is threads.
+  -l LANGUAGE, --language LANGUAGE
+                        Target language, "csharp", "python" or "javascript". Defaults
+                        to "python".
+```
+
+For a detailed explanation on the formalism's syntax please consult the latest report <a href="http://msdl.cs.mcgill.ca/people/glenn/60_Downloads">here</a>.
+
+Tests
+-------------
+Executing the tests written for the Python compiler and generated Python code can be done by running `tests.py`. This file imports the test cases from the `test_files` folder.
+
+Tanks Example
+-------------
+In the `tanks` folder a tanks game can be found for which both the input handling of the player-controlled tank, and the behaviour of the NPC tank are modelled using the SCCD formalism. For this specific example the commands to compile the models are as follows :
+
+```sh
+python sccdc.py tanks/player_controller.xml -o tanks/player_controller.py -p gameloop
+python sccdc.py tanks/ai_controller.xml -o tanks/ai_controller.py -p gameloop
+```
+The resulting files `player_controller.py` and `ai_controller.py` (and any other compiled code) depend on the runtime files found in `python_runtime`, so this folder should either be put in `PYTHONPATH` or directly in the `tanks` directory (you can use a symbolic link).
+
+Live demo
+---------
+
+Live demo of a statechart (compiled to Javascript) simulating a bouncing ball: https://gwd.dyn.mk/public/sccd/svgdemo

+ 0 - 0
__init__.py


+ 77 - 0
csharp_runtime/Association.cs

@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+
+namespace sccdlib
+{
+    /**
+     * wrapper object for one association relation
+     */
+    public class Association
+    {
+        string name;
+        string class_name;
+        int min_card;
+        int max_card;
+        List<InstanceWrapper> instances;
+        
+        public Association (string name, string class_name, int min_card, int max_card)
+        {
+            this.min_card = min_card;
+            this.max_card = max_card;
+            this.name = name;
+            this.class_name = class_name;
+            this.instances = new List<InstanceWrapper>();
+        }
+        
+        public string getName ()
+        {
+            return this.name;
+        }
+        
+        public string getClassName ()
+        {
+            return this.class_name;   
+        }
+        
+        public bool allowedToAdd ()
+        {
+            return ( (this.max_card == -1) || ( this.instances.Count < this.max_card ) );    
+        }
+        
+        public void addInstance (InstanceWrapper instance)
+        {
+            if (this.allowedToAdd ()) {
+                this.instances.Add (instance);
+            } else {
+                throw new AssociationException("Not allowed to add the instance to the association.");
+            }
+        }
+        
+        public ReadOnlyCollection<InstanceWrapper> getAllInstances ()
+        {
+            return this.instances.AsReadOnly();   
+        }
+        
+        /*
+        public List<InstanceWrapper> getAllInstances ()
+        {
+            return new List<InstanceWrapper>(this.instances);
+        }*/
+        
+        public InstanceWrapper getInstance(int index)
+        {
+            try 
+            {
+                return this.instances[index];
+            }
+            catch (ArgumentOutOfRangeException)
+            {
+                throw new AssociationException("Invalid index for fetching instance from association.");
+            }
+        }
+        
+    }
+}
+

+ 23 - 0
csharp_runtime/AssociationException.cs

@@ -0,0 +1,23 @@
+using System;
+
+namespace sccdlib
+{
+    public class AssociationException : RunTimeException
+    {
+        public AssociationException ()
+        {
+        }
+        
+        public AssociationException(string message)
+            : base(message)
+        {
+        }
+    
+        public AssociationException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+  
+}
+

+ 22 - 0
csharp_runtime/AssociationReferenceException.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace sccdlib
+{
+    public class AssociationReferenceException : RunTimeException
+    {
+        public AssociationReferenceException ()
+        {
+        }
+        
+        public AssociationReferenceException(string message)
+            : base(message)
+        {
+        }
+    
+        public AssociationReferenceException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+}
+

+ 12 - 0
csharp_runtime/AssociationWrapper.cs

@@ -0,0 +1,12 @@
+using System;
+
+namespace sccdlib
+{
+    public class AssociationWrapper
+    {
+        public AssociationWrapper ()
+        {
+        }
+    }
+}
+

+ 38 - 0
csharp_runtime/ConcurrentOutputListener.cs

@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+
+namespace sccdlib
+{
+    public class ConcurrentOutputListener : IOutputListener
+    {
+        ConcurrentQueue<Event> queue = new ConcurrentQueue<Event>();
+        List<string> ports = new List<string>();
+        
+        public ConcurrentOutputListener (string[] port_names)
+        {
+            foreach (string port_name in port_names)
+            {
+                this.ports.Add (port_name);
+            }
+        }
+        
+        public void add (Event output_event)
+        {
+            if (this.ports.Count == 0 || this.ports.Contains (output_event.getPort ())) {
+                this.queue.Enqueue (output_event);
+            }
+        }
+                
+        public Event fetch ()
+        {
+            Event fetched_event;
+            bool success = this.queue.TryDequeue (out fetched_event);
+            if (success) {
+                return fetched_event;
+            }
+            return null;
+        }
+    }
+}
+

+ 89 - 0
csharp_runtime/ControllerBase.cs

@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+
+namespace sccdlib
+{
+    public abstract class ControllerBase
+    {
+        protected ObjectManagerBase object_manager;
+        protected bool done = false;
+        protected List<string> input_ports = new List<string>();
+        protected EventQueue input_queue = new EventQueue();
+
+        protected List<string> output_ports = new List<string>();
+        protected List<IOutputListener> output_listeners = new List<IOutputListener>();
+
+        public ControllerBase ()
+        {
+        }
+
+        protected void addInputPort(string port_name)
+        {
+            this.input_ports.Add(port_name);
+        }
+        
+        protected void addOutputPort(string port_name)
+        {
+            this.output_ports.Add(port_name);
+        }
+
+        public void broadcast(Event new_event)
+        {
+            this.object_manager.broadcast(new_event);
+        }
+        
+        public virtual void start()
+        {
+            this.object_manager.start();
+        }
+    
+        public virtual void stop()
+        {
+        }
+
+        public void outputEvent(Event output_event)
+        {
+            foreach (IOutputListener listener in this.output_listeners)
+            {
+                listener.add(output_event);
+            }
+        }
+        
+        public IOutputListener addOutputListener(string[] ports)
+        {
+            IOutputListener listener = this.createOutputListener(ports);
+            this.output_listeners.Add(listener);
+            return listener;
+        }
+        
+        protected virtual IOutputListener createOutputListener (string[] ports)
+        {
+            return new OutputListener(ports);   
+        }
+        
+        public virtual void addInput(Event input_event, double time_offset = 0.0)
+        {   
+            if ( input_event.getName() == "" )
+                throw new InputException("Input event can't have an empty name.");
+            
+            if ( !this.input_ports.Contains (input_event.getPort()) )
+                throw new InputException("Input port mismatch.");
+            
+            this.input_queue.Add(input_event, time_offset);
+        }
+    
+        public virtual void addEventList(List<Tuple<Event,double>> event_list)
+        {
+            foreach (Tuple<Event,double> event_tuple in event_list)
+            {   
+                this.addInput (event_tuple.Item1, event_tuple.Item2);
+            }
+        }
+        
+        public ObjectManagerBase getObjectManager ()
+        {
+            return this.object_manager;
+        }
+    }
+}
+

+ 41 - 0
csharp_runtime/Event.cs

@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+
+namespace sccdlib
+{
+    public class Event
+    {
+        string name = "";
+        string port = "";
+        object[] parameters;
+        
+
+        public Event (string name = "", string port = "", object[] parameters = null)
+        {
+            this.name = name;
+            this.port = port;
+            this.parameters = (parameters == null ? new object[] {} : parameters);
+        }
+
+        public string getName ()
+        {
+            return this.name;
+        }
+
+        public string getPort ()
+        {
+            return this.port;
+        }
+        
+        public object[] getParameters ()
+        {
+            return this.parameters;
+        }
+        
+        public override string ToString()
+        {
+            return string.Format("(event name : {0}; port : {1}; parameters : [{2}])", this.name, this.port, string.Join(", ", this.parameters));
+        }
+    }
+}
+

+ 105 - 0
csharp_runtime/EventQueue.cs

@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+
+namespace sccdlib
+{
+    /// <summary>
+    /// Abstracting the event Queue. Currently uses a List to store it's content, but could have better performance when built on a priority queue.
+    /// </summary>
+    public class EventQueue
+    {
+        private class EventQueueEntry
+        {
+            double time_offset;
+            Event e;
+            
+            public EventQueueEntry(Event e, double time_offset)
+            {
+                this.e = e;
+                this.time_offset = time_offset;
+            }
+            
+            public void decreaseTime(double offset)
+            {
+                this.time_offset -= offset;   
+            }
+            
+            public Event getEvent()
+            {
+                return this.e;
+            }
+            
+            public double getTime ()
+            {
+                return this.time_offset;
+            }
+            
+        }
+
+        List<EventQueueEntry> event_list = new List<EventQueueEntry>();
+                
+        public void Add (Event e, double time_offset)
+        {
+            EventQueueEntry entry = new EventQueueEntry(e,time_offset);
+            //We maintain a sorted stable list
+            int insert_index = 0;
+            for (int index = this.event_list.Count-1; index >= 0; index--)
+            {
+                if (this.event_list[index].getTime() <= time_offset)
+                {
+                    insert_index = index + 1;
+                    break;
+                }
+            }
+            this.event_list.Insert(insert_index, entry);
+        }
+
+        public void decreaseTime(double offset)
+        {
+            foreach (EventQueueEntry e in this.event_list)
+                e.decreaseTime(offset);
+        }
+        
+        public bool isEmpty()
+        {
+            return this.event_list.Count == 0;
+        }
+        
+        
+        /// <summary>
+        /// Gets the earliest time.
+        /// </summary>
+        /// <returns>
+        /// The earliest time. Positive infinity if no events are present.
+        /// </returns>
+        public double getEarliestTime ()
+        {
+            if (this.isEmpty())
+            {
+                return double.PositiveInfinity;
+            }
+            else
+            {
+                return this.event_list[0].getTime();
+            }
+        }
+
+        public List<Event> popDueEvents ()
+        {
+            List<Event> result = new List<Event> ();
+            if (this.isEmpty() || this.event_list[0].getTime() > 0.0)
+                //There are no events, or the earliest event isn't due, so we can already return an emtpy result
+                return result;
+
+            int index = 0;
+            while (index < this.event_list.Count && this.event_list[index].getTime() <= 0.0)
+            {
+                result.Add(this.event_list[index].getEvent()); //Add all events that are due (offset less than 0) to the result
+                index++;
+            }
+            this.event_list.RemoveRange(0, result.Count);
+            return result;
+        }
+    }
+}
+

+ 22 - 0
csharp_runtime/GameControllerBase.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+
+namespace sccdlib
+{
+    public class GameControllerBase : ControllerBase
+    {
+        public GameControllerBase ()
+            : base()
+        {        
+        }
+        
+        public void update(double delta)
+        {  
+            this.input_queue.decreaseTime(delta);
+            foreach(Event e in this.input_queue.popDueEvents())
+                this.broadcast (e);
+            this.object_manager.stepAll(delta);
+        }
+    }
+}
+

+ 11 - 0
csharp_runtime/IOutputListener.cs

@@ -0,0 +1,11 @@
+using System;
+
+namespace sccdlib
+{
+    public interface IOutputListener
+    {
+        void add (Event output_event);
+        Event fetch ();
+    }
+}
+

+ 23 - 0
csharp_runtime/InputException.cs

@@ -0,0 +1,23 @@
+using System;
+
+namespace sccdlib
+{
+    public class InputException : RunTimeException
+    {
+        public InputException ()
+        {
+        }
+        
+        public InputException(string message)
+            : base(message)
+        {
+        }
+    
+        public InputException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+  
+}
+

+ 34 - 0
csharp_runtime/InstanceWrapper.cs

@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+
+namespace sccdlib
+{
+    public class InstanceWrapper
+    {
+        RuntimeClassBase instance;
+        Dictionary<string,Association> associations = new Dictionary<string, Association>();
+        
+        
+        public InstanceWrapper (RuntimeClassBase instance, List<Association> associations)
+        {
+            this.instance = instance;
+            foreach (var association in associations) {
+                this.associations[association.getName()] = association;   
+            }
+        }
+        
+        public Association getAssociation (string name)
+        {
+            try{
+                return this.associations[name];
+            }catch (KeyNotFoundException) {
+                throw new AssociationReferenceException("Unknown association.");
+            }
+        }
+        
+        public RuntimeClassBase getInstance ()
+        {
+            return this.instance;
+        }
+    }
+}

+ 12 - 0
csharp_runtime/MyClass.cs

@@ -0,0 +1,12 @@
+using System;
+
+namespace sccdlib
+{
+	public class MyClass
+	{
+		public MyClass ()
+		{
+		}
+	}
+}
+

+ 253 - 0
csharp_runtime/ObjectManagerBase.cs

@@ -0,0 +1,253 @@
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace sccdlib
+{
+    public abstract class ObjectManagerBase
+    {
+        protected ControllerBase controller;
+        EventQueue events = new EventQueue();
+        Dictionary<RuntimeClassBase,InstanceWrapper> instances_map = new Dictionary<RuntimeClassBase,InstanceWrapper> ();
+        
+        public ObjectManagerBase (ControllerBase controller)
+        {
+            this.controller = controller;
+        }
+       
+        
+        public void addEvent (Event input_event, double time_offset = 0.0)
+        {
+            this.events.Add (input_event, time_offset);
+        }
+        
+        public void broadcast (Event new_event)
+        {
+            foreach (RuntimeClassBase instance in this.instances_map.Keys)
+                instance.addEvent(new_event);
+        }
+        
+        public  double getWaitTime()
+        {
+            //first get waiting time of the object manager's events
+            double smallest_time = this.events.getEarliestTime();
+            //check all the instances
+            foreach (RuntimeClassBase instance in this.instances_map.Keys)
+                smallest_time = Math.Min(smallest_time, instance.getEarliestEventTime());
+            return smallest_time;
+        }
+        
+        public void step (double delta)
+        {
+            this.events.decreaseTime(delta);
+            foreach( Event e in this.events.popDueEvents())
+                this.handleEvent (e);
+        }
+        
+        private void handleEvent (Event handle_event)
+        {
+            string event_name = handle_event.getName ();
+            if (event_name == "narrow_cast") {
+                this.handleNarrowCastEvent(handle_event.getParameters());
+            } else if (event_name == "broad_cast") {
+                this.handleBroadCastEvent(handle_event.getParameters());
+            } else if (event_name == "create_instance") {
+                this.handleCreateEvent(handle_event.getParameters());
+            } else if (event_name == "associate_instance") {
+                this.handleAssociateEvent(handle_event.getParameters());
+            } else if (event_name == "start_instance") {
+                this.handleStartInstanceEvent(handle_event.getParameters());
+            }
+        }
+        
+        public void stepAll (double delta)
+        {
+            this.step(delta);
+            foreach (RuntimeClassBase instance in this.instances_map.Keys)
+                instance.step(delta);
+        }
+    
+        
+        public void start ()
+        {
+            foreach (RuntimeClassBase instance in this.instances_map.Keys)
+                instance.start(); 
+        }
+        
+        /// <summary>
+        /// Processes the association reference.
+        /// </summary>
+        /// <returns>
+        /// The association reference.
+        /// </returns>
+        /// <param name='input_string'>
+        /// Input_string.
+        /// </param>
+        private List<Tuple<string, int>> processAssociationReference (string input_string)
+        {
+            if (input_string.Length == 0)
+                throw new AssociationReferenceException("Empty association reference.");
+            string[] path_string = input_string.Split (new char[] {'/'});
+            Regex regex = new Regex(@"^([a-zA-Z_]\w*)(?:\[(\d+)\])?$");
+            
+            var result = new List<Tuple<string, int>>();
+            
+            foreach (string string_piece in path_string) {
+                Match match = regex.Match (string_piece);
+                if (match.Success ){
+                    string name = match.Groups[1].ToString ();
+                    int index;
+                    if (match.Groups[2].Success)
+                        int.TryParse(match.Groups[2].ToString(), out index);
+                    else
+                        index = -1;
+                    result.Add( new Tuple<string, int>(name,index));
+                }else{
+                    throw new AssociationReferenceException("Invalid entry in association reference.");
+                }   
+            }
+            return result;
+        }
+        
+        /// <summary>
+        /// Gets the instances.
+        /// </summary>
+        /// <returns>
+        /// The instances.
+        /// </returns>
+        /// <param name='source'>
+        /// Source.
+        /// </param>
+        /// <param name='traversal_list'>
+        /// Traversal_list.
+        /// </param>
+        private List<InstanceWrapper> getInstances (RuntimeClassBase source, List<Tuple<string, int>> traversal_list)
+        {
+            var currents = new List<InstanceWrapper> ();
+            currents.Add (this.instances_map [source]);
+            foreach (Tuple<string, int> tuple in traversal_list) {
+                var nexts = new List<InstanceWrapper> ();
+                foreach ( InstanceWrapper current in currents ){
+                    Association association = current.getAssociation (tuple.Item1);   
+                    if (tuple.Item2 >= 0 )
+                        nexts.Add ( association.getInstance(tuple.Item2) );
+                    else if (tuple.Item2 == -1)
+                        nexts.AddRange ( association.getAllInstances() );
+                    else
+                        throw new AssociationReferenceException("Incorrect index in association reference.");
+                }
+                currents = nexts;
+            }
+            return currents;
+        }
+        
+        /// <summary>
+        /// Handles the start instance event.
+        /// </summary>
+        /// <param name='parameters'>
+        /// [0] The instance the event originates from.
+        /// [1] An association reference string targeting the instance to start.
+        /// </param>
+        private void handleStartInstanceEvent (object[] parameters)
+        {
+            if (parameters.Length != 2) {
+                throw new ParameterException ("The start instance event needs 2 parameters.");    
+            } else {
+                RuntimeClassBase source = (RuntimeClassBase) parameters[0];
+                var traversal_list = this.processAssociationReference((string) parameters [1]);
+                
+                foreach( InstanceWrapper i in this.getInstances (source, traversal_list)){
+                    i.getInstance().start();
+                }
+            }
+        }
+        
+        /// <summary>
+        /// Handles the broad cast event.
+        /// </summary>
+        /// <param name='parameters'>
+        /// [0] The event to be broadcasted.
+        /// </param>
+        private void handleBroadCastEvent(object[] parameters)
+        {
+            if (parameters.Length != 1 ) 
+                throw new ParameterException ("The broadcast event needs 1 parameter.");   
+            this.broadcast((Event)parameters[0]); 
+        }
+
+        private void handleCreateEvent (object[] parameters)
+        {
+            if (parameters.Length < 2) {
+                throw new ParameterException ("The create event needs at least 2 parameters.");   
+            } else {
+                RuntimeClassBase source = (RuntimeClassBase)parameters [0];
+                string association_name = (string)parameters [1];
+                Association association = this.instances_map[source].getAssociation (association_name);
+                if (association.allowedToAdd ()){
+                    int constructor_parameters_length = parameters.Length -2;
+                    object[] constructor_parameters = new object[constructor_parameters_length];
+                    Array.Copy(parameters, 2, constructor_parameters, 0, constructor_parameters_length);
+                    InstanceWrapper new_instance_wrapper = this.createInstance(association.getClassName (), constructor_parameters);
+                    association.addInstance (new_instance_wrapper);
+                    source.addEvent(
+                        new Event(name: "instance_created", parameters : new object[] {association_name})
+                    );
+                }else{
+                    source.addEvent (
+                        new Event(name: "instance_creation_error", parameters : new object[] {association_name})    
+                    );
+                }    
+            }
+        }
+        
+                
+        private void handleAssociateEvent (object[] parameters)
+        {
+            if (parameters.Length != 3) {
+                throw new ParameterException ("The associate_instance event needs 3 parameters.");
+            } else {
+                RuntimeClassBase source = (RuntimeClassBase)parameters [0];
+                List<InstanceWrapper> to_copy_list = this.getInstances (source, this.processAssociationReference ((string)parameters [1]));
+                if (to_copy_list.Count != 1)
+                    throw new AssociationReferenceException ("Invalid source association reference.");
+                InstanceWrapper wrapped_to_copy_instance = to_copy_list [0];
+                List<Tuple<string,int>> dest_list = this.processAssociationReference ((string)parameters [2]);
+                if (dest_list.Count == 0)
+                    throw new AssociationReferenceException ("Invalid destination association reference.");
+                Tuple<string,int> last_tuple = dest_list [dest_list.Count - 1];
+                if (last_tuple.Item2 != -1)
+                    throw new AssociationReferenceException ("Last association name in association reference should not be accompanied by an index.");
+                dest_list.RemoveAt (dest_list.Count - 1);
+                foreach (InstanceWrapper i in this.getInstances(source, dest_list)) {
+                    i.getAssociation (last_tuple.Item1).addInstance (wrapped_to_copy_instance);
+                }
+            }
+        }
+            
+        private void handleNarrowCastEvent(object[] parameters)
+        {
+            if (parameters.Length != 3){
+                throw new ParameterException ("The associate_instance event needs 3 parameters.");
+            }else{
+                RuntimeClassBase source = (RuntimeClassBase)parameters [0];
+                Event cast_event = (Event) parameters[2];
+                foreach (InstanceWrapper i in this.getInstances(source, this.processAssociationReference( (string) parameters[1])))
+                    i.getInstance ().addEvent(cast_event);
+            
+            }
+        }   
+        
+        
+        protected abstract InstanceWrapper instantiate(string class_name, object[] construct_params);
+
+            
+        public InstanceWrapper createInstance(string class_name, object[] construct_params)
+        {
+            InstanceWrapper iw = this.instantiate(class_name, construct_params);
+            if (iw != null)
+                this.instances_map[iw.getInstance ()] = iw;
+            return iw;
+        }
+    }
+}
+

+ 34 - 0
csharp_runtime/OutputListener.cs

@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+
+namespace sccdlib
+{
+    public class OutputListener : IOutputListener
+    {
+        Queue<Event> queue = new Queue<Event>();
+        List<string> ports = new List<string>();
+        
+        public OutputListener (string[] port_names)
+        {
+            foreach (string port_name in port_names)
+            {
+                this.ports.Add (port_name);
+            }
+        }
+        
+        public void add (Event output_event)
+        {
+            if (this.ports.Count == 0 || this.ports.Contains (output_event.getPort ())) {
+                this.queue.Enqueue (output_event);
+            }
+        }
+                
+        public Event fetch ()
+        {
+            if (this.queue.Count > 0)
+                return this.queue.Dequeue ();
+            return null;
+        }
+    }
+}
+

+ 22 - 0
csharp_runtime/ParameterException.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace sccdlib
+{
+    public class ParameterException : RunTimeException
+    {
+        public ParameterException ()
+        {
+        }      
+                
+        public ParameterException(string message)
+            : base(message)
+        {
+        }
+    
+        public ParameterException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+}
+

+ 27 - 0
csharp_runtime/Properties/AssemblyInfo.cs

@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes. 
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("csharp_runtime")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("gl3nn")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly, 
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+

+ 22 - 0
csharp_runtime/RunTimeException.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace sccdlib
+{
+    public class RunTimeException : Exception
+    {
+        public RunTimeException ()
+        {
+        }
+        
+        public RunTimeException(string message)
+            : base(message)
+        {
+        }
+    
+        public RunTimeException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+}
+

+ 95 - 0
csharp_runtime/RuntimeClassBase.cs

@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+
+namespace sccdlib
+{
+    public abstract class RuntimeClassBase
+    {
+
+        protected bool active = false;
+        protected bool state_changed = false;
+        protected EventQueue events = new EventQueue();
+        protected ControllerBase controller;
+        protected ObjectManagerBase object_manager;
+        protected Dictionary<int,double> timers = null;
+
+        public RuntimeClassBase ()
+        {
+        }
+        
+        public void addEvent (Event input_event, double time_offset = 0.0)
+        {
+            this.events.Add (input_event, time_offset);
+        }
+        
+        
+        public double getEarliestEventTime ()
+        {
+            if (this.timers != null)
+            {
+                double smallest_timer_value = double.PositiveInfinity;
+                foreach (double timer_value in this.timers.Values)
+                {
+                    if (timer_value < smallest_timer_value)
+                        smallest_timer_value = timer_value;
+                }
+                return Math.Min(this.events.getEarliestTime(), smallest_timer_value); 
+            }
+            return this.events.getEarliestTime();   
+        }
+
+        /// <summary>
+        /// Execute statechart
+        /// </summary>
+        /// <param name='delta'>
+        /// Time passed since last step.
+        /// </param>
+        public void step(double delta)
+        {
+            if (!this.active)
+                return;
+
+            this.events.decreaseTime(delta);
+
+            if (this.timers != null && this.timers.Count > 0)
+            {
+                var next_timers = new Dictionary<int,double>();
+                foreach(KeyValuePair<int,double> pair in this.timers)
+                {
+                    double new_time = pair.Value - delta;
+                    if (new_time <= 0.0)
+                        this.addEvent (new Event("_" + pair.Key + "after"), new_time);
+                    else
+                        next_timers[pair.Key] = new_time;
+                }
+                this.timers = next_timers;
+            }
+
+            this.microstep();
+            while (this.state_changed)
+                this.microstep();
+        }
+        
+        private void microstep ()
+        {
+            List<Event> due = this.events.popDueEvents();
+            if (due.Count == 0) {
+                this.transition ();   
+            } else {
+                foreach (Event e in due)
+                {
+                    this.transition(e);
+                }
+            }
+        }
+        
+        protected abstract void transition (Event e = null);
+        
+        public virtual void start ()
+        {
+            this.active = true;
+        }
+        
+    }
+}
+

+ 146 - 0
csharp_runtime/ThreadsControllerBase.cs

@@ -0,0 +1,146 @@
+using System;
+using System.Threading;
+using System.Collections.Generic;
+
+namespace sccdlib
+{
+    public class ThreadsControllerBase : ControllerBase
+    {
+        bool stop_thread = false;
+        bool keep_running;
+        Thread thread = null;
+        Mutex input_mutex = new Mutex(false);
+        Mutex stop_thread_mutex = new Mutex(false);
+        AutoResetEvent wait_handle = new AutoResetEvent(false);
+        DateTime last_recorded_time = DateTime.UtcNow;
+        
+        public ThreadsControllerBase (bool keep_running = true)
+            : base()
+        {          
+            this.keep_running = keep_running;
+            this.thread = new Thread (new ThreadStart (this.run));
+        }
+        
+        private void handleInput(double delta)
+        {
+            this.input_mutex.WaitOne(-1);
+            this.input_queue.decreaseTime(delta);
+            foreach(Event e in this.input_queue.popDueEvents())
+                this.broadcast (e);
+            this.input_mutex.ReleaseMutex();
+        }
+        
+        public override void start()
+        {
+            this.thread.Start ();
+        }
+    
+        public override void stop()
+        {
+            this.stop_thread_mutex.WaitOne(-1);
+            this.stop_thread = true;
+            this.stop_thread_mutex.ReleaseMutex ();
+            this.wait_handle.Set();
+        }
+        
+        
+        private double getWaitTime ()
+        {
+            this.input_mutex.WaitOne (-1);
+            double wait_time = Math.Min (this.object_manager.getWaitTime (), this.input_queue.getEarliestTime ());
+            this.input_mutex.ReleaseMutex ();
+    
+            if (double.IsPositiveInfinity (wait_time)) {
+                if (this.done) {
+                    this.done = false;
+                } else {
+                    this.done = true;
+                    return 0.0;
+                }
+            }
+            return wait_time;
+        }
+    
+        private void handleWaiting ()
+        {
+            double wait_time = this.getWaitTime ();
+            if (wait_time <= 0.0)
+                return;
+            if (double.IsPositiveInfinity(wait_time))
+            {
+                if (this.keep_running)
+                {
+                    this.wait_handle.WaitOne(-1); //Wait until signal
+                }
+                else
+                {
+                    this.stop_thread_mutex.WaitOne(-1);
+                    this.stop_thread = true;
+                    this.stop_thread_mutex.ReleaseMutex();
+                }
+            }
+            else if (wait_time != 0.0)
+            {
+                //Calculate how much wait time is left.
+                double actual_wait_time = (wait_time - DateTime.UtcNow.Subtract(this.last_recorded_time).TotalSeconds); //In seconds and double
+                if (actual_wait_time > 0.0)
+                {
+                    this.wait_handle.Reset();
+                    this.wait_handle.WaitOne((int)Math.Ceiling(actual_wait_time * 1000)); //Convert to seconds and int round up
+                }
+            }
+        }
+    
+        private void run()
+        {
+            this.last_recorded_time = DateTime.UtcNow;
+            base.start ();
+            DateTime previous_recorded_time;
+            double last_iteration_time = 0.0;
+
+            while (true)
+            {
+                this.handleInput(last_iteration_time);
+                //Compute the new state based on internal events
+                this.object_manager.stepAll(last_iteration_time);
+
+                this.handleWaiting();
+                
+                this.stop_thread_mutex.WaitOne (-1);
+                if (this.stop_thread) 
+                    break;
+                this.stop_thread_mutex.ReleaseMutex ();
+                
+                previous_recorded_time = this.last_recorded_time;
+                this.last_recorded_time = DateTime.UtcNow;
+                last_iteration_time = this.last_recorded_time.Subtract(previous_recorded_time).TotalSeconds;
+            }
+        }
+    
+        public void join()
+        {
+            this.thread.Join ();
+        }
+    
+        public override void addInput(Event input_event, double time_offset = 0.0)
+        {
+            this.input_mutex.WaitOne (-1);
+            base.addInput (input_event, time_offset); //TODO Add time to offset that has already passed, so that next subtraction evens it out? Also Gameloop then!
+            this.input_mutex.ReleaseMutex ();
+            this.wait_handle.Set();
+        }
+    
+        public override void addEventList(List<Tuple<Event,double>> event_list)
+        {
+            this.input_mutex.WaitOne (-1);
+            base.addEventList (event_list);
+            this.input_mutex.ReleaseMutex ();
+        }
+        
+        protected override IOutputListener createOutputListener (string[] ports)
+        {
+            return new ConcurrentOutputListener(ports);   
+        }
+    }
+}
+

+ 55 - 0
csharp_runtime/sccdlib.csproj

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>10.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{B4A57EE1-3C90-4B43-9ACA-43821CB35EA0}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>sccdlib</RootNamespace>
+    <AssemblyName>sccdlib</AssemblyName>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Event.cs" />
+    <Compile Include="ObjectManagerBase.cs" />
+    <Compile Include="InstanceWrapper.cs" />
+    <Compile Include="Association.cs" />
+    <Compile Include="OutputListener.cs" />
+    <Compile Include="ControllerBase.cs" />
+    <Compile Include="GameControllerBase.cs" />
+    <Compile Include="RuntimeClassBase.cs" />
+    <Compile Include="AssociationException.cs" />
+    <Compile Include="IOutputListener.cs" />
+    <Compile Include="ConcurrentOutputListener.cs" />
+    <Compile Include="AssociationReferenceException.cs" />
+    <Compile Include="RunTimeException.cs" />
+    <Compile Include="ParameterException.cs" />
+    <Compile Include="EventQueue.cs" />
+    <Compile Include="ThreadsControllerBase.cs" />
+    <Compile Include="InputException.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+</Project>

+ 50 - 0
csharp_runtime/sccdlib.sln

@@ -0,0 +1,50 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sccdlib", "sccdlib.csproj", "{B4A57EE1-3C90-4B43-9ACA-43821CB35EA0}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B4A57EE1-3C90-4B43-9ACA-43821CB35EA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B4A57EE1-3C90-4B43-9ACA-43821CB35EA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B4A57EE1-3C90-4B43-9ACA-43821CB35EA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B4A57EE1-3C90-4B43-9ACA-43821CB35EA0}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(MonoDevelopProperties) = preSolution
+		StartupItem = sccdlib.csproj
+		Policies = $0
+		$0.TextStylePolicy = $1
+		$1.inheritsSet = VisualStudio
+		$1.inheritsScope = text/plain
+		$1.scope = text/x-csharp
+		$0.CSharpFormattingPolicy = $2
+		$2.IndentSwitchBody = True
+		$2.AnonymousMethodBraceStyle = NextLine
+		$2.PropertyBraceStyle = NextLine
+		$2.PropertyGetBraceStyle = NextLine
+		$2.PropertySetBraceStyle = NextLine
+		$2.EventBraceStyle = NextLine
+		$2.EventAddBraceStyle = NextLine
+		$2.EventRemoveBraceStyle = NextLine
+		$2.StatementBraceStyle = NextLine
+		$2.ElseNewLinePlacement = NewLine
+		$2.CatchNewLinePlacement = NewLine
+		$2.FinallyNewLinePlacement = NewLine
+		$2.WhileNewLinePlacement = DoNotCare
+		$2.ArrayInitializerWrapping = DoNotChange
+		$2.ArrayInitializerBraceStyle = NextLine
+		$2.BeforeMethodDeclarationParentheses = False
+		$2.BeforeMethodCallParentheses = False
+		$2.BeforeConstructorDeclarationParentheses = False
+		$2.BeforeDelegateDeclarationParentheses = False
+		$2.NewParentheses = False
+		$2.SpacesBeforeBrackets = False
+		$2.inheritsSet = Mono
+		$2.inheritsScope = text/x-csharp
+		$2.scope = text/x-csharp
+	EndGlobalSection
+EndGlobal

+ 41 - 0
csharp_sccd_compiler/Action.cs

@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Xml.Linq;
+
+
+namespace csharp_sccd_compiler
+{
+    public class Action : Visitable
+    {
+        public List<SubAction> sub_actions { get; private set; }
+
+        public Action(XElement xml)
+        {
+            this.sub_actions = new List<SubAction>();
+            foreach (XElement sub_action_xml in xml.Elements())
+            {
+                SubAction sub_action = null;
+                if (sub_action_xml.Name == "raise")
+                    sub_action = new RaiseEvent(sub_action_xml);
+                else if (sub_action_xml.Name == "script")
+                    sub_action = new Script(sub_action_xml);
+                else if (sub_action_xml.Name == "log")
+                    sub_action = new Log(sub_action_xml);
+                else if (sub_action_xml.Name == "assign")
+                    sub_action = new Assign(sub_action_xml);
+                else if (sub_action_xml.Name != "parameter")      
+                    throw new CompilerException(string.Format("Invalid subaction <{0}>.", sub_action_xml.Name));
+
+                if (sub_action != null)
+                    this.sub_actions.Add(sub_action);
+            }
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            foreach (SubAction sub_action in this.sub_actions)
+                sub_action.accept(visitor);
+        }
+    }
+}
+

+ 96 - 0
csharp_sccd_compiler/Association.cs

@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+
+namespace csharp_sccd_compiler
+{
+    public class Association : Visitable
+    {
+        /// <summary>
+        /// Minimum cardinality of the association.
+        /// </summary>
+        public int min { get; private set; }
+        /// <summary>
+        /// Maximum cardinality of the association.
+        /// </summary>
+        /// <value>N is represented as -1.</value>
+        public int max { get; private set; }
+
+        public string to_class { get; private set; } // TODO perhaps try to replace the string by the actual class with a visitor? That's an extra error check.
+
+        public string name { get; private set; }
+
+        public Association(XElement xml)
+        {
+            XAttribute class_name_attribute = xml.Attribute("class");
+            if (class_name_attribute == null)
+                throw new CompilerException("Association missing class attribute.");
+            this.to_class = class_name_attribute.Value.Trim();
+            if (this.to_class == "")
+                throw new CompilerException("Association has empty class attribute.");
+
+            if (Constants.Reserved.Contains(this.to_class))
+                throw new CompilerException(string.Format("Reserved word '{0}' used as class attribute for association.", this.to_class));
+
+            XAttribute min_card_attribute = xml.Attribute("min");
+            if (min_card_attribute == null)
+                this.min = 0; //default value
+            else
+            {
+                try
+                {
+                    this.min = Convert.ToInt32(min_card_attribute.Value);
+                    if(this.min < 0)
+                        throw new FormatException();            
+                }
+                catch(FormatException)
+                {
+                    throw new CompilerException("Faulty minimum cardinality value in association.");
+                }
+                catch(OverflowException)
+                {
+                    throw new CompilerException("Minimum cardinality of association is too large.");
+                }
+            }
+
+            XAttribute max_card_attribute = xml.Attribute("max");
+            if (max_card_attribute == null)
+                this.max = -1; //default value TODO:use maxvalue?
+            else
+            {
+                try
+                {
+                    this.max = Convert.ToInt32(max_card_attribute.Value);
+                    if(this.max < this.min)
+                        throw new FormatException();                 
+                }
+                catch(FormatException)
+                {
+                    throw new CompilerException("Faulty maximum cardinality value in association.");
+                }
+                catch(OverflowException)
+                {
+                    throw new CompilerException("Maximum cardinality of association is too large.");
+                }
+            }
+
+            XAttribute association_name_attribute = xml.Attribute("name");
+            if (association_name_attribute == null)
+                throw new CompilerException("Association missing name attribute.");
+            this.name = association_name_attribute.Value.Trim();
+            if (this.name == "")
+                throw new CompilerException("Associaion has empty name attribute.");
+
+            if (Constants.Reserved.Contains(this.name))
+                throw new CompilerException(string.Format("Reserved word '{0}' used as class attribute for association.", this.name));
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 45 - 0
csharp_sccd_compiler/Attribute.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class Attribute : Visitable
+    {
+        public string name { get; private set; }
+        public string type { get; private set; }
+        public string init_value { get; private set; }
+
+        public Attribute(XElement xml)
+        {
+            XAttribute name_attribute = xml.Attribute("name");
+            if (name_attribute == null)
+                throw new CompilerException("Missing attribute name.");
+            this.name = name_attribute.Value.Trim();
+            if (this.name == "")
+                throw new CompilerException("Empty attribute name.");
+            if (Constants.Reserved.Contains(this.name))
+                throw new CompilerException(string.Format("Reserved word '{0}' used as attribute name.", this.name));
+
+            XAttribute type_attribute = xml.Attribute("type");
+            if (type_attribute == null)
+                throw new CompilerException("Missing attribute type.");
+            this.type = type_attribute.Value.Trim();
+            if (this.type == "")
+                throw new CompilerException("Empty attribute type.");
+
+            XAttribute init_attribute = xml.Attribute("init-value");
+            if (init_attribute == null || init_attribute.Value == "")
+                this.init_value = null;
+            else
+                this.init_value = init_attribute.Value;
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 104 - 0
csharp_sccd_compiler/Class.cs

@@ -0,0 +1,104 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class Class : Visitable
+    {
+        public string name { get; private set; }
+        public bool is_default { get; private set; }
+
+        public List<Constructor> constructors { get; private set; }
+        public List<Destructor> destructors { get; private set; }
+        public List<Method> methods { get; private set; }
+        public List<Attribute> attributes { get; private set; }
+        public List<Association> associations { get; private set; }
+
+        public StateChart statechart { get; private set; }
+        public string super_class { get; private set; }
+
+        public Class(XElement xml)
+        {
+            this.name = xml.Attribute("name").Value;
+            XAttribute default_attribute = xml.Attribute("default");
+            if (default_attribute != null && default_attribute.Value.ToLower() == "true")
+            {
+                this.is_default = true;
+            }
+            else
+            {
+                this.is_default = false;
+            }
+            this.attributes = new List<Attribute>();
+            foreach(XElement attribute_xml in xml.Elements("attribute"))
+            {
+                this.attributes.Add(new Attribute(attribute_xml));
+            }
+
+            this.methods = new List<Method>();
+            this.constructors = new List<Constructor>();
+            this.destructors = new List<Destructor>();
+            foreach(XElement method_xml in xml.Elements("method"))
+            {
+                this.processMethod(method_xml);
+            }
+
+            if (this.destructors.Count > 1)
+                throw new CompilerException("Multiple destructors defined.");
+
+            if (this.constructors.Count == 0)
+                this.constructors.Add(new Constructor(this.name));
+
+
+            var associations = new List<XElement>();
+            var inheritances = new List<XElement>();
+            foreach (XElement relationships_xml in xml.Elements("relationships"))
+            {
+                associations.AddRange(relationships_xml.Elements("association"));
+                inheritances.AddRange(relationships_xml.Elements("inheritance"));
+            }
+
+            this.associations = new List<Association>();
+            foreach( XElement association_xml in associations)
+                this.associations.Add(new Association(association_xml));
+
+            if(inheritances.Count > 1)
+                throw new CompilerException("Multiple inheritance detected which is not supported.");
+            if (inheritances.Count == 1)
+                this.super_class = inheritances[0].Attribute("class").Value;
+            else
+                this.super_class = null;
+
+            XElement[] statecharts = xml.Elements("scxml").ToArray();
+            if (statecharts.Length > 1)
+                throw new CompilerException("Multiple statecharts found.");
+            if (statecharts.Length == 1)
+                this.statechart = new StateChart(statecharts[0]);
+        }
+
+        private void processMethod(XElement method_xml)
+        {
+            XAttribute method_name_attribute = method_xml.Attribute("name");
+            if (method_name_attribute == null)
+                throw new CompilerException("Missing method name.");
+            string method_name = method_name_attribute.Value;
+            if (method_name == "")
+                throw new CompilerException("Empty method name.");
+            if (Constants.Reserved.Contains(method_name))
+                throw new CompilerException(string.Format("Reserved word '{0}' used as method name.", method_name));
+            if (method_name == this.name)
+                this.constructors.Add(new Constructor(method_xml));
+            else if (method_name == string.Concat("~",this.name))
+                this.destructors.Add(new Destructor(method_xml));
+            else
+                this.methods.Add(new Method(method_xml));
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}

+ 132 - 0
csharp_sccd_compiler/ClassDiagram.cs

@@ -0,0 +1,132 @@
+using System;
+using System.Linq;
+using System.Xml.Linq;
+using System.Collections.Generic;
+
+namespace csharp_sccd_compiler
+{
+	public class ClassDiagram : Visitable
+	{
+        public string model_name { get; private set; }
+
+        public string model_author { get; private set; }
+
+        public string model_description { get; private set; }
+
+        public List<string> class_names { get; private set; }
+
+        public List<string> inports { get; private set; }
+
+        public List<string> outports { get; private set; }
+
+        public string top_section { get; private set; }
+
+        public List<Class> classes { get; private set; }
+
+        public Class default_class { get; private set; }
+
+		public ClassDiagram (string input_file_path)
+        {
+            XElement root = XDocument.Load(input_file_path).Root;
+            XAttribute name_attribute = root.Attribute("name");
+            if (name_attribute != null && name_attribute.Value.Trim() != "")
+                this.model_name = name_attribute.Value.Trim();
+            XAttribute author_attribute = root.Attribute("author");
+            if (author_attribute != null && author_attribute.Value.Trim() != "")
+                this.model_author = author_attribute.Value.Trim();
+            XElement description_element = root.Element("description");
+            if (description_element != null && description_element.Value.Trim() != "")
+                model_description = description_element.Value;
+
+            this.class_names = new List<string>();
+			foreach (XElement class_xml in root.Elements("class"))
+            {
+                XAttribute class_name_attribute = class_xml.Attribute("name");
+                if (class_name_attribute == null)
+                    throw new CompilerException("Missing class name.");
+                string class_name = class_name_attribute.Value.Trim();
+                if (class_name == "")
+                    throw new CompilerException("Empty class name.");
+                if (this.class_names.Contains(class_name))
+                    throw new CompilerException(string.Format("Found 2 classes with the same name '{0}'.", class_name));
+                this.class_names.Add(class_name);
+            }
+
+            if (this.class_names.Count == 0)
+                throw new CompilerException("Found no classes to compile.");
+
+			this.inports = new List<string> ();
+            foreach (XElement inport_xml in root.Elements("inport"))
+            {
+                XAttribute inport_name_attribute = inport_xml.Attribute("name");
+                if (inport_name_attribute == null)
+                    throw new CompilerException("Missing inport name.");
+                string inport_name = inport_name_attribute.Value.Trim();
+                if (inport_name == "")
+                    throw new CompilerException("Empty inport name.");
+                if (this.inports.Contains(inport_name))
+                    throw new CompilerException(string.Format("Found 2 inports with the same name '{0}'.", inport_name));
+                this.inports.Add(inport_name);
+            }
+
+			this.outports = new List<string> ();
+            foreach (XElement outport_xml in root.Elements("outport"))
+            {
+                XAttribute outport_name_attribute = outport_xml.Attribute("name");
+                if (outport_name_attribute == null)
+                    throw new CompilerException("Missing outport name.");
+                string outport_name = outport_name_attribute.Value.Trim();
+                if (outport_name == "")
+                    throw new CompilerException("Empty outport name.");
+                if (this.outports.Contains(outport_name))
+                    throw new CompilerException(string.Format("Found 2 outports with the same name '{0}'.", outport_name));
+                this.outports.Add(outport_name);
+            }
+
+            List<XElement> top_elements = root.Elements("top").ToList();
+            if (top_elements.Count == 1 && top_elements[0].Value.Trim() != "")
+                this.top_section = top_elements[0].Value;
+            else if (top_elements.Count > 1)
+                throw new CompilerException("Class diagram can only have one <top> element.");
+
+            this.classes = new List<Class>(); 
+            List<Class> default_classes = new List<Class>(); 
+
+            foreach (XElement class_xml in root.Elements("class"))
+            {
+                Class processed_class = null;
+                try
+                {
+                    processed_class = new Class(class_xml);
+                }
+                catch(CompilerException e)
+                {
+                    throw new CompilerException(string.Format("Class <{0}> failed compilation.", class_xml.Attribute("name").Value), e);
+                }
+
+                Logger.displayInfo(string.Format("Class <{0}> has been successfully loaded.", processed_class.name));
+                this.classes.Add(processed_class);
+                if (processed_class.is_default)
+                    default_classes.Add(processed_class);
+            }
+
+            if (default_classes.Count != 1)
+            {
+                if (this.classes.Count == 1)
+                {
+                    Logger.displayInfo(string.Format("Only one class given. Using <{0}> as the default class.", this.classes[0].name));
+                    this.default_class = this.classes[0];
+                }
+                else
+                    throw new CompilerException("Provide one and only one default class to instantiate on start up.");
+            }
+            else
+                this.default_class = default_classes[0];
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+	}
+}

+ 890 - 0
csharp_sccd_compiler/Code Generation/CSharpGenerator.cs

@@ -0,0 +1,890 @@
+using System;
+using System.Linq;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace csharp_sccd_compiler
+{
+    public class CSharpGenerator : CodeGenerator
+    {
+
+        public CSharpGenerator() : base( new Platform[]{Platform.THREADS, Platform.GAMELOOP} )
+        {
+        }
+
+        public override void visit(ClassDiagram class_diagram)
+        {
+            this.output_file.write("/*");
+            this.output_file.indent();
+            this.output_file.write("Statecharts + Class Diagram compiler by Glenn De Jonghe");
+            this.output_file.write();
+            this.output_file.write(string.Format("Generated on {0}.", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
+            if  (class_diagram.model_name != null || class_diagram.model_author != null || class_diagram.model_description != null)
+                this.output_file.write();
+
+            if (class_diagram.model_name != null)
+                this.output_file.write("Model name:   " + class_diagram.model_name);
+            if (class_diagram.model_author != null)
+                this.output_file.write("Model author: " + class_diagram.model_author);
+
+            if (class_diagram.model_description != null)
+            {
+                this.output_file.write("Model description:");
+                this.output_file.write();
+                this.output_file.indent();
+                this.writeCorrectIndent(class_diagram.model_description);
+                this.output_file.dedent();
+            }
+            this.output_file.dedent();
+            this.output_file.write("*/");
+            this.output_file.write();
+            
+            //Use runtime libraries
+            this.output_file.write("using System;");
+            this.output_file.write("using System.Collections.Generic;");
+            this.output_file.write("using sccdlib;");
+
+            //Namespace using declarations by the user
+            if (class_diagram.top_section != null)
+                this.writeCorrectIndent(class_diagram.top_section);
+            this.output_file.write();
+            
+            //visit children
+            foreach (Class c in class_diagram.classes)
+                c.accept(this);
+             
+            //writing out ObjectManager
+            this.output_file.write("public class ObjectManager : ObjectManagerBase");
+            this.output_file.write("{");
+            this.output_file.indent();
+            this.output_file.write("public ObjectManager(ControllerBase controller): base(controller)");
+            this.output_file.write("{");
+            this.output_file.write("}");
+            this.output_file.write();
+            
+            this.output_file.write("protected override InstanceWrapper instantiate(string class_name, object[] construct_params)");
+            this.output_file.write("{");
+            this.output_file.indent();
+            this.output_file.write("RuntimeClassBase instance = null;");
+            this.output_file.write("List<Association> associations = new List<Association>();");
+            for (int index = 0; index < class_diagram.classes.Count; ++index)
+            {
+                if (index == 0)
+                    this.output_file.write();
+                else
+                    this.output_file.write("}else ");
+                this.output_file.extendWrite("if (class_name == \"" + class_diagram.classes[index].name + "\" ){");
+                this.output_file.indent();
+                this.output_file.write("object[] new_parameters = new object[construct_params.Length + 1];");
+                this.output_file.write("new_parameters[0] = this.controller;");
+                this.output_file.write("Array.Copy(construct_params, 0, new_parameters, 1, construct_params.Length);");
+                this.output_file.write("instance = (RuntimeClassBase) Activator.CreateInstance(typeof(" + class_diagram.classes[index].name + "), new_parameters);");
+                foreach (Association association in class_diagram.classes[index].associations)
+                    association.accept(this);
+                this.output_file.dedent();
+                if (index == class_diagram.classes.Count - 1)
+                    this.output_file.write("}");
+            }
+            this.output_file.write("if (instance != null) {");
+            this.output_file.indent();
+            this.output_file.write("return new InstanceWrapper(instance, associations);");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write("return null;");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.dedent();
+            this.output_file.write("}");
+
+            //Write out controller
+            this.output_file.write();
+            string controller_sub_class = "";
+            if (this.current_platform == Platform.THREADS)
+                controller_sub_class = "ThreadsControllerBase";
+            else if (this.current_platform == Platform.GAMELOOP)
+                controller_sub_class = "GameLoopControllerBase";
+            this.output_file.write("public class Controller : " + controller_sub_class);
+            this.output_file.write("{");
+            this.output_file.indent();
+        
+            //Write out constructor(s)
+            if (class_diagram.default_class.constructors != null)
+                foreach (Constructor constructor in class_diagram.default_class.constructors)
+                    this.writeControllerConstructor(class_diagram, constructor.parameters);
+            else
+                this.writeControllerConstructor(class_diagram, new List<FormalParameter>());
+            
+            this.output_file.write("public static void Main()");
+            this.output_file.write("{");
+            this.output_file.indent();
+            this.output_file.write("Controller controller = new Controller();");
+            this.output_file.write("controller.start();");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            
+            this.output_file.dedent();
+            this.output_file.write("}");
+        }
+
+        /// <summary>
+        /// Helper method
+        /// </summary>
+        private void writeControllerConstructor(ClassDiagram class_diagram, List<FormalParameter> parameters)
+        {
+            this.output_file.write("public Controller(");
+            this.writeFormalParameters(parameters.Concat(new FormalParameter[]{new FormalParameter("keep_running", "bool", "true")}));
+            this.output_file.extendWrite(") : base(keep_running)");
+            this.output_file.write("{");
+            this.output_file.indent();
+            
+            foreach (string p in class_diagram.inports)
+                this.output_file.write("this.addInputPort(\"" + p + "\");");
+            foreach (string p in class_diagram.outports)
+                this.output_file.write("this.addOutputPort(\"" + p + "\");");
+            this.output_file.write("this.object_manager = new ObjectManager(this);");
+            string[] actual_parameters = (from parameter in parameters select parameter.name).ToArray();
+            this.output_file.write("this.object_manager.createInstance(\"" + class_diagram.default_class.name + "\", new object[]{" + string.Join(", ", actual_parameters) + "});");
+            this.output_file.dedent();
+            this.output_file.write("}");
+        }
+
+        /// <summary>
+        /// Generate code for Class construct
+        /// </summary>
+        public override void visit(Class class_node)
+        {
+            this.output_file.write();
+            this.output_file.write("public class " + class_node.name);
+            // Take care of inheritance
+            if (class_node.super_class != null)
+                this.output_file.extendWrite(" : " + class_node.super_class);
+            else
+                this.output_file.extendWrite(" : " + "RuntimeClassBase");
+            this.output_file.write("{");
+            this.output_file.indent();
+            this.output_file.write();
+            
+            if (class_node.statechart != null)
+            {
+                //assign each node a unique ID
+                this.output_file.write("/// <summary>");
+                this.output_file.write("/// Enum uniquely representing all statechart nodes.");
+                this.output_file.write("/// </summary>");
+                this.output_file.write("public enum Node {");
+                this.output_file.indent();
+                foreach( StateChartNode node in class_node.statechart.composites.Concat(class_node.statechart.basics))
+                    this.output_file.write(node.full_name + ",");
+                this.output_file.dedent();
+                this.output_file.write("};");
+                this.output_file.write();
+                this.output_file.write("Dictionary<Node,List<Node>> current_state = new Dictionary<Node,List<Node>>();");
+                if (class_node.statechart.histories.Count > 0)
+                    this.output_file.write("Dictionary<Node,List<Node>> history_state = new Dictionary<Node,List<Node>>();");
+                this.output_file.write();
+            }
+
+            //User defined attributes
+            if (class_node.attributes.Count > 0)
+            {
+                this.output_file.write("//User defined attributes");
+                foreach (Attribute attribute in class_node.attributes)
+                {
+                    this.output_file.write(attribute.type + " " + attribute.name);
+                    if (attribute.init_value != null)
+                        this.output_file.extendWrite(" = " + attribute.init_value);
+                    this.output_file.extendWrite(";");     
+                }
+                this.output_file.write();
+            }
+
+            if (class_node.statechart != null)
+            {
+                this.output_file.write("/// <summary>");
+                this.output_file.write("/// Constructor part that is common for all constructors.");
+                this.output_file.write("/// </summary>");
+                this.output_file.write("private void commonConstructor(ControllerBase controller = null)");
+                this.output_file.write("{");
+                this.output_file.indent(); 
+                this.output_file.write("this.controller = controller;");
+                this.output_file.write("this.object_manager = controller.getObjectManager();");
+                if (class_node.statechart.nr_of_after_transitions != 0)
+                    this.output_file.write("this.timers = new Dictionary<int,double>();");
+
+                this.output_file.write();
+                this.output_file.write("//Initialize statechart :");
+                this.output_file.write();
+
+                if (class_node.statechart.histories.Count > 0)
+                {
+                    foreach (StateChartNode node in class_node.statechart.combined_history_parents)
+                    {
+                        this.output_file.write("this.history_state[Node." + node.full_name + "] = new List<Node>();");
+                    }
+                    this.output_file.write();
+                }
+
+                foreach (StateChartNode node in class_node.statechart.composites)
+                    this.output_file.write("this.current_state[Node." + node.full_name + "] = new List<Node>();");
+            }
+
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+            
+            this.output_file.write("public override void start()");
+            this.output_file.write("{");
+            
+            this.output_file.indent();
+            this.output_file.write("base.start();");
+            foreach (StateChartNode default_node in class_node.statechart.root.defaults)
+            {
+                if (default_node.is_composite)
+                    this.output_file.write("this.enterDefault_" + default_node.full_name + "();");
+                else if (default_node.is_basic)
+                    this.output_file.write("this.enter_" + default_node.full_name + "();");
+            }
+
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+            
+            //visit children
+            foreach( var i in class_node.constructors)
+                i.accept(this);
+            foreach( var i in class_node.destructors)
+                i.accept(this);
+            foreach( var i in class_node.methods)
+                i.accept(this);
+            if (class_node.statechart != null)
+                class_node.statechart.accept(this);
+              
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+        }
+
+        /// <summary>
+        /// Helper method that writes a correct comma separated list of formal parameters.
+        /// </summary>
+        private void writeFormalParameters(IEnumerable<FormalParameter> parameters)
+        {
+            bool first = true;       
+            foreach (FormalParameter param in parameters)
+            {
+                if (first)
+                    first = false;
+                else
+                    this.output_file.extendWrite(", ");
+                param.accept(this);
+            }
+        }
+            
+        public override void visit(FormalParameter formal_parameter)
+        {
+            this.output_file.extendWrite(formal_parameter.type + " " + formal_parameter.name);
+            if (formal_parameter.default_value != null)
+                this.output_file.extendWrite(" = " + formal_parameter.default_value);
+        }
+                        
+        public override void visit(Constructor constructor)
+        {
+            this.output_file.write(constructor.access + " " + constructor.name + "(");
+            this.writeFormalParameters(new FormalParameter[]{new FormalParameter("controller", "ControllerBase", null)}.Concat(constructor.parameters));
+            this.output_file.extendWrite(")");
+            this.output_file.write("{");
+            this.output_file.indent();
+            this.output_file.write("this.commonConstructor(controller);");
+            if (constructor.body != null && constructor.body.Trim() != "")
+            {
+                this.output_file.write();
+                this.output_file.write("//constructor body (user-defined)");
+                this.writeCorrectIndent(constructor.body);
+            }
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+        }
+            
+        public override void visit(Destructor destructor)
+        {
+            this.output_file.write(destructor.name + "()");
+            this.output_file.write("{");
+            if (destructor.body != null)
+            {
+                this.output_file.indent();
+                this.writeCorrectIndent(destructor.body);
+                this.output_file.dedent();
+            }
+            this.output_file.write("}");
+            this.output_file.write();
+        }
+            
+        public override void visit(Method method)
+        {
+            this.output_file.write(method.access + " " + method.return_type + " " + method.name + "(");
+            this.writeFormalParameters(method.parameters);
+            this.output_file.extendWrite(")");
+            this.output_file.write("{");
+            this.output_file.indent();
+            if (method.body != null)
+            {
+                this.output_file.indent();
+                this.writeCorrectIndent(method.body);
+                this.output_file.dedent();
+            }
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+        }
+
+        public override void visit(Association association)
+        {
+            this.output_file.write("associations.Add(new Association(\"" + association.name + "\", \"" + association.to_class + "\", " + association.min.ToString() + ", " + association.max.ToString() + "));");
+        }
+
+        /// <summary>
+        /// Helper method that writes the transitions recursively.
+        /// </summary>
+        public void writeTransitionsRecursively(StateChartNode current_node)
+        {
+            this.output_file.write("private bool transition_" + current_node.full_name + "(Event e)");
+            this.output_file.write("{");
+            this.output_file.indent();
+            
+            List<StateChartNode> valid_children = new List<StateChartNode>();
+            foreach (StateChartNode child in current_node.children)
+            {
+                if (child.is_composite || child.is_basic)
+                    valid_children.Add(child);
+            }
+             
+            this.output_file.write("bool catched = false;");
+            bool do_dedent = false;
+            if (current_node.solves_conflict_outer)
+            {
+                this.writeFromTransitions(current_node);
+                if (current_node.is_parallel || current_node.is_composite)
+                {
+                    this.output_file.write("if (!catched){");
+                    this.output_file.indent();
+                    do_dedent = true;
+                }
+            }
+                
+            if (current_node.is_parallel)
+            {
+                foreach (StateChartNode child in valid_children) 
+                    this.output_file.write("catched = this.transition_" + child.full_name + "(e) || catched;");
+            }
+            else if (current_node.is_composite)
+            {
+                this.output_file.write();
+                for (int i=0; i < valid_children.Count; ++i)
+                {
+                    if (i > 0)
+                        this.output_file.extendWrite(" else ");
+                    this.output_file.extendWrite("if (this.current_state[Node." + current_node.full_name + "][0] == Node." + valid_children[i].full_name + "){");
+                    this.output_file.indent();
+                    this.output_file.write("catched = this.transition_" + valid_children[i].full_name + "(e);");
+                    this.output_file.dedent();
+                    this.output_file.write("}");
+                }
+            }   
+            if (current_node.solves_conflict_outer)
+            {
+                if (do_dedent)
+                {
+                    this.output_file.dedent();
+                    this.output_file.write("}");
+                }
+            }
+            else if (current_node.transitions.Count > 0)
+            {
+                this.output_file.write("if (!catched) {");
+                this.output_file.indent();
+                this.writeFromTransitions(current_node);
+                this.output_file.dedent();
+                this.output_file.write("}");
+            }
+                
+            this.output_file.write("return catched;");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+            
+            foreach (StateChartNode child in valid_children)
+                this.writeTransitionsRecursively(child);
+        }
+                    
+        /// <summary>
+        /// Helper method
+        /// </summary>
+        private void writeFromTransitions(StateChartNode current_node)
+        {
+            if (current_node.transitions.Count == 0)
+                return;
+            
+            this.output_file.write("List<int> enableds = new List<int>();");
+            for (int index=0; index < current_node.transitions.Count; ++index)
+                this.writeTransitionCondition(current_node.transitions[index], index);
+                
+            this.output_file.write("if (enableds.Count > 1){");
+            this.output_file.indent();
+            this.output_file.write("Console.WriteLine(\"Runtime warning : indeterminism detected in a transition from node " +  current_node.full_name + ". Only the first in document order enabled transition is executed.\");");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write("if (enableds.Count > 0){");
+            this.output_file.indent();
+            this.output_file.write("int enabled = enableds[0];");
+            this.output_file.write();
+                  
+            for (int index=0; index < current_node.transitions.Count; ++index)
+                this.writeTransitionAction(current_node.transitions[index], index);
+            
+            this.output_file.write("catched = true;");   
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+        }
+            
+        public override void visit( FormalEventParameter formal_event_parameter)
+        {
+            this.output_file.extendWrite(formal_event_parameter.type + " " + formal_event_parameter.name);
+        }
+            
+        /// <summary>
+        /// Helper method
+        /// </summary>
+        private void writeFormalEventParameters(StateChartTransition transition)
+        {
+            if (transition.trigger.parameters.Count > 0)
+            {
+                this.output_file.write("object[] parameters = e.getParameters();");
+                for (int index=0; index < transition.trigger.parameters.Count; ++index)
+                {
+                    this.output_file.write();
+                    transition.trigger.parameters[index].accept(this);
+                    this.output_file.extendWrite(" = (" + transition.trigger.parameters[index].type + ")parameters[" + index.ToString() + "];");
+                }
+            }
+        }
+
+        ///
+        private void writeTransitionAction(StateChartTransition transition, int index)
+        {
+            if (index > 1)
+                this.output_file.extendWrite(" else ");
+            else
+                this.output_file.write();
+            this.output_file.extendWrite("if (enabled == " + index.ToString() + "){");
+            this.output_file.indent();
+
+            //Handle parameters to actually use them             
+            this.writeFormalEventParameters(transition);
+            
+            //Write out exit actions
+            StateChartNode last_exit_node = transition.exit_nodes[transition.exit_nodes.Count - 1];
+            if (!last_exit_node.is_basic)
+                this.output_file.write("this.exit_" + last_exit_node.full_name + "();");
+            else
+            {
+                foreach (StateChartNode node in transition.exit_nodes)
+                {
+                    if (node.is_basic)
+                        this.output_file.write("this.exit_" + node.full_name + "();");
+                }
+            }
+
+            //Write out trigger actions
+            transition.action.accept(this);
+            
+            foreach (Tuple<StateChartNode,bool> enter_node_tuple in transition.enter_nodes)
+            {
+                StateChartNode entering_node = enter_node_tuple.Item1;
+                if (enter_node_tuple.Item2)
+                {
+                    if (entering_node.is_composite)
+                        this.output_file.write("this.enterDefault_" + entering_node.full_name + "();");
+                    else if (entering_node.is_history)
+                    {
+                        if (entering_node.is_history_deep)
+                            this.output_file.write("this.enterHistoryDeep_" + entering_node.parent.full_name + "();");
+                        else
+                            this.output_file.write("this.enterHistoryShallow_" + entering_node.parent.full_name + "();");
+                    }
+                    else
+                        this.output_file.write("this.enter_" + entering_node.full_name + "();");
+                }
+                else
+                {
+                    if (entering_node.is_composite)
+                        this.output_file.write("this.enter_" + entering_node.full_name + "();");
+                }
+            }
+            this.output_file.dedent();
+            this.output_file.write("}");
+        }
+                            
+        private void writeTransitionCondition(StateChartTransition transition, int index)
+        {
+            if (!transition.trigger.is_uc)
+            {
+                this.output_file.write("if (e.getName() == \"" + transition.trigger.event_name + "\" && e.getPort() == \"" + transition.trigger.port + "\"){");
+                this.output_file.indent();   
+            }
+            //Evaluate guard
+            if (transition.guard != null)
+            {
+                //Handle parameters for guard evaluation       
+                this.writeFormalEventParameters(transition);  
+
+                this.output_file.write("if (");
+                transition.guard.accept(this);
+                this.output_file.extendWrite("){");
+                this.output_file.indent();    
+            }
+            this.output_file.write("enableds.Add(" + index.ToString() + ");");
+
+            if (transition.guard != null)
+            {
+                this.output_file.dedent();
+                this.output_file.write("}");
+            }
+            if (!transition.trigger.is_uc)
+            {
+                this.output_file.dedent();
+                this.output_file.write("}");
+            }
+            this.output_file.write();
+        }
+        
+        public override void visit(EnterAction enter_method)
+        {
+            this.output_file.write("private void enter_" + enter_method.parent.full_name + "()");
+            this.output_file.write("{");
+            this.output_file.indent();
+            
+            //Take care of any AFTER events
+            foreach (StateChartTransition transition in enter_method.parent.transitions)
+            {
+                if (transition.trigger.is_after)
+                {
+                    this.output_file.write("this.timers[" + transition.trigger.after_index.ToString() + "] = ");
+                    transition.trigger.after_expression.accept(this);
+                    this.output_file.extendWrite(";");
+                }
+            }
+            if (enter_method.action != null)
+                enter_method.action.accept(this);
+            this.output_file.write("this.current_state[Node." + enter_method.parent.parent.full_name + "].Add(Node." + enter_method.parent.full_name + ");");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+        }
+
+        private void writeEnterDefault(StateChartNode entered_node)
+        {
+            this.output_file.write("private void enterDefault_" + entered_node.full_name + "()");
+            this.output_file.write("{");
+            this.output_file.indent();
+            this.output_file.write("this.enter_" + entered_node.full_name + "();");
+            if (entered_node.is_composite)
+            {
+                foreach(StateChartNode default_node in entered_node.defaults)
+                {
+                    if (default_node.is_composite)
+                        this.output_file.write("this.enterDefault_" + default_node.full_name + "();");
+                    else if (default_node.is_basic)
+                        this.output_file.write("this.enter_" + default_node.full_name + "();");
+                }
+            }
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+        }
+             
+        public override void visit(ExitAction exit_method)
+        {
+            this.output_file.write("private void exit_" + exit_method.parent.full_name + "()");
+            this.output_file.write("{");
+            this.output_file.indent();
+            //If the exited node is composite take care of potential history and the leaving of descendants
+            if (exit_method.parent.is_composite)
+            {
+                //handle history
+                if (exit_method.parent.save_state_on_exit)
+                    this.output_file.write("this.history_state[Node." + exit_method.parent.full_name + "].AddRange(this.current_state[Node." + exit_method.parent.full_name + "]);");
+                
+                //Take care of leaving children
+                if (exit_method.parent.is_parallel)
+                {
+                    foreach(StateChartNode child in exit_method.parent.children)
+                    {
+                        if (!child.is_history)
+                            this.output_file.write("this.exit_" + child.full_name + "();");
+                    }
+                }
+                else
+                {
+                    foreach(StateChartNode child in exit_method.parent.children)
+                    {
+                        if (!child.is_history)
+                        {
+                            this.output_file.write("if (this.current_state[Node." + exit_method.parent.full_name + "].Contains(Node." + child.full_name + ")){");
+                            this.output_file.indent();
+                            this.output_file.write("this.exit_" + child.full_name + "();");
+                            this.output_file.dedent();
+                            this.output_file.write("}");
+                        }
+                    }
+                }
+            }
+
+            //Take care of any AFTER events
+            foreach (StateChartTransition transition in exit_method.parent.transitions)
+            {
+                if (transition.trigger.is_after)
+                    this.output_file.write("this.timers.Remove(" + transition.trigger.after_index.ToString() + ");");
+            } 
+
+            //Execute user-defined exit action if present
+            if (exit_method.action != null)
+                exit_method.action.accept(this);
+                
+            //Adjust state
+            this.output_file.write("this.current_state[Node." + exit_method.parent.parent.full_name + "].Remove(Node." + exit_method.parent.full_name + ");");
+
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+        }
+           
+        private void writeEnterHistory(StateChartNode entered_node, bool is_deep)
+        {
+            this.output_file.write("private void enterHistory");
+            if (is_deep)
+                this.output_file.extendWrite("Deep");
+            else
+                this.output_file.extendWrite("Shallow");
+            this.output_file.extendWrite("_" + entered_node.full_name + "()");
+            this.output_file.write("{");
+            this.output_file.indent();
+            this.output_file.write("if (this.history_state[Node." + entered_node.full_name + "].Count == 0){");
+            this.output_file.indent();
+
+            foreach (StateChartNode node in entered_node.defaults)
+            {
+                if (node.is_basic)
+                    this.output_file.write("this.enter_" + node.full_name + "();");
+                else if (node.is_composite)
+                    this.output_file.write("this.enterDefault_" + node.full_name + "();");
+            }
+
+            this.output_file.dedent();
+            this.output_file.write("} else {");
+            this.output_file.indent();
+
+            if (entered_node.is_parallel)
+            {
+                foreach (StateChartNode child in entered_node.children)
+                {
+                    if (!child.is_history)
+                    {
+                        this.output_file.write("this.enterHistory");
+                        if (is_deep)
+                            this.output_file.extendWrite("Deep");
+                        else
+                            this.output_file.extendWrite("Shallow");
+                        this.output_file.extendWrite("_" + child.full_name + "();");
+                    }
+                }
+            }
+            else
+            {
+                foreach (StateChartNode child in entered_node.children)
+                {
+                    if (!child.is_history)
+                    {
+                        this.output_file.write("if (this.history_state[Node." + entered_node.full_name + "].Contains(Node." + child.full_name + ")){");
+                        this.output_file.indent();
+                        if (child.is_composite)
+                        {
+                            if (is_deep)
+                            {
+                                this.output_file.write("this.enter_" + child.full_name + "();");
+                                this.output_file.write("this.enterHistoryDeep_" + child.full_name + "();");
+                            }
+                            else
+                                this.output_file.write("this.enterDefault_" + child.full_name + "();");
+                        }
+                        else
+                            this.output_file.write("this.enter_" + child.full_name + "();");
+                        this.output_file.dedent();
+                        this.output_file.write("}");
+                    }
+                }
+            }
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+        }
+
+        public override void visit(StateChart statechart)
+        {
+            this.output_file.write("//Statechart enter/exit action method(s) :");
+            this.output_file.write();
+            
+            //Visit enter and exit actions of children
+            foreach (StateChartNode node in statechart.composites.Concat(statechart.basics))
+            {
+                if (!object.ReferenceEquals(node, statechart.root))
+                {
+                    node.enter_action.accept(this);
+                    node.exit_action.accept(this);
+                }
+            }
+            //Write out statecharts methods for enter/exit state
+            if (statechart.composites.Count > 1)
+            {
+                this.output_file.write("//Statechart enter/exit default method(s) :");
+                this.output_file.write();
+                foreach (StateChartNode node in statechart.composites)
+                {
+                    if (!object.ReferenceEquals(node, statechart.root))
+                        this.writeEnterDefault(node);
+                }
+            }
+
+            //Write out statecharts methods for enter/exit history
+            if (statechart.histories.Count > 0)
+            {
+                this.output_file.write("//Statechart enter/exit history method(s) :");
+                this.output_file.write();
+                foreach (StateChartNode node in statechart.shallow_history_parents)
+                    this.writeEnterHistory(node, false);
+                foreach (StateChartNode node in statechart.deep_history_parents)
+                    this.writeEnterHistory(node, true);   
+            }
+            this.output_file.write("//Statechart transitions :");
+            this.output_file.write();
+            this.writeTransitionsRecursively(statechart.root);           
+                    
+            //Write out transition function
+            this.output_file.write("protected override void transition (Event e = null)");
+            this.output_file.write("{");
+            this.output_file.indent();
+            this.output_file.write("if (e == null) {");
+            this.output_file.indent();
+            this.output_file.write("e = new Event();");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write("this.state_changed = this.transition_" + statechart.root.full_name + "(e);");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+
+            //Write out inState function
+            this.output_file.write("public bool inState(List<Node> nodes)");
+            this.output_file.write("{");
+            this.output_file.indent();
+            this.output_file.write("foreach(List<Node> actives in current_state.Values){");
+            this.output_file.indent();
+            this.output_file.write("foreach(Node node in actives)");
+            this.output_file.indent();
+            this.output_file.write("nodes.Remove (node);");
+            this.output_file.dedent();
+            this.output_file.write("if (nodes.Count == 0){");
+            this.output_file.indent();
+            this.output_file.write("return true;");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write("return false;");
+            this.output_file.dedent();
+            this.output_file.write("}");
+            this.output_file.write();
+        }
+
+        public override void visit(ExpressionPartString expression_part_string)
+        {
+            this.output_file.extendWrite(expression_part_string.value);
+        }
+            
+        public override void visit(SelfReference self_reference)
+        {
+            this.output_file.extendWrite("this");
+        }
+            
+        public override void visit(StateReference state_ref)
+        {
+            this.output_file.extendWrite("new List<Node>() {");
+            this.output_file.extendWrite(string.Join(", ", (from node in state_ref.target_nodes select "Node." + node.full_name)));
+            this.output_file.extendWrite("}");
+        }
+            
+        public override void visit(InStateCall in_state_call)
+        {
+            this.output_file.extendWrite("this.inState(");
+            in_state_call.state_reference.accept(this);
+            this.output_file.extendWrite(")");
+        }
+            
+        public override void visit(RaiseEvent raise_event)
+        {
+            if (raise_event.scope == RaiseEvent.Scope.NARROW_SCOPE || raise_event.scope == RaiseEvent.Scope.BROAD_SCOPE)
+                this.output_file.write("Event send_event = new Event(\"" + raise_event.event_name + "\", \"\", new object[] {");
+            else if (raise_event.scope == RaiseEvent.Scope.LOCAL_SCOPE)
+                this.output_file.write("this.addEvent( new Event(\"" + raise_event.event_name + "\", \"\", new object[] {");
+            else if (raise_event.scope == RaiseEvent.Scope.OUTPUT_SCOPE)
+                this.output_file.write("this.controller.outputEvent(new Event(\"" + raise_event.event_name + "\", \"" + raise_event.port + "\", new object[] {");
+            else if (raise_event.scope == RaiseEvent.Scope.CD_SCOPE)
+                this.output_file.write("this.object_manager.addEvent(new Event(\"" + raise_event.event_name + "\", \"\", new object[] { this, ");
+
+            bool first_param = true;
+            foreach (Expression param in raise_event.parameters)
+            {
+                if (first_param)
+                    first_param = false;
+                else
+                    this.output_file.extendWrite(",");
+                param.accept(this);
+            }
+
+            if (raise_event.scope == RaiseEvent.Scope.NARROW_SCOPE)
+            {
+                this.output_file.extendWrite("});");
+                this.output_file.write("this.object_manager.addEvent(new Event(\"narrow_cast\", \"\", new object[] {this, \"" + raise_event.target + "\" ,send_event}));");
+            }
+            else if (raise_event.scope == RaiseEvent.Scope.BROAD_SCOPE)
+            {
+                this.output_file.extendWrite("});");
+                this.output_file.write("this.object_manager.addEvent(new Event(\"broad_cast\", \"\", new object[] {send_event}));");
+            }
+            else
+                this.output_file.extendWrite("}));");
+        }
+                
+        public override void visit(Script script)
+        {
+            this.writeCorrectIndent(script.code);
+        }
+            
+        public override void visit(Log log)
+        {
+            this.output_file.write("Console.WriteLine(\"" + log.message + "\");");
+        }
+            
+        public override void visit(Assign assign)
+        {
+            this.output_file.write();
+            assign.lvalue.accept(this);
+            this.output_file.extendWrite(" = ");
+            assign.expression.accept(this);
+            this.output_file.extendWrite(";");
+        }
+    }
+}
+

+ 89 - 0
csharp_sccd_compiler/Code Generation/CodeGenerator.cs

@@ -0,0 +1,89 @@
+using System;
+using System.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public abstract class CodeGenerator : Visitor
+    {
+        protected Platform current_platform;
+        protected Platform[] supported_platforms;
+        protected FileOutputer output_file;
+
+        public enum Platform {
+            THREADS,
+            GAMELOOP
+        };
+
+        private enum IndentType {
+            NOT_SET,
+            SPACES,
+            TABS
+        }
+
+        public CodeGenerator(Platform[] supported_platforms)
+        {
+            this.supported_platforms = supported_platforms;
+        }
+
+        public bool generate(ClassDiagram class_diagram, string output_file_path, Platform current_platform)
+        {
+            this.current_platform = current_platform;
+            if (! this.supported_platforms.Contains(this.current_platform))
+            {
+                Logger.displayError("Unsupported platform.");
+                return false;
+            }
+            try
+            {
+                this.output_file = new FileOutputer(output_file_path);
+                class_diagram.accept(this);
+            }
+            finally
+            {
+                this.output_file.close();
+            }
+            return true;
+        }
+
+        protected void writeCorrectIndent(string code)
+        {
+            string[] lines = code.Split('\n');
+
+            int begin_index = 0;
+            while (begin_index < lines.Length && lines[begin_index].Trim() == "")
+                begin_index += 1;
+
+            if (begin_index >= lines.Length)
+                return;
+
+            int end_index = lines.Length - 1;
+            while (end_index > begin_index && lines[end_index].Trim() == "")
+            {
+                end_index -= 1;
+            }
+
+            //first index where valid code is present
+            int to_strip_length = lines[begin_index].TrimEnd().Length - lines[begin_index].Trim().Length;
+            IndentType indent_type = IndentType.NOT_SET;
+
+            for(int index = begin_index; index <= end_index; ++index)
+            {
+				string strip_part = lines[index].Substring (0, to_strip_length);
+
+				if ((strip_part.Contains ('\t') && strip_part.Contains (' ')) ||
+					(indent_type == IndentType.SPACES && strip_part.Contains ('\t')) ||
+					(indent_type == IndentType.TABS && strip_part.Contains (' '))   
+                )
+					throw new CodeBlockException ("Mixed tab and space indentation!");
+
+				if (indent_type == IndentType.NOT_SET) {
+					if (strip_part.Contains (' '))
+						indent_type = IndentType.SPACES;
+					else if (strip_part.Contains ('\t'))
+						indent_type = IndentType.TABS;
+				}
+				this.output_file.write (lines[index].Substring (to_strip_length));
+            }
+        }
+    }
+}

+ 55 - 0
csharp_sccd_compiler/Code Generation/FileOutputer.cs

@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using System.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class FileOutputer
+    {
+        int             indent_level = 0;
+        int             nr_of_indent_chars = 4;
+        char            indent_char = ' ';
+        bool            first_write = true;
+        StreamWriter    output_file;
+
+        public FileOutputer(string output_file_path)
+        {
+            this.output_file = new StreamWriter(output_file_path, false);
+        }
+
+        public void write(string text = "")
+        {
+            if (this.first_write)
+            {
+                this.first_write = false;
+                this.output_file.Write(new String(this.indent_char, this.indent_level * this.nr_of_indent_chars) + text);
+            }
+            else
+            {
+                this.output_file.WriteLine();
+                this.output_file.Write(new String(this.indent_char, this.indent_level * this.nr_of_indent_chars) + text);
+            }
+        }
+
+        public void extendWrite(string text = "")
+        {
+            this.output_file.Write(text);            
+        }
+
+        public void indent()
+        {
+            this.indent_level += 1;
+        }
+
+        public void dedent()
+        {
+            this.indent_level -= 1;
+        }
+
+        public void close()
+        {
+            this.output_file.Close();
+        }
+    }
+}
+

+ 29 - 0
csharp_sccd_compiler/Compiler.cs

@@ -0,0 +1,29 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class Compiler
+    {
+
+        public static void generate(string input_file, string output_file, CodeGenerator.Platform platform)
+        {
+            ClassDiagram class_diagram = createAST(input_file);
+            generateFromAST(class_diagram, output_file, platform);
+        }
+              
+        public static ClassDiagram createAST(string input_file)
+        {
+            ClassDiagram cd = new ClassDiagram(input_file); //create AST
+            (new StateLinker()).visit(cd); //visitor fixing state references
+            (new PathCalculator()).visit(cd); //visitor calculating paths
+            return cd;
+        }
+            
+        public static void generateFromAST(ClassDiagram class_diagram, string output_file, CodeGenerator.Platform platform)
+        {
+            if ((new CSharpGenerator()).generate(class_diagram, output_file, platform))
+                Logger.displayInfo("The following classes <" + string.Join(", ", class_diagram.class_names) + "> have been exported to the following file: " + output_file);
+        }
+    }
+}
+

+ 17 - 0
csharp_sccd_compiler/Constants.cs

@@ -0,0 +1,17 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class Constants
+    {
+        /// <summary>
+        /// Reserved keywords.
+        /// </summary>
+        public static string[] Reserved = new string[]{};
+
+        public static string INSTATE_SEQ = "INSTATE";
+
+        public static string SELF_REFERENCE_SEQ = "SELF";
+    }
+}
+

+ 28 - 0
csharp_sccd_compiler/Constructor.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+
+namespace csharp_sccd_compiler
+{
+    public class Constructor : Method
+    {
+        public Constructor(XElement xml) : base(xml)
+        {
+        }
+
+        public Constructor(string class_name)
+        {
+            this.name = class_name;
+            this.access = "public";
+            this.parameters = new List<FormalParameter>();
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 21 - 0
csharp_sccd_compiler/Destructor.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+
+namespace csharp_sccd_compiler
+{
+    public class Destructor : Method
+    {
+        public Destructor(XElement xml) : base(xml)
+        {
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 51 - 0
csharp_sccd_compiler/EnterExitAction.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public abstract class EnterExitAction : Visitable
+    {
+        public StateChartNode parent { get; private set; }
+
+        public Action action { get; private set; }
+
+        public EnterExitAction(StateChartNode parent, XElement xml = null)
+        {
+            this.parent = parent;
+            if (xml != null)
+                this.action = new Action(xml);
+            else
+                this.action = null;
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+
+    public class EnterAction : EnterExitAction
+    {
+        public EnterAction(StateChartNode parent, XElement xml = null) : base(parent,xml)
+        {
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+
+    public class ExitAction : EnterExitAction
+    {
+        public ExitAction(StateChartNode parent, XElement xml = null) : base(parent,xml)
+        {
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 22 - 0
csharp_sccd_compiler/Exceptions/ActionException.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class ActionException : CompilerException
+    {
+        public ActionException ()
+        {
+        }
+
+        public ActionException(string message)
+            : base(message)
+        {
+        }
+
+        public ActionException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+}
+

+ 22 - 0
csharp_sccd_compiler/Exceptions/CodeBlockException.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class CodeBlockException : CompilerException
+    {
+        public CodeBlockException ()
+        {
+        }
+
+        public CodeBlockException(string message)
+            : base(message)
+        {
+        }
+
+        public CodeBlockException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+}
+

+ 22 - 0
csharp_sccd_compiler/Exceptions/CompilerException.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class CompilerException : Exception
+    {
+        public CompilerException ()
+        {
+        }
+
+        public CompilerException(string message)
+            : base(message)
+        {
+        }
+
+        public CompilerException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+}
+

+ 24 - 0
csharp_sccd_compiler/Exceptions/LexerException.cs

@@ -0,0 +1,24 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class LexerException : CompilerException
+    {
+        public LexerException ()
+        {
+        }
+
+        public LexerException(string message)
+            : base(message)
+        {
+        }
+
+        public LexerException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+}
+
+
+

+ 22 - 0
csharp_sccd_compiler/Exceptions/StateReferenceException.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class StateReferenceException : CompilerException
+    {
+        public StateReferenceException ()
+        {
+        }
+
+        public StateReferenceException(string message)
+            : base(message)
+        {
+        }
+
+        public StateReferenceException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+}
+

+ 22 - 0
csharp_sccd_compiler/Exceptions/TransitionException.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class TransitionException : CompilerException
+    {
+        public TransitionException ()
+        {
+        }
+
+        public TransitionException(string message)
+            : base(message)
+        {
+        }
+
+        public TransitionException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+}
+

+ 22 - 0
csharp_sccd_compiler/Exceptions/UnprocessedException.cs

@@ -0,0 +1,22 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class UnprocessedException : CompilerException
+    {
+		public UnprocessedException ()
+        {
+        }
+
+		public UnprocessedException(string message)
+            : base(message)
+        {
+        }
+
+		public UnprocessedException(string message, Exception inner)
+            : base(message, inner)
+        {
+        }
+    }
+}
+

+ 87 - 0
csharp_sccd_compiler/Expression/Expression.cs

@@ -0,0 +1,87 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class Expression : Visitable
+    {
+        private static Lexer lexer = new Lexer(false, true);
+
+        public List<ExpressionPart> expression_parts { get; private set; }
+
+        public Expression(string input_string)
+        {
+            if (input_string == "")
+                throw new CompilerException("Empty Expression.");
+            this.parse(input_string);
+        }
+
+        protected void parse(string input_string, string[] dont_parse = null)
+        {
+            this.expression_parts = new List<ExpressionPart>();
+            Expression.lexer.setInput(input_string);
+            string processed_bare_expression = "";
+            if (dont_parse == null)
+                dont_parse = new string[] { };
+
+            foreach (Token token in Expression.lexer.iterateTokens())
+            {
+                ExpressionPart created_part = null;
+
+                if (token.type == Token.Type.WORD)
+                {
+                    if (dont_parse.Contains(token.val))
+                        throw new CompilerException(string.Format("Macro \"{0}\" not allowed here.",token.val));
+                    else if (token.val == Constants.SELF_REFERENCE_SEQ)
+                        created_part = new SelfReference();
+                    else if (token.val == Constants.INSTATE_SEQ)
+                    {
+                        created_part = this.parseInStateCall();
+                        if (created_part == null)
+                            throw new CompilerException(string.Format("Illegal use of \"{0}\" macro.", Constants.INSTATE_SEQ));
+                    }
+                }
+
+                if (created_part == null)
+                    processed_bare_expression += token.val;
+                else
+                {
+                    if (processed_bare_expression != "")
+                    {
+                        this.expression_parts.Add( new ExpressionPartString(processed_bare_expression));
+                        processed_bare_expression = "";
+                    }
+                    this.expression_parts.Add(created_part);
+                }
+            }
+
+            //Process part of input after the last created macro object
+            if (processed_bare_expression != "")
+                this.expression_parts.Add( new ExpressionPartString(processed_bare_expression));
+        }
+
+        private InStateCall parseInStateCall()
+        {
+            Token token = Expression.lexer.nextToken();
+            if (token == null || token.type != Token.Type.LBRACKET)
+                return null;
+            token = Expression.lexer.nextToken();
+            if (token == null || token.type != Token.Type.QUOTED)
+                return null;
+            InStateCall result = new InStateCall(token.val.Substring(1, token.val.Length - 2));
+            token = Expression.lexer.nextToken();
+            if (token == null || token.type != Token.Type.RBRACKET)
+                return null;
+            return result;
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            foreach (ExpressionPart expression_part in this.expression_parts)
+                expression_part.accept(visitor);
+        }
+    }
+}
+

+ 12 - 0
csharp_sccd_compiler/Expression/ExpressionPart.cs

@@ -0,0 +1,12 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public abstract class ExpressionPart : Visitable
+    {
+        public ExpressionPart()
+        {
+        }
+    }
+}
+

+ 20 - 0
csharp_sccd_compiler/Expression/ExpressionPartString.cs

@@ -0,0 +1,20 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class ExpressionPartString : ExpressionPart
+    {
+        public string value { get; private set; }
+
+        public ExpressionPartString(string value)
+        {
+            this.value = value;
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 20 - 0
csharp_sccd_compiler/Expression/InStateCall.cs

@@ -0,0 +1,20 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+	public class InStateCall : ExpressionPart
+    {
+        public StateReference state_reference { get; private set; }
+
+        public InStateCall(string state_reference_string)
+        {
+            this.state_reference = new StateReference(state_reference_string);
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 12 - 0
csharp_sccd_compiler/Expression/LValue.cs

@@ -0,0 +1,12 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class LValue : Expression
+    {
+        public LValue(string input_string) : base(input_string)
+        {
+        }
+    }
+}
+

+ 17 - 0
csharp_sccd_compiler/Expression/SelfReference.cs

@@ -0,0 +1,17 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class SelfReference : ExpressionPart
+    {
+        public SelfReference()
+        {
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 38 - 0
csharp_sccd_compiler/FormalEventParameter.cs

@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class FormalEventParameter : Visitable
+    {
+        public string name { get; private set; }
+        public string type { get; private set; }
+
+        public FormalEventParameter(XElement xml)
+        {
+            //Parse "name" attribute
+            XAttribute name_attribute = xml.Attribute("name");
+            if (name_attribute == null)
+                throw new CompilerException("Missing name for formal event parameter.");
+            this.name = name_attribute.Value.Trim();
+            if (this.name == "")
+                throw new CompilerException("Empty name for formal event parameter.");
+
+            //Parse "type" attribute
+            XAttribute type_attribute = xml.Attribute("type");
+            if (type_attribute == null)
+                throw new CompilerException("Missing type for formal event parameter.");
+            this.type = type_attribute.Value.Trim();
+            if (this.type == "")
+                throw new CompilerException("Empty type for formal event parameter.");
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 56 - 0
csharp_sccd_compiler/FormalParameter.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+
+namespace csharp_sccd_compiler
+{
+    public class FormalParameter : Visitable
+    {
+        public string name { get; protected set; }
+        public string type { get; protected set; }
+        public string default_value { get; protected set; }
+
+        public FormalParameter(string name, string type, string default_value = null)
+        {
+            this.name = name;
+            this.type = type;
+            this.default_value = default_value;
+        }
+
+        public FormalParameter(XElement xml)
+        {
+            //Set name
+            XAttribute name_attribute = xml.Attribute("name");
+            if (name_attribute == null)
+                throw new CompilerException("Missing formal parameter name.");
+            this.name = name_attribute.Value.Trim();
+            if (this.name == "")
+                throw new CompilerException("Empty formal parameter name.");
+            if (Constants.Reserved.Contains(this.name))
+                throw new CompilerException(string.Format("Reserved word '{0}' used as formal parameter name.", this.name));
+
+            //Set type
+            XAttribute type_attribute = xml.Attribute("type");
+            if (type_attribute == null)
+                throw new CompilerException("Missing formal parameter type.");
+            this.type = type_attribute.Value.Trim();
+            if (this.type == "")
+                throw new CompilerException("Empty formal parameter type.");
+
+            //Set default value
+            XAttribute default_attribute = xml.Attribute("default");
+            if (default_attribute == null || default_attribute.Value.Trim() == "")
+                this.default_value = null;
+            else
+                this.default_value = default_attribute.Value.Trim();
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 161 - 0
csharp_sccd_compiler/Lexing/Lexer.cs

@@ -0,0 +1,161 @@
+using System;
+using System.Collections.Generic;
+
+namespace csharp_sccd_compiler
+{
+    public class Lexer
+    {
+        bool skip_white_space;
+        bool accept_unknown_tokens;
+        static Dictionary<char, Token.Type> single_rules = new Dictionary<char, Token.Type>{
+            { '/', Token.Type.SLASH },
+            { '(', Token.Type.LBRACKET },
+            { ')', Token.Type.RBRACKET },
+            { ',', Token.Type.COMMA },
+            { '.', Token.Type.DOT },
+        };
+
+        string buf;
+        int pos;
+
+        public Lexer( bool skip_white_space = true, bool accept_unknown_tokens = false)
+        {
+            this.accept_unknown_tokens = accept_unknown_tokens;
+            this.skip_white_space = skip_white_space;
+        }
+
+        /// <summary>
+        /// Initialize the lexer with a buffer as input.
+        /// </summary>
+        public void setInput(string buffer)
+        {
+            this.buf = buffer;
+            this.pos = 0;
+        }
+
+        /// <summary>
+        /// Return the next token (a Token object) found in the input buffer. None is returned if the end of the buffer was reached.
+        /// In case of a lexing error (the current chunk of the buffer matches no rule), a LexerException is raised.
+        /// </summary>
+        public Token nextToken()
+        {
+            if (this.skip_white_space)
+                this.skipWhiteSpace();
+            if (this.pos >= this.buf.Length)
+                return null;
+
+            char c = this.buf[this.pos]; //first char of next token
+
+            Token.Type result_type;
+            if (Lexer.single_rules.TryGetValue(c, out result_type)) //check if it is an operator
+            {
+                Token token = new Token(result_type, c.ToString(), this.pos);
+                this.pos += 1;
+                return token;
+            }
+            else //not an operator
+            {
+                if (this.isAlpha(c))
+                    return this.processWord();
+                else if (this.isDigit(c))
+                    return this.processNumber();
+                else if (c == '\'' || c == '"')
+                    return this.processQuote();
+                else if (this.isWhiteSpace(c))
+                    return this.processWhiteSpace();
+            }
+            //if we're here, no rule matched
+            if (this.accept_unknown_tokens)
+            {
+                Token token = new Token(Token.Type.UNKNOWN, c.ToString(), this.pos);
+                this.pos += 1;
+                return token;
+            }
+            throw new LexerException(string.Format("Invalid character at position {0}.", this.pos));
+        }
+
+        public IEnumerable<Token> iterateTokens()
+        {
+            while (true)
+            {
+                Token tok = this.nextToken();
+                if (tok == null)
+                    break;
+                yield return tok;
+            }
+        }
+
+        private void skipWhiteSpace()
+        {
+            while (this.pos < this.buf.Length)
+            {
+                if (this.isWhiteSpace(this.buf[this.pos]))
+                    this.pos += 1;
+                else
+                    break; 
+            }
+        }
+
+        private bool isWhiteSpace(char c)
+        {
+            return c == ' ' || c == '\t' || c == '\r' || c == '\n';
+        }
+
+        private bool isAlpha(char c)
+        {
+            return char.IsLetter(c) || c == '_';
+        }
+
+        private bool isDigit(char c)
+        {
+            return char.IsDigit(c);
+        }
+
+        private bool isAlphaNum(char c)
+        {
+            return this.isAlpha(c) || this.isDigit(c);
+        }
+
+        private Token processWhiteSpace()
+        {
+            int nextpos = this.pos + 1;
+            while ( nextpos < this.buf.Length && this.isWhiteSpace(this.buf[nextpos]))
+                nextpos += 1;
+            Token token = new Token(Token.Type.WHITESPACE, this.buf.Substring(this.pos, nextpos-this.pos), this.pos);
+            this.pos = nextpos;
+            return token;
+        }
+
+        private Token processNumber()
+        {
+            int nextpos = this.pos + 1;
+            while ( nextpos < this.buf.Length && this.isDigit(this.buf[nextpos]))
+                nextpos += 1;
+            Token token = new Token(Token.Type.NUMBER, this.buf.Substring(this.pos, nextpos-this.pos), this.pos);
+            this.pos = nextpos;
+            return token;
+        }
+
+        private Token processWord()
+        {
+            int nextpos = this.pos + 1;
+            while ( nextpos < this.buf.Length && this.isAlphaNum(this.buf[nextpos]))
+                nextpos += 1;
+            Token token = new Token(Token.Type.WORD, this.buf.Substring(this.pos, nextpos-this.pos), this.pos);
+            this.pos = nextpos;
+            return token;
+        }
+
+        private Token processQuote()
+        {
+            //this.pos points at the opening quote. Find the ending quote.
+            int end_index = this.buf.IndexOf(this.buf[this.pos], this.pos + 1);
+            if (end_index == -1)
+                throw new LexerException(string.Format("Missing matching quote for the quote at position {0}.", this.pos));
+
+            Token token = new Token(Token.Type.QUOTED, this.buf.Substring(this.pos, end_index-this.pos+1), this.pos);
+            this.pos = end_index + 1;
+            return token;
+        }
+    }
+}

+ 40 - 0
csharp_sccd_compiler/Lexing/Token.cs

@@ -0,0 +1,40 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class Token
+    {
+        public enum Type
+        {
+            SLASH,
+            LBRACKET,
+            RBRACKET,
+            COMMA,
+            DOT,
+            NUMBER,
+            WORD,
+            QUOTED,
+            WHITESPACE,
+            UNKNOWN
+        }
+
+        public Type type { get; private set; }
+
+        public string val { get; private set; }
+
+        public int pos { get; private set; }
+
+        public Token(Type token_type, string value, int pos)
+        {
+            this.type = token_type;
+            this.val = value;
+            this.pos = pos;
+        }
+
+        public override string ToString()
+        {
+            return string.Format("{0}({1}) at {2}", Enum.GetName(typeof(Type), this.type), this.val, this.pos);
+        }
+    }
+}
+

+ 35 - 0
csharp_sccd_compiler/Logger.cs

@@ -0,0 +1,35 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public class Logger
+    {
+        /// <summary>
+        /// Gets or sets the verbose of the logger.
+        /// </summary>
+        /// <value>The verbose. -1 = no ouput; 0 = only errors; 1 = only warnings and errors; 2 = all output.</value>
+        static public int verbose = 2;
+
+        private Logger()
+        {
+        }
+
+        public static void displayError(string message)
+        {
+            if (Logger.verbose > -1)
+                Console.WriteLine(string.Format("ERROR : {0}", message));
+        }
+
+        public static void displayWarning(string message)
+        {
+            if (Logger.verbose > 0)
+                Console.WriteLine(string.Format("WARNING : {0}", message));
+        }
+
+        public static void displayInfo(string message)
+        {
+            if (Logger.verbose > 1)
+                Console.WriteLine(string.Format("INFO : {0}", message));
+        }
+    }
+}

+ 69 - 0
csharp_sccd_compiler/Method.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class Method : Visitable
+    {
+        public string name { get; protected set; }
+        public string return_type { get; protected set; }
+
+        public string access { get; protected set; }
+        public string body { get; protected set; }
+
+        public List<FormalParameter> parameters { get; protected set; }
+
+        protected Method()
+        {
+        }
+
+        public Method(XElement xml)
+        {
+            //Set name
+            XAttribute name_attribute = xml.Attribute("name");
+            if (name_attribute == null)
+                throw new CompilerException("Missing method name.");
+            this.name = name_attribute.Value.Trim();
+            if (this.name == "")
+                throw new CompilerException("Empty method name.");
+            if (Constants.Reserved.Contains(this.name))
+                throw new CompilerException(string.Format("Reserved word '{0}' used as method name.", this.name));
+
+            //Set return type
+            XAttribute return_attribute = xml.Attribute("type");
+            if (return_attribute == null)
+                throw new CompilerException("Missing method type.");
+            this.return_type = return_attribute.Value.Trim();
+            if (this.return_type == "")
+                throw new CompilerException("Empty method type.");
+
+            //Set access level
+            XAttribute access_attribute = xml.Attribute("access");
+            if (access_attribute == null || access_attribute.Value.Trim() == "")
+                this.access = "public"; //default value
+            else
+                this.access = access_attribute.Value.Trim();
+
+            //Set body
+            XAttribute body_attribute = xml.Attribute("body");
+            if (body_attribute == null)
+                this.body = "";
+            else
+                this.body = body_attribute.Value;
+
+            //Set parameters
+            this.parameters = new List<FormalParameter>();
+            foreach (XElement parameter_xml in xml.Elements("parameter"))
+            {
+                this.parameters.Add(new FormalParameter(parameter_xml));
+            }
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}

+ 22 - 0
csharp_sccd_compiler/Properties/AssemblyInfo.cs

@@ -0,0 +1,22 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes. 
+// Change them to the values specific to your project.
+[assembly: AssemblyTitle ("csharp_sccd_compiler")]
+[assembly: AssemblyDescription ("")]
+[assembly: AssemblyConfiguration ("")]
+[assembly: AssemblyCompany ("")]
+[assembly: AssemblyProduct ("")]
+[assembly: AssemblyCopyright ("gl3nn")]
+[assembly: AssemblyTrademark ("")]
+[assembly: AssemblyCulture ("")]
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+[assembly: AssemblyVersion ("1.0.*")]
+// The following attributes are used to specify the signing key for the assembly, 
+// if desired. See the Mono documentation for more information about signing.
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+

+ 128 - 0
csharp_sccd_compiler/StateChart.cs

@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class StateChart : Visitable
+    {
+        /// <summary>
+        /// The total number of transitions present in this statechart that are trigger by time (AFTER).
+        /// </summary>
+        public int nr_of_after_transitions { get; private set; }
+        /// <summary>
+        /// Root node of the statechart.
+        /// </summary>
+        public StateChartNode root { get; private set; } 
+        /// <summary>
+        /// All basic states.
+        /// </summary>
+        public List<StateChartNode> basics { get; private set; } 
+        /// <summary>
+        /// All composite states.
+        /// </summary>
+        public List<StateChartNode> composites { get; private set; }
+        /// <summary>
+        /// All history states.
+        /// </summary>
+        public List<StateChartNode> histories { get; private set; }
+        /// <summary>
+        /// All nodes that need their state saved shallow.
+        /// </summary>
+        public List<StateChartNode> shallow_history_parents { get; private set; }
+        /// <summary>
+        /// All nodes that need their state saved deep.
+        /// </summary>
+        public List<StateChartNode> deep_history_parents { get; private set; }
+        /// <summary>
+        /// All nodes that need their state saved on leaving
+        /// </summary>
+        public List<StateChartNode> combined_history_parents { get; private set; }
+
+        public StateChart(XElement xml)
+        {
+            this.root = new StateChartNode(xml);
+
+            this.nr_of_after_transitions = 0;
+            this.basics = new List<StateChartNode>();
+            this.composites = new List<StateChartNode>();
+            this.histories = new List<StateChartNode>();
+
+            this.extractFromHierarchy(this.root);
+
+            this.shallow_history_parents = new List<StateChartNode>();
+            this.deep_history_parents = new List<StateChartNode>();
+            this.combined_history_parents = new List<StateChartNode>();
+
+            foreach (StateChartNode node in this.histories)
+            {
+                this.calculateHistory(node.parent, node.is_history_deep);
+            }
+        }
+
+        /// <summary>
+        /// Calculates which nodes need their state saved for history purposes.
+        /// </summary>
+        /// <param name="parent">The parent node of a history state.</param>
+        /// <param name="is_history_deep">If set to <c>true</c> the history type is <c>deep</c>.</param>
+        private void calculateHistory(StateChartNode parent, bool is_history_deep)
+        {
+            if (object.ReferenceEquals(parent, this.root)) //TODO use is_root property?
+                throw new CompilerException("Root component cannot contain a history state.");
+
+            if (!this.combined_history_parents.Contains(parent))
+            {
+                this.combined_history_parents.Add(parent);
+                parent.save_state_on_exit = true;
+            }
+
+            if (is_history_deep)
+            {
+                if (! this.deep_history_parents.Contains(parent))
+                    this.deep_history_parents.Add(parent);
+            }
+            else
+            {
+                if (! this.shallow_history_parents.Contains(parent))
+                    this.shallow_history_parents.Add(parent);
+            }
+            if ( parent.is_parallel || is_history_deep)
+            {
+                foreach (StateChartNode child in parent.children)
+                    if (child.is_composite)
+                        this.calculateHistory(child, is_history_deep);
+            }
+        }
+
+        private void extractFromHierarchy(StateChartNode node)
+        {
+            foreach (StateChartTransition transition in node.transitions)
+            {
+                TriggerEvent trigger = transition.trigger;
+                if (trigger.is_after)
+                {
+                    trigger.after_index = this.nr_of_after_transitions;
+                    string event_name = string.Format("_{0}after", trigger.after_index);
+                    trigger.event_name = event_name;
+                    this.nr_of_after_transitions += 1;
+                }
+            }
+
+            if (node.is_basic)
+                this.basics.Add(node);
+            else if (node.is_composite) 
+                this.composites.Add(node);
+            else if (node.is_history) 
+                this.histories.Add(node);
+
+            foreach (StateChartNode child in node.children)
+                this.extractFromHierarchy(child);
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}

+ 337 - 0
csharp_sccd_compiler/StateChartNode.cs

@@ -0,0 +1,337 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class StateChartNode : Visitable
+    {
+
+        public bool is_basic { get; private set; }
+        /// <summary>
+        /// Gets a value indicating whether this <see cref="csharp_sccd_compiler.StateChartNode"/> is a parallel state.
+        /// </summary>
+        /// <value><c>true</c> if is_parallel; otherwise, <c>false</c>.</value>
+        public bool is_parallel { get; private set; }
+        /// <summary>
+        /// Gets a value indicating whether this <see cref="csharp_sccd_compiler.StateChartNode"/> is a composite state.
+        /// </summary>
+        /// <value><c>true</c> if is_composite; otherwise, <c>false</c>.</value>
+        public bool is_composite { get; private set; }
+
+        public bool is_history { get; private set; }
+        /// <summary>
+        /// Gets a value indicating whether this <see cref="csharp_sccd_compiler.StateChartNode"/> is history state of type <c>deep</c>.
+        /// </summary>
+        /// <value><c>true</c> if is_history_deep; otherwise, <c>false</c>.</value>
+        public bool is_history_deep { get; private set; }
+
+        public bool is_root { get; private set; }
+
+        public bool save_state_on_exit { get; set; }
+
+        public bool solves_conflict_outer { get; private set; }
+
+        public string name { get; private set; }
+
+        public string full_name { get; private set; }
+
+        /// <summary>
+        /// The children nodes of this node.
+        /// </summary>
+        public List<StateChartNode> children { get; private set; }
+        /// <summary>
+        /// The parent node of this node. In case of a root node, this property is <c>null</c>.
+        /// </summary>
+        public StateChartNode parent { get; private set; }
+
+        public List<StateChartTransition> transitions { get; private set; }
+
+        public EnterAction enter_action { get; private set; }
+
+        public ExitAction exit_action { get; private set; }
+
+        public List<StateChartNode> defaults { get; private set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="csharp_sccd_compiler.StateChartNode"/> class.
+        /// </summary>
+        /// <param name="xml">The XML element that contains the information related to this node.</param>
+        /// <param name="type">The type of node.</param>
+        /// <param name="is_orthogonal">If set to <c>true</c> this node is orthogonal. (= child of a parallel state.</param>
+        /// <param name="parent">The parent of this node. Defaults to null, which means the node is the root.</param>
+        public StateChartNode(XElement xml, StateChartNode parent = null)
+        {
+            this.parent = parent;
+            this.children = new List<StateChartNode>();
+            this.is_root = false;
+            this.is_basic = false;
+            this.is_composite = false;
+            this.is_history = false;
+            this.is_history_deep = false;
+            this.is_parallel = false;
+            this.save_state_on_exit = false;
+
+            if (xml.Name == "scxml")
+            {
+                this.is_root = true;
+                this.is_composite = true;
+            }
+            else if (xml.Name == "parallel")
+            {
+                this.is_composite = true;
+                this.is_parallel = true;
+            }
+            else if (xml.Name == "state")
+            {
+                if (xml.Element("state") != null || xml.Element("parallel") != null)
+                    this.is_composite = true;
+                else
+                    this.is_basic = true;
+                if (this.parent.is_parallel)
+                {
+                    if (this.is_basic)
+                        throw new CompilerException("Orthogonal nodes (nodes that are immediate children of parallel nodes) can't be basic.");
+                }
+            }
+            else if (xml.Name == "history")
+            {
+				this.is_history = true;
+
+                XAttribute type_attribute = xml.Attribute("type");
+
+                if (type_attribute != null)
+                {
+                    string history_type = type_attribute.Value.Trim();
+                    if (history_type == "deep")
+                        this.is_history_deep = true;
+                    else if (history_type != "shallow")
+                        throw new CompilerException("Invalid history type.");
+                }
+            }
+            else
+                return;
+
+            this.resolveName(xml);
+            this.parseConflictAttribute(xml);
+            this.parseEnterActions(xml);
+            this.parseExitActions(xml);
+
+            //Parse transitions
+            this.transitions = new List<StateChartTransition>();
+            foreach (XElement transition_xml in xml.Elements("transition"))
+                this.transitions.Add(new StateChartTransition(transition_xml, this));
+
+            this.optimizeTransitions();
+            this.generateChildren(xml);
+            this.calculateDefaults(xml);
+        }
+
+        private void resolveName(XElement xml)
+        {
+            if (this.is_root)
+            {
+                this.name = "Root";
+                this.full_name = "Root";
+            }
+            else
+            {
+                XAttribute name_attribute = xml.Attribute("id");
+                if (name_attribute == null)
+                    throw new CompilerException("Currently states without id aren't allowed.");
+                this.name = name_attribute.Value.Trim();
+                if (this.name == "")
+                    throw new CompilerException("Currently states need an non-empty id.");
+                this.full_name = string.Format("{0}_{1}", this.parent.full_name, this.name);
+            }
+        }
+
+        private void parseConflictAttribute(XElement xml)
+        {
+            XAttribute conflict_attribute = xml.Attribute("conflict");
+
+            if(conflict_attribute != null)
+            {
+                string conflict = conflict_attribute.Value.Trim();
+                if (conflict == "outer")
+                {
+                    this.solves_conflict_outer = true;
+                    return;
+                }
+                else if (conflict == "inner")
+                {
+                    this.solves_conflict_outer = false;
+                    return;
+                }
+
+                if (conflict != "" && conflict != "inherit")
+                    throw new CompilerException( string.Format("Unknown conflict attribute for {0}.", this.full_name));
+            }
+            //Do our default inherit action
+            if (this.is_root || this.parent.solves_conflict_outer)
+                this.solves_conflict_outer = true;
+            else
+                this.solves_conflict_outer = false;
+        }
+
+        private void parseEnterActions(XElement xml)
+        {
+            XElement onentry_xml = xml.Element("onentry");
+            if (onentry_xml == null)
+                this.enter_action = new EnterAction(this);
+            else
+            {
+                this.enter_action = new EnterAction(this, onentry_xml);
+                if (onentry_xml.ElementsAfterSelf("onentry").Any())
+                    throw new CompilerException(string.Format("Multiple <onentry> tags detected for {0}, only 1 allowed.", this.full_name));
+            }
+        }
+
+        private void parseExitActions(XElement xml)
+        {
+            XElement onexit_xml = xml.Element("onexit");
+            if (onexit_xml == null)
+                this.exit_action = new ExitAction(this);
+            else
+            {
+                this.exit_action = new ExitAction(this, onexit_xml);
+                if (onexit_xml.ElementsAfterSelf("onexit").Any())
+                    throw new CompilerException(string.Format("Multiple <onexit> tags detected for {0}, only 1 allowed.", this.full_name));
+            }
+        }
+
+        /// <summary>
+        /// If a transition with no trigger and no guard is found then it is considered as the only transition.
+        /// Otherwise the list is ordered by placing transitions having guards only first.
+        /// </summary>
+        private void optimizeTransitions()
+        {
+            List<StateChartTransition> with_trigger = new List<StateChartTransition>();
+            List<StateChartTransition> only_guard = new List<StateChartTransition>();
+            List<StateChartTransition> uc_and_no_guard = new List<StateChartTransition>();
+
+            foreach( StateChartTransition transition in this.transitions)
+            {
+                if (transition.trigger.is_uc)
+                {
+                    if (transition.guard == null)
+                    {
+                        if (uc_and_no_guard.Count > 0)
+                            throw new TransitionException("More than one transition found at a single node, that has no trigger and no guard.");
+                        uc_and_no_guard.Add(transition);
+                    }
+                    else
+                    {
+                        only_guard.Add(transition);
+                    }
+                }
+                else
+                {
+                    with_trigger.Add(transition);
+                }
+            }
+
+            if (uc_and_no_guard.Count > 0)
+                this.transitions = uc_and_no_guard;
+            else
+            {
+                only_guard.AddRange(with_trigger);
+                this.transitions = only_guard;
+            }
+        }
+
+        private void generateChildren(XElement xml)
+        {
+            List<string> children_names = new List<string>();
+            foreach (XElement child_xml in xml.Elements())
+            {
+                StateChartNode child = new StateChartNode(child_xml, this);
+                if (!child.is_composite && !child.is_basic && !child.is_history)
+                    continue;
+                this.children.Add(child);
+
+                //Check if the name of the child is valid
+                if (children_names.Contains(child.name))
+                    throw new CompilerException(string.Format("Found 2 equivalent state id's '{0}' as children of state '{1}'", child.name, this.full_name));
+                children_names.Add(child.name);
+            }
+        }
+
+        private void calculateDefaults(XElement xml)
+        {
+            XAttribute initial_state_attribute = xml.Attribute("initial");
+            string initial_state = "";
+            if (initial_state_attribute != null)
+                initial_state = initial_state_attribute.Value.Trim();
+        
+            if (this.is_parallel)
+            {
+                this.defaults = (from child in this.children where !child.is_history select child).ToList();
+                if (initial_state != "") 
+                    throw new CompilerException(string.Format("Component <{0}> contains an initial state while being parallel.", this.full_name));   
+            }
+            else if (initial_state == "")
+            {
+                if (!this.is_basic && !this.is_history)
+                {
+                    if (this.children.Count == 1)
+                        this.defaults = this.children;
+                    else
+                        throw new CompilerException(string.Format("Component <{0}> contains no default state.", this.full_name)); 
+                }
+            }
+            else
+            {
+                if (this.is_basic)
+                    throw new CompilerException(string.Format("Component <{0}> contains a default state while being a basic state.", this.full_name));
+                this.defaults = new List<StateChartNode>();
+                foreach (StateChartNode child in this.children)
+                {
+                    if (child.name == initial_state)
+                        this.defaults.Add(child);
+                }
+                if (this.defaults.Count < 1)
+                    throw new CompilerException(string.Format("Initial state '{0}' referred to, is missing in {1}.", initial_state, this.full_name));
+                else if (this.defaults.Count > 1)
+                    throw new CompilerException(string.Format("Multiple states with the name '{0}' found in {1} which is referred to as initial state.", initial_state, this.full_name));
+            }
+        }
+
+        /// <summary>
+        /// Returns a list representing the containment hierarchy of this node.
+        /// </summary>
+        /// <returns>The ancestors with node being the first element and its outermost parent (root) being the last.</returns>
+        public IEnumerable<StateChartNode> getAncestors()
+        {
+            StateChartNode current = this;
+            while ( !current.is_root)
+            {
+                current = current.parent;
+                yield return current;
+            }
+        }
+    
+        public bool isDescendantOf(StateChartNode anc)
+        {
+            StateChartNode current = this;
+            while(! current.is_root)
+            {
+                current = current.parent;
+                if (object.ReferenceEquals(current,anc))
+                    return true;
+            }
+            return false;
+        }
+
+        public bool isDescendantOrAncestorOf(StateChartNode node)
+        {
+            return this.isDescendantOf(node) || node.isDescendantOf(this);
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}

+ 57 - 0
csharp_sccd_compiler/StateChartTransition.cs

@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class StateChartTransition : Visitable
+    {
+        public TriggerEvent trigger { get; private set; }
+
+        public StateChartNode parent { get; private set; }
+
+        public Expression guard { get; private set; }
+
+        public StateReference target { get; private set; }
+
+        public Action action { get; private set; }
+
+        /// <summary>
+        /// Ordered list of nodes to be entered upon taking the transition. 
+        /// The boolean value indicates whether the <c>StateChartNode</c> in the list is the last in a branch. 
+        /// (And was thus specified specifically in the state reference.)
+        /// </summary>
+        /// <value>Set by the Path Calculator visitor.</value>
+        public List<Tuple<StateChartNode,bool>> enter_nodes { get; set; }
+
+        /// <summary>
+        /// Ordered list of nodes to be exited upon taking the transition.
+        /// </summary>
+        /// <value>Set by the Path Calculator visitor.</value>
+        public List<StateChartNode> exit_nodes { get; set; }
+
+        public StateChartTransition(XElement xml, StateChartNode parent)
+        {
+            this.parent = parent;
+            this.trigger = new TriggerEvent(xml);
+            XAttribute guard_attribute = xml.Attribute("cond");
+            if (guard_attribute != null && guard_attribute.Value.Trim() != "")
+                this.guard = new Expression(guard_attribute.Value.Trim());
+            else
+                this.guard = null;
+
+            XAttribute target_attribute = xml.Attribute("target");
+            if (target_attribute == null)
+                throw new CompilerException(string.Format("Transition from <{0}> is missing a target attribute.", this.parent.full_name));
+            this.target = new StateReference(target_attribute.Value.Trim());
+
+            this.action = new Action(xml);
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 26 - 0
csharp_sccd_compiler/StateReference.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+
+namespace csharp_sccd_compiler
+{
+    public class StateReference : Visitable
+    {
+        public string state_reference_string { get; private set; }
+
+        /// <summary>
+        /// Populated later by State Linker
+        /// </summary>
+        public List<StateChartNode> target_nodes { get; set; }
+
+        public StateReference(string state_reference_string)
+        {
+            this.state_reference_string = state_reference_string;
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 30 - 0
csharp_sccd_compiler/SubAction/Assign.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class Assign : SubAction
+    {
+        public LValue lvalue { get; private set; }
+
+        public Expression expression { get; private set; }
+
+        public Assign(XElement xml)
+        {
+            XAttribute ident_attribute = xml.Attribute("ident");
+            if (ident_attribute == null)
+                throw new ActionException("Missing \"ident\" attribute for assignment.");
+            this.lvalue = new LValue(ident_attribute.Value.Trim());
+
+            XAttribute expression_attribute = xml.Attribute("expr");
+            if (expression_attribute == null)
+                throw new ActionException("Missing \"expr\" attribute for assignment.");
+            this.expression = new Expression(expression_attribute.Value.Trim());
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}

+ 20 - 0
csharp_sccd_compiler/SubAction/Log.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class Log : SubAction
+    {
+        public string message { get; private set; }
+
+        public Log(XElement xml)
+        {
+            this.message = xml.Value.Trim();
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}

+ 109 - 0
csharp_sccd_compiler/SubAction/RaiseEvent.cs

@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class RaiseEvent : SubAction
+    {
+        public enum Scope {
+            UNKNOWN_SCOPE,
+            LOCAL_SCOPE,
+            BROAD_SCOPE,
+            OUTPUT_SCOPE,
+            NARROW_SCOPE,
+            CD_SCOPE
+        };
+
+        public string event_name { get; private set; }
+
+        public string target { get; private set; }
+
+        public string port { get; private set; }
+
+        public Scope scope { get; private set; }
+
+        public List<Expression> parameters { get; private set; }
+
+        public RaiseEvent(XElement xml)
+        {
+            XAttribute event_attribute = xml.Attribute("event");
+            if (event_attribute == null)
+                throw new ActionException("Missing \"event\" attribute for <raise> action.");
+            this.event_name = event_attribute.Value.Trim();
+            if (this.event_name == "")
+                throw new ActionException("Empty \"event\" attribute for <raise> action.");
+
+            XAttribute target_attribute = xml.Attribute("target");
+            if (target_attribute == null || target_attribute.Value.Trim() == "")
+                this.target = null;
+            else
+                this.target = target_attribute.Value.Trim();
+
+            XAttribute port_attribute = xml.Attribute("port");
+            if (port_attribute == null || port_attribute.Value.Trim() == "")
+                this.port = null;
+            else
+                this.port = port_attribute.Value.Trim();
+
+            string scope_string;
+            XAttribute scope_attribute = xml.Attribute("scope");
+            if (scope_attribute == null || scope_attribute.Value.Trim() == "")
+                scope_string = null;
+            else
+                scope_string = scope_attribute.Value.Trim();
+
+            if (scope_string == null)
+            {
+                //Calculate scope depending on present attributes
+                if (this.target != null && this.port != null)
+                    throw new ActionException("Both target and port attribute detected for <raise> action without a scope defined.");
+                else if (this.port != null)
+                    this.scope = Scope.OUTPUT_SCOPE;
+                else if (this.target != null)
+                    this.scope = Scope.NARROW_SCOPE;
+                else
+                    this.scope = Scope.LOCAL_SCOPE;
+            }
+            else if (scope_string == "local")
+                this.scope = Scope.LOCAL_SCOPE;
+            else if (scope_string == "broad")
+                this.scope = Scope.BROAD_SCOPE;
+            else if (scope_string == "output")
+                this.scope = Scope.OUTPUT_SCOPE;
+            else if (scope_string == "narrow")
+                this.scope = Scope.NARROW_SCOPE;
+            else if (scope_string == "cd")
+                this.scope = Scope.CD_SCOPE;    
+            else
+                throw new ActionException(string.Format("Illegal scope attribute \"{0}\"; needs to be one of the following : local, broad, narrow, output, cd or nothing.", scope_string));  
+        
+            if (this.scope == Scope.LOCAL_SCOPE || this.scope == Scope.BROAD_SCOPE || this.scope == Scope.CD_SCOPE)
+            {
+                if (this.target != null)
+                    throw new ActionException("<raise> target detected, not matching with scope.");
+                if (this.port != null)
+                    throw new ActionException("<raise> port detected, not matching with scope. Ignored.");
+            }
+            if (this.scope == Scope.NARROW_SCOPE && this.port != null)
+                throw new ActionException("<raise> port detected, not matching with scope");
+            if (this.scope == Scope.OUTPUT_SCOPE && this.target != null)
+                throw new ActionException("Raise event target detected, not matching with scope. Ignored.");     
+
+            this.parameters = new List<Expression>();
+            foreach (XElement parameter_xml in xml.Elements("parameter"))
+            {
+                XAttribute expr_attribute = parameter_xml.Attribute("expr");
+                if (expr_attribute == null || expr_attribute.Value.Trim() == "")
+                    throw new ActionException("<parameter> in <raise> detected without \"value\" attribute.");
+                this.parameters.Add( new Expression(expr_attribute.Value.Trim()));
+            }
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}
+

+ 20 - 0
csharp_sccd_compiler/SubAction/Script.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class Script : SubAction
+    {
+        public string code { get; private set; }
+
+        public Script(XElement xml)
+        {
+            this.code = xml.Value.Trim();
+        }
+
+        public override void accept(Visitor visitor)
+        {
+            visitor.visit (this);
+        }
+    }
+}

+ 9 - 0
csharp_sccd_compiler/SubAction/SubAction.cs

@@ -0,0 +1,9 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public abstract class SubAction : Visitable
+    {
+    }
+}
+

+ 73 - 0
csharp_sccd_compiler/TriggerEvent.cs

@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml.Linq;
+
+namespace csharp_sccd_compiler
+{
+    public class TriggerEvent
+    {
+        public bool is_after { get; private set; }
+        public bool is_uc { get; private set; }
+
+        public int after_index { get; set; }
+        public List<FormalEventParameter> parameters { get; private set; }
+
+        public string event_name { get; set; }
+        public string port { get; private set; }
+        public Expression after_expression { get; private set; }
+
+        public TriggerEvent(XElement xml)
+        {
+            after_index = -1; //Initial value
+
+            //Parse "port" attribute
+            XAttribute port_attribute = xml.Attribute("port");
+            if (port_attribute == null || port_attribute.Value.Trim() == "")
+                this.port = null;
+            else
+                this.port = port_attribute.Value.Trim();
+
+            //Parse "after" attribute
+            XAttribute after_attribute = xml.Attribute("after");
+            if (after_attribute == null || after_attribute.Value.Trim() == "")
+            {
+                this.after_expression = null;
+                this.is_after = false;
+            }
+            else
+            {
+                this.after_expression = new Expression(after_attribute.Value.Trim());
+                if (this.port != null)
+                    throw new CompilerException("An after event can not have a port defined.");
+                this.is_after = true;
+
+            }
+
+            //parse "event" attribute
+            XAttribute event_name_attribute = xml.Attribute("event");
+            if (event_name_attribute == null || event_name_attribute.Value.Trim() == "")
+            {
+                this.event_name = null;
+                if (this.port != null)
+                    throw new CompilerException("A transition without event can not have a port.");
+                if (!this.is_after)
+                    this.is_uc = true;
+            }
+            else
+            {
+                this.event_name = event_name_attribute.Value.Trim();
+                if (this.is_after)
+                    throw new CompilerException("Cannot have both the event and after attribute set for a transition.");
+            }
+         
+            this.parameters = new List<FormalEventParameter>();
+            foreach (XElement parameter_xml in xml.Elements("parameter"))
+            {
+                this.parameters.Add(new FormalEventParameter(parameter_xml));
+            }
+            if(this.parameters.Count > 0 && (this.is_after || this.is_uc ))
+                throw new CompilerException("AFTER and unconditional events can not have parameters defined.");
+        }
+    }
+}

+ 104 - 0
csharp_sccd_compiler/Visitors/PathCalculator.cs

@@ -0,0 +1,104 @@
+using System;
+using System.Linq;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace csharp_sccd_compiler
+{
+
+    /// <summary>
+    /// Computes the states that must be exited and entered for a specific transition if the system is to make that transition. 
+    /// </summary>
+    public class PathCalculator : Visitor
+    {
+        public PathCalculator()
+        {
+        }
+
+        public override void visit(ClassDiagram class_diagram)
+        {
+            foreach(Class c in class_diagram.classes)
+                c.accept(this);
+        }
+
+        public override void visit(Class c)
+        {
+            c.statechart.accept(this);
+        }
+
+        public override void visit(StateChart statechart)
+        {
+            foreach (StateChartNode node in statechart.basics.Concat(statechart.composites))
+                node.accept(this);
+        }
+
+        public override void visit(StateChartNode node)
+        {
+            foreach (StateChartTransition transition in node.transitions)
+                transition.accept(this);
+        }
+
+        public override void visit(StateChartTransition transition)
+        {
+            //Find the scope of the transition (lowest common proper ancestor)
+            //TODO: Could it be made more efficient if we calculated the LCA from the source node and just one of the target nodes?
+
+            StateChartNode LCA = this.calculateLCA(transition);
+            //Calculate exit nodes
+            transition.exit_nodes = new List<StateChartNode>(){transition.parent};
+            foreach(StateChartNode node in transition.parent.getAncestors())
+            {
+                if (object.ReferenceEquals(node, LCA))
+                    break;
+                transition.exit_nodes.Add(node);
+            }
+            //Calculate enter nodes
+            transition.enter_nodes = new List<Tuple<StateChartNode, bool>>();
+
+            foreach (StateChartNode target_node in transition.target.target_nodes)
+            {
+                var to_append = new List<Tuple<StateChartNode, bool>>(){new Tuple<StateChartNode, bool>(target_node, true)};
+                foreach (StateChartNode anc in target_node.getAncestors())
+                {
+                    if (object.ReferenceEquals(anc, LCA))//If we reach the LCA in the ancestor hierarchy we break
+                        break;
+                    bool to_add = true; //boolean value to see if the current ancestor should be added to the result
+                    foreach (Tuple<StateChartNode, bool> enter_node_entry in transition.enter_nodes)
+                    {
+                        if (object.ReferenceEquals(enter_node_entry.Item1, anc))
+                        {
+                            to_add = false; //If we reach an ancestor in the hierarchy that is already listed as enter node, we don't add and break
+                            break;
+                        }
+                    }
+                    if (to_add)
+                        to_append.Add(new Tuple<StateChartNode, bool>(anc, false)); //Only target nodes get true
+                    else
+                        break;
+                }
+                to_append.Reverse();
+                transition.enter_nodes.AddRange(to_append);
+            }
+        }
+
+        private StateChartNode calculateLCA(StateChartTransition transition)
+        {
+            foreach(StateChartNode anc in transition.parent.getAncestors())
+            {
+                bool all_descendants = true;
+                foreach (StateChartNode node in transition.target.target_nodes)
+                {
+                    if (!node.isDescendantOf(anc))
+                    {
+                        all_descendants = false;
+                        break;
+                    }
+                }
+                if (all_descendants)
+                    return anc;
+            }
+            return null;
+        }
+    }
+}
+

+ 197 - 0
csharp_sccd_compiler/Visitors/StateLinker.cs

@@ -0,0 +1,197 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace csharp_sccd_compiler
+{
+    public class StateLinker : Visitor
+    {
+        StateChart visiting_statechart;
+        StateChartNode visiting_node;
+        Lexer lexer;
+
+        public StateLinker()
+        {
+            this.lexer = new Lexer();
+        }
+
+        public override void visit(ClassDiagram class_diagram)
+        {
+            foreach (Class c in class_diagram.classes)
+                c.accept(this);
+        }
+
+        public override void visit(Class c)
+        {
+            c.statechart.accept(this);
+        }
+
+        public override void visit(StateChart statechart)
+        {
+            this.visiting_statechart = statechart;
+            foreach (StateChartNode node in statechart.basics.Concat(statechart.composites))
+                node.accept(this);
+        }
+        
+        public override void visit(StateChartNode node)
+        {
+            this.visiting_node = node;
+            node.enter_action.accept(this);
+            node.exit_action.accept(this);
+            foreach (StateChartTransition transition in node.transitions)
+                transition.accept(this);
+        }
+               
+
+        public override void visit(StateChartTransition transition)
+        {
+            try
+            {
+                transition.target.accept(this);
+            }
+            catch (StateReferenceException exception)
+            {
+                throw new StateReferenceException(string.Format("Transition from <{0}> has invalid target.", this.visiting_node.full_name), exception);
+            }
+            try
+            {
+                transition.action.accept(this);
+            }
+            catch (StateReferenceException exception)
+            {
+                throw new StateReferenceException(string.Format("Transition from <{0}> has invalid action.", this.visiting_node.full_name), exception);
+            }
+            try
+            {
+                if (transition.guard != null)
+                    transition.guard.accept(this);
+            }
+            catch (StateReferenceException exception)
+            {
+                throw new StateReferenceException(string.Format("Transition from <{0}> has invalid guard.", this.visiting_node.full_name), exception);
+            }
+        }
+
+        public override void visit(StateReference state_reference)
+        {
+            state_reference.target_nodes = new List<StateChartNode>();
+            StateChartNode current_node = null; //Will be used to find the target state(s)
+            Stack<StateChartNode> split_stack = new Stack<StateChartNode>(); // user for branching
+            this.lexer.setInput(state_reference.state_reference_string);
+
+            foreach (Token token in this.lexer.iterateTokens())
+            {
+                if (current_node == null) //current_node is not set yet or has been reset, the CHILD token can now have a special meaning
+                {
+                    if (token.type == Token.Type.SLASH) 
+                    {
+                        current_node = this.visiting_statechart.root; //Root detected
+                        continue;
+                    }
+                    else
+                        current_node = this.visiting_node;
+                }
+
+                if (token.type == Token.Type.DOT)
+                {
+                    Token next_token = this.lexer.nextToken();//Advance to next token
+                    if (next_token == null || next_token.type == Token.Type.SLASH)
+                        continue;//CURRENT operator "." detected
+                    else if (next_token.type == Token.Type.DOT)
+                    {
+                        next_token = this.lexer.nextToken();//Advance to next token
+                        if (next_token == null || next_token.type == Token.Type.SLASH)
+                        {
+                            current_node = current_node.parent; //PARENT operator ".." detected
+                            if (current_node == null)
+                                throw new StateReferenceException(string.Format("Illegal use of PARENT \"..\" operator at position {0} in state reference. Root of statechart reached.", token.pos));
+                        }
+                        else
+                            throw new StateReferenceException(string.Format("Illegal use of PARENT \"..\" operator at position {0} in state reference.", token.pos));
+                    }
+                    else
+                        throw new StateReferenceException(string.Format("Illegal use of CURRENT \"..\" operator at position {0} in state reference.", token.pos));
+                }
+                else if (token.type == Token.Type.SLASH)
+                    continue;
+                else if (token.type == Token.Type.WORD)
+                {
+                    //Trying to advance to next child state
+                    string child_name = token.val;
+                    bool found = false;
+                    foreach (StateChartNode child in current_node.children)
+                    {
+                        if (child.name == child_name)
+                        {
+                            found = true;
+                            current_node = child;
+                            break;
+                        }
+                    }
+                    if (!found)
+                        throw new StateReferenceException(string.Format("Refering to non exiting node at posisition {0} in state reference.", token.pos));
+                }
+                else if (token.type == Token.Type.LBRACKET)
+                    split_stack.Push(current_node);
+                else if (token.type == Token.Type.RBRACKET)
+                {
+                    if (split_stack.Count > 0)
+                        split_stack.Pop();
+                    else
+                        throw new StateReferenceException(string.Format("Invalid token at position {0} in state reference.", token.pos));
+                }
+                else if (token.type == Token.Type.COMMA)
+                {
+                    state_reference.target_nodes.Add(current_node);
+                    if (split_stack.Count > 0)
+                        current_node = split_stack.Peek();
+                    else
+                        current_node = null;
+                }
+                else
+                    throw new StateReferenceException(string.Format("Invalid token at position {0} in state reference.", token.pos));
+            }
+
+            if (split_stack.Count != 0 || current_node == null) //RB missing or extra COMMA
+                throw new StateReferenceException("State reference ends unexpectedly.");
+
+            //TODO better validation of the target! When is it a valid state configuration?
+            foreach (StateChartNode node in state_reference.target_nodes)
+            {
+                if (object.ReferenceEquals(current_node,node))
+                    throw new StateReferenceException("A state reference can't reference the same node more than once.");
+                if (node.isDescendantOrAncestorOf(current_node))
+                    throw new StateReferenceException("A state reference can't reference a node and one of its descendants.");
+            }
+
+            state_reference.target_nodes.Add(current_node);
+
+            if (state_reference.target_nodes.Count == 0)
+                throw new StateReferenceException("Meaningless state reference.");
+        }
+
+        public override void visit(EnterExitAction enter_exit_action)
+        {
+            if (enter_exit_action.action != null)
+                enter_exit_action.action.accept(this);
+        }
+
+        public override void visit(InStateCall in_state_call)
+        {
+            try
+            {
+                in_state_call.state_reference.accept(this);
+            }
+            catch (StateReferenceException exception)
+            {
+                throw new StateReferenceException(string.Format("Invalid state reference for {0} macro.", Constants.INSTATE_SEQ), exception);
+            }
+        }
+
+        public override void visit(Assign assign)
+        {
+            assign.expression.accept(this);
+        }
+    }
+}
+

+ 10 - 0
csharp_sccd_compiler/Visitors/Visitable.cs

@@ -0,0 +1,10 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+    public abstract class Visitable
+    {
+        public abstract void accept(Visitor visitor);
+    }
+}
+

+ 100 - 0
csharp_sccd_compiler/Visitors/Visitor.cs

@@ -0,0 +1,100 @@
+using System;
+
+namespace csharp_sccd_compiler
+{
+	abstract public class Visitor
+	{
+        public virtual void visit(Visitable visiting)
+        {
+        }
+
+        public virtual void visit(ClassDiagram class_diagram)
+        {
+        }
+
+        public virtual void visit(Class class_node)
+        {
+        }
+
+        public virtual void visit(FormalParameter formal_parameter)
+        {
+        }
+
+        public virtual void visit(Constructor constructor)
+        {
+        }
+
+        public virtual void visit(Destructor destructor)
+        {
+        }
+
+        public virtual void visit(Method method)
+        {
+        }
+
+        public virtual void visit(Association association)
+        {
+        }
+
+        public virtual void visit(EnterExitAction enter_exit_action)
+        {
+        }
+
+        public virtual void visit(EnterAction enter_method)
+        {
+        }
+
+        public virtual void visit(ExitAction exit_method)
+        {
+        }
+
+        public virtual void visit(StateChart statechart)
+        {
+        }
+        
+        public virtual void visit(StateChartNode node)
+        {
+        }
+
+        public virtual void visit(StateChartTransition transition)
+        {
+        }
+
+        public virtual void visit(ExpressionPartString expression_part_string)
+        {
+        }
+
+        public virtual void visit(SelfReference self_reference)
+        {
+        }
+
+        public virtual void visit(StateReference state_ref)
+        {
+        }
+
+        public virtual void visit(InStateCall in_state_call)
+        {
+        }
+
+        public virtual void visit(RaiseEvent raise_event)
+        {
+        }
+
+        public virtual void visit(Script script)
+        {
+        }
+
+        public virtual void visit(Log log)
+        {
+        }
+
+        public virtual void visit(Assign assign)
+        {
+        }
+
+        public virtual void visit( FormalEventParameter formal_event_parameter)
+        {
+        }
+	}
+}
+

+ 97 - 0
csharp_sccd_compiler/csharp_sccd_compiler.csproj

@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>10.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{DFB7F649-CA2A-40CD-925B-7D975252A8C3}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>csharp_sccd_compiler</RootNamespace>
+    <AssemblyName>csharp_sccd_compiler</AssemblyName>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Externalconsole>true</Externalconsole>
+    <PlatformTarget>x86</PlatformTarget>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>full</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Externalconsole>true</Externalconsole>
+    <PlatformTarget>x86</PlatformTarget>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ClassDiagram.cs" />
+    <Compile Include="Class.cs" />
+    <Compile Include="Logger.cs" />
+    <Compile Include="Constructor.cs" />
+    <Compile Include="Method.cs" />
+    <Compile Include="Destructor.cs" />
+    <Compile Include="Attribute.cs" />
+    <Compile Include="Association.cs" />
+    <Compile Include="StateChart.cs" />
+    <Compile Include="Constants.cs" />
+    <Compile Include="FormalParameter.cs" />
+    <Compile Include="StateChartNode.cs" />
+    <Compile Include="StateChartTransition.cs" />
+    <Compile Include="TriggerEvent.cs" />
+    <Compile Include="FormalEventParameter.cs" />
+    <Compile Include="EnterExitAction.cs" />
+    <Compile Include="Action.cs" />
+    <Compile Include="SubAction\SubAction.cs" />
+    <Compile Include="SubAction\RaiseEvent.cs" />
+    <Compile Include="SubAction\Script.cs" />
+    <Compile Include="SubAction\Log.cs" />
+    <Compile Include="SubAction\Assign.cs" />
+    <Compile Include="Exceptions\CompilerException.cs" />
+    <Compile Include="Exceptions\TransitionException.cs" />
+    <Compile Include="StateReference.cs" />
+    <Compile Include="Exceptions\UnprocessedException.cs" />
+    <Compile Include="Exceptions\ActionException.cs" />
+    <Compile Include="Visitors\Visitor.cs" />
+    <Compile Include="Visitors\Visitable.cs" />
+    <Compile Include="Visitors\StateLinker.cs" />
+    <Compile Include="Exceptions\StateReferenceException.cs" />
+    <Compile Include="Lexing\Lexer.cs" />
+    <Compile Include="Exceptions\LexerException.cs" />
+    <Compile Include="Lexing\Token.cs" />
+    <Compile Include="Expression\Expression.cs" />
+    <Compile Include="Expression\LValue.cs" />
+    <Compile Include="Expression\ExpressionPart.cs" />
+    <Compile Include="Expression\ExpressionPartString.cs" />
+    <Compile Include="Expression\SelfReference.cs" />
+    <Compile Include="Expression\InStateCall.cs" />
+    <Compile Include="Code Generation\FileOutputer.cs" />
+    <Compile Include="Code Generation\CodeGenerator.cs" />
+    <Compile Include="Exceptions\CodeBlockException.cs" />
+    <Compile Include="Code Generation\CSharpGenerator.cs" />
+    <Compile Include="Visitors\PathCalculator.cs" />
+    <Compile Include="Compiler.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Folder Include="SubAction\" />
+    <Folder Include="Exceptions\" />
+    <Folder Include="Visitors\" />
+    <Folder Include="Lexing\" />
+    <Folder Include="Expression\" />
+    <Folder Include="Code Generation\" />
+  </ItemGroup>
+</Project>

+ 50 - 0
csharp_sccd_compiler/csharp_sccd_compiler.sln

@@ -0,0 +1,50 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp_sccd_compiler", "csharp_sccd_compiler.csproj", "{DFB7F649-CA2A-40CD-925B-7D975252A8C3}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|x86 = Debug|x86
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{DFB7F649-CA2A-40CD-925B-7D975252A8C3}.Debug|x86.ActiveCfg = Debug|x86
+		{DFB7F649-CA2A-40CD-925B-7D975252A8C3}.Debug|x86.Build.0 = Debug|x86
+		{DFB7F649-CA2A-40CD-925B-7D975252A8C3}.Release|x86.ActiveCfg = Release|x86
+		{DFB7F649-CA2A-40CD-925B-7D975252A8C3}.Release|x86.Build.0 = Release|x86
+	EndGlobalSection
+	GlobalSection(MonoDevelopProperties) = preSolution
+		StartupItem = csharp_sccd_compiler.csproj
+		Policies = $0
+		$0.TextStylePolicy = $1
+		$1.inheritsSet = VisualStudio
+		$1.inheritsScope = text/plain
+		$1.scope = text/x-csharp
+		$0.CSharpFormattingPolicy = $2
+		$2.IndentSwitchBody = True
+		$2.AnonymousMethodBraceStyle = NextLine
+		$2.PropertyBraceStyle = NextLine
+		$2.PropertyGetBraceStyle = NextLine
+		$2.PropertySetBraceStyle = NextLine
+		$2.EventBraceStyle = NextLine
+		$2.EventAddBraceStyle = NextLine
+		$2.EventRemoveBraceStyle = NextLine
+		$2.StatementBraceStyle = NextLine
+		$2.ElseNewLinePlacement = NewLine
+		$2.CatchNewLinePlacement = NewLine
+		$2.FinallyNewLinePlacement = NewLine
+		$2.WhileNewLinePlacement = DoNotCare
+		$2.ArrayInitializerWrapping = DoNotChange
+		$2.ArrayInitializerBraceStyle = NextLine
+		$2.BeforeMethodDeclarationParentheses = False
+		$2.BeforeMethodCallParentheses = False
+		$2.BeforeConstructorDeclarationParentheses = False
+		$2.BeforeDelegateDeclarationParentheses = False
+		$2.NewParentheses = False
+		$2.SpacesBeforeBrackets = False
+		$2.inheritsSet = Mono
+		$2.inheritsScope = text/x-csharp
+		$2.scope = text/x-csharp
+	EndGlobalSection
+EndGlobal

+ 42 - 0
csharp_tests/CSharpTests.cs

@@ -0,0 +1,42 @@
+using System;
+using csharp_sccd_compiler;
+using NUnit.Framework;
+
+namespace csharp_tests
+{
+    [TestFixture]
+    [Category("CSharp")]
+    public class CSharpTests : TestsBase
+    {
+        [TestFixtureSetUp]
+        public void setLogger()
+        {
+            Logger.verbose = 1;
+        }
+
+        protected override bool generate(string file_path, string expected_exception)
+        {
+            TestDelegate generation_delegate = () => Compiler.generate(file_path, this.path_generated_code, CodeGenerator.Platform.THREADS);
+
+            if (expected_exception == null)
+                generation_delegate();
+            else
+            {
+                Type expected_exception_type = null;
+                if (expected_exception == "CompilerException")
+                    expected_exception_type = typeof(CompilerException);
+                else if (expected_exception == "TransitionException")
+                    expected_exception_type = typeof(TransitionException);
+                else
+                    Assert.Fail("Invalid value for the exception attribute.");
+
+                Exception throwed_exception = Assert.Catch<Exception>(generation_delegate, "Expected an exception but none was throwed.").GetBaseException();
+                Assert.IsInstanceOf(expected_exception_type, throwed_exception, 
+                                        string.Format("Expected exception of type {0} but got an exception of type {1} instead.", expected_exception_type, throwed_exception.GetType()));
+                return false;
+            }
+            return true;
+        }
+    }
+}
+

+ 51 - 0
csharp_tests/CodeCompiler.cs

@@ -0,0 +1,51 @@
+using System;
+using System.IO;
+using Microsoft.CSharp;
+using System.CodeDom.Compiler;
+using System.Reflection;
+
+namespace csharp_tests
+{
+    public class CodeCompiler
+    {
+        protected CSharpCodeProvider compiler = new CSharpCodeProvider();
+        protected CompilerParameters compiler_parameters;
+
+        public CodeCompiler()
+        {
+            this.compiler_parameters = new CompilerParameters
+            {
+                WarningLevel = 0,
+                GenerateExecutable = false,
+                GenerateInMemory = true/*,
+                OutputAssembly = "Assembly.dll"*/
+            };
+        }
+
+        public void AddReferencedAssembly(string name)
+        {
+            this.compiler_parameters.ReferencedAssemblies.Add(name);
+        }
+         
+        public Assembly compileFile(string file)
+        {
+            Assembly returnAssembly = null;
+            try
+            {
+                CompilerResults results = this.compiler.CompileAssemblyFromFile(compiler_parameters, file);
+                returnAssembly = results.CompiledAssembly;
+         
+                foreach (string output in results.Output)
+                {
+                    Console.WriteLine(output);
+                }
+            }
+            catch (Exception exception)
+            {
+                Console.WriteLine(exception.Message);
+            }
+            return returnAssembly;
+        }
+    }
+}
+

+ 27 - 0
csharp_tests/Properties/AssemblyInfo.cs

@@ -0,0 +1,27 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+// Information about this assembly is defined by the following attributes. 
+// Change them to the values specific to your project.
+
+[assembly: AssemblyTitle("csharp_tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("gl3nn")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
+// The form "{Major}.{Minor}.*" will automatically update the build and revision,
+// and "{Major}.{Minor}.{Build}.*" will update just the revision.
+
+[assembly: AssemblyVersion("1.0.*")]
+
+// The following attributes are used to specify the signing key for the assembly, 
+// if desired. See the Mono documentation for more information about signing.
+
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile("")]
+

+ 45 - 0
csharp_tests/PythonTests.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using NUnit.Framework;
+
+namespace csharp_tests
+{
+    [TestFixture]
+    [Category("Python")]
+    public class PythonTests : TestsBase
+    {
+
+        protected override bool generate(string file_path, string expected_exception)
+        {
+            ProcessStartInfo start_info = new ProcessStartInfo();
+            start_info.FileName = "python";
+            start_info.Arguments = string.Format("../../../python_sccd_compiler/sccdc.py {0} -o {1} -p threads -l C# -v -1", file_path, this.path_generated_code);
+            start_info.UseShellExecute = false;
+            start_info.RedirectStandardOutput = true;
+            //Print any output the compiler gave
+            using (Process process = Process.Start(start_info))
+            {
+                using (StreamReader reader = process.StandardOutput)
+                {
+                    string result = reader.ReadToEnd();
+                    Console.Write(result);
+                }
+            }
+            //Exception check
+            //If the test file expects an exception to be thrown by the compiler,
+            //we just try to compile the model and see if a file got generated.
+            //If the result file got generated, this means that no exception was thrown
+            //and thus the test should fail.
+            bool target_file_exists = File.Exists(this.path_generated_code);
+            if (expected_exception != null)
+            {
+                Assert.AreEqual(false, target_file_exists, "An exception was expected to be thrown by the compiler but the SCCD compiler completed successfully.");
+                return false; //No target file as expected, we can end the test.
+            }
+            Assert.AreEqual(true, target_file_exists, "The SCCD Compiler did not complete compilation. No generated file has been found.");
+            return true;
+        }
+    }
+}
+

+ 45 - 0
csharp_tests/TestEvent.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using sccdlib;
+
+namespace csharp_tests
+{
+    public class TestEvent
+    {
+        string name;
+        string port;
+        List<string> parameters;
+
+        public TestEvent(string name, string port, List<string> parameters)
+        {
+            this.name = name;
+            this.port = port;
+            this.parameters = parameters;
+        }
+
+        public bool matches(Event output_event)
+        {
+            if (output_event == null)
+                return false;
+            if (output_event.getName() != this.name)
+                return false;
+            if (output_event.getPort() != this.port)
+                return false;
+            List<object> compare_parameters = new List<object>(output_event.getParameters());
+            if (this.parameters.Count != compare_parameters.Count)
+                return false;
+            for (int i = 0; i < this.parameters.Count; i++)
+            {
+                if (this.parameters [i] != compare_parameters[i].ToString())
+                    return false;
+            }
+            return true;
+        }
+    
+        public override string ToString()
+        {
+            return string.Format("(event name : {0}; port : {1}; parameters : [{2}])", this.name, this.port, string.Join(", ", this.parameters));
+        }
+    }
+}
+

+ 151 - 0
csharp_tests/TestsBase.cs

@@ -0,0 +1,151 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Reflection;
+using System.Collections;
+using System.Collections.Generic;
+using System.Xml.Linq;
+using System.Linq;
+using Microsoft.CSharp.RuntimeBinder;
+using NUnit.Framework;
+using sccdlib;
+
+namespace csharp_tests
+{
+    public abstract class TestsBase
+    {
+        protected string path_generated_code;
+        protected bool keep_after_test;
+
+        protected abstract bool generate(string file_path, string expected_exception);
+
+        [Test, TestCaseSource(typeof(TestsBase),"GetTestCases")]
+        public void testXML(string file_path)
+        {
+            XElement test_xml = XDocument.Load(file_path).Root.Element("test");
+            Assert.AreNotEqual(null, test_xml, "No test data found. (A test that should just compile correctly, still needs an empthy test tag.)");
+
+            //Calculate path to output file
+            this.path_generated_code = Path.ChangeExtension(Path.GetFileName(file_path), ".cs");
+
+            this.keep_after_test = false;
+            if (File.Exists(this.path_generated_code))
+            {
+                this.keep_after_test = true;
+                File.Delete(this.path_generated_code);
+            }
+
+            string expected_exception = null;
+            if (test_xml.Attribute("exception") != null && test_xml.Attribute("exception").Value.Trim() != "")
+            {
+                expected_exception = test_xml.Attribute("exception").Value.Trim();
+            }
+
+            //Call code generator
+            if (!this.generate(file_path, expected_exception))
+                return;
+
+            //Compile generated code
+            CodeCompiler code_compiler = new CodeCompiler();
+            code_compiler.AddReferencedAssembly("System.dll");
+            code_compiler.AddReferencedAssembly("sccdlib.dll");
+            Assembly assembly = code_compiler.compileFile(this.path_generated_code);
+            Type class_type = assembly.GetType("Controller");
+
+            //Prepare expected output
+            XElement expected_xml = test_xml.Element("expected");
+            if (expected_xml == null)
+                return;
+
+            HashSet<string> output_ports = new HashSet<string>();
+            List<List<TestEvent>> expected_result = new List<List<TestEvent>>();
+
+            foreach (XElement slot_xml in expected_xml.Elements("slot"))
+            {
+                List<TestEvent> slot = new List<TestEvent>();
+                foreach (XElement event_xml in slot_xml.Elements("event"))
+                {
+                    string event_name = event_xml.Attribute("name").Value;
+                    string port = event_xml.Attribute("port").Value;
+                    List<string> parameters = new List<string>();
+                    foreach (XElement parameter_xml in event_xml.Elements("parameter"))
+                    {
+                        string parameter_value = parameter_xml.Attribute("value").Value;
+                        parameters.Add(parameter_value);
+                    }
+                    slot.Add(new TestEvent(event_name, port, parameters));
+                    output_ports.Add(port);
+                }
+                if (slot.Count > 0)
+                    expected_result.Add(slot);
+            }
+
+            //Prepare model
+            ThreadsControllerBase controller = (ThreadsControllerBase) Activator.CreateInstance(class_type, new object [] {false});
+            IOutputListener output_listener = controller.addOutputListener(output_ports.ToArray());
+
+            //Input
+            XElement input_xml = test_xml.Element("input");
+            if (input_xml != null)
+            {
+                foreach (XElement event_xml in input_xml.Elements("event"))
+                {
+                    controller.addInput(new Event(event_xml.Attribute("name").Value, event_xml.Attribute("port").Value), Convert.ToDouble(event_xml.Attribute("time").Value));
+                }
+            }
+
+            //Execute model
+            controller.start();
+            controller.join();
+
+            //Check output
+            for (int slot_index = 0; slot_index < expected_result.Count; slot_index++)
+            {
+                List<TestEvent> slot = expected_result[slot_index];
+                List<TestEvent> remaining_options = new List<TestEvent>(slot);
+                List<Event> received_output = new List<Event>();
+                while (remaining_options.Count > 0)
+                {
+                    Event output_event = output_listener.fetch();
+                    Assert.AreNotEqual(null, output_event,
+                                       string.Format("Expected results slot {0} mismatch. Expected [{1}], but got [{2}] followed by null instead.", slot_index, string.Join(", ", slot), string.Join(", ", received_output))
+                                       );
+                    received_output.Add(output_event);
+                    int i = 0;
+                    foreach (TestEvent option in remaining_options)
+                    {
+                        if (option.matches(output_event))
+                            break;
+                        i++;
+                    }
+                    //Mismath?
+                    Assert.AreNotEqual(remaining_options.Count,i,
+                                       string.Format("Expected results slot {0} mismatch. Expected [{1}], but got [{2}] instead.", slot_index, string.Join(", ", slot), string.Join(", ", received_output))
+                                       );
+                    remaining_options.RemoveAt(i);
+                }
+            }
+            //check if there are no extra events          
+            Assert.AreEqual(null, output_listener.fetch(), "More output events than expected on selected ports.");
+        }
+
+        [TearDown]
+        public void cleanup()
+        {
+            if (!keep_after_test && File.Exists(this.path_generated_code))
+            {
+                File.Delete(this.path_generated_code);
+            }
+        }
+
+        protected static IEnumerable GetTestCases()
+        {
+            foreach (string file_path in Directory.EnumerateFiles("../../../test_files"))
+            {
+                if (Path.GetExtension(file_path) == ".xml")
+                    yield return new TestCaseData(file_path).SetName(Path.GetFileNameWithoutExtension(file_path));
+            }
+        }
+    }
+}
+

+ 68 - 0
csharp_tests/csharp_tests.csproj

@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>10.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{EA55100B-CE22-4ACD-B132-443A30896D19}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>csharp_tests</RootNamespace>
+    <AssemblyName>csharp_tests</AssemblyName>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+    <UnitTestInformation>
+      <UnitTestInformation />
+    </UnitTestInformation>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="sccdlib">
+      <HintPath>..\csharp_runtime\bin\Debug\sccdlib.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Core" />
+    <Reference Include="nunit.framework, Version=2.6.0.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System.Xml" />
+    <Reference Include="csharp_sccd_compiler">
+      <HintPath>..\csharp_sccd_compiler\bin\Debug\csharp_sccd_compiler.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="CodeCompiler.cs" />
+    <Compile Include="TestEvent.cs" />
+    <Compile Include="TestsBase.cs" />
+    <Compile Include="PythonTests.cs" />
+    <Compile Include="CSharpTests.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ProjectExtensions>
+    <MonoDevelop>
+      <Properties>
+        <Policies>
+          <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" />
+        </Policies>
+      </Properties>
+    </MonoDevelop>
+  </ProjectExtensions>
+</Project>

+ 44 - 0
csharp_tests/csharp_tests.sln

@@ -0,0 +1,44 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp_tests", "csharp_tests.csproj", "{EA55100B-CE22-4ACD-B132-443A30896D19}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{EA55100B-CE22-4ACD-B132-443A30896D19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EA55100B-CE22-4ACD-B132-443A30896D19}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EA55100B-CE22-4ACD-B132-443A30896D19}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EA55100B-CE22-4ACD-B132-443A30896D19}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(MonoDevelopProperties) = preSolution
+		StartupItem = csharp_tests.csproj
+		Policies = $0
+		$0.TextStylePolicy = $1
+		$1.inheritsSet = VisualStudio
+		$1.inheritsScope = text/plain
+		$1.scope = text/x-csharp
+		$0.CSharpFormattingPolicy = $2
+		$2.IndentSwitchBody = True
+		$2.AnonymousMethodBraceStyle = NextLine
+		$2.PropertyBraceStyle = NextLine
+		$2.PropertyGetBraceStyle = NextLine
+		$2.PropertySetBraceStyle = NextLine
+		$2.EventBraceStyle = NextLine
+		$2.EventAddBraceStyle = NextLine
+		$2.EventRemoveBraceStyle = NextLine
+		$2.StatementBraceStyle = NextLine
+		$2.ArrayInitializerBraceStyle = NextLine
+		$2.BeforeMethodDeclarationParentheses = False
+		$2.BeforeMethodCallParentheses = False
+		$2.BeforeConstructorDeclarationParentheses = False
+		$2.BeforeDelegateDeclarationParentheses = False
+		$2.NewParentheses = False
+		$2.inheritsSet = Mono
+		$2.inheritsScope = text/x-csharp
+		$2.scope = text/x-csharp
+	EndGlobalSection
+EndGlobal

+ 138 - 0
examples/HTTP_client/classes/http_client.xml

@@ -0,0 +1,138 @@
+<class name="HTTPClient">
+    <relationships>
+        <association name="parent" class="Prompt" min="1" max="1"/>
+    </relationships>
+    <constructor>
+        <parameter name="hostname"/>
+        <parameter name="port"/>
+        <body>
+            <![CDATA[
+            self.socket = None
+            self.destination = (hostname, port)
+            self.received_data = ""
+            self.send_data = ""
+            self.queue = []
+            self.destinations = []
+            ]]>
+        </body>
+    </constructor>
+    <scxml initial="init">
+        <state id="init">
+            <onentry>
+                <raise scope="output" event="create_socket" output="socket_out"/>
+            </onentry>
+            <transition port="socket_in" event="created_socket" target="../connecting">
+                <parameter name="socket"/>
+                <script>
+                    self.socket = socket
+                </script>
+            </transition>
+        </state>
+        <state id="connecting">
+            <onentry>
+                <raise scope="output" event="connect_socket" output="socket_out">
+                    <parameter expr="self.socket"/>
+                    <parameter expr="self.destination"/>
+                </raise>
+            </onentry>
+            <transition port="socket_in" event="connected_socket" cond="self.socket == socket" target="../connected">
+                <parameter name="socket"/>
+                <raise scope="broad" event="http_client_ready"/>
+            </transition>
+        </state>
+                
+        <parallel id="connected">
+            <state id="listening" initial="listen">
+                <state id="listen">
+                    <onentry>
+                        <raise scope="output" port="socket_out" event="recv_socket">
+                            <parameter expr="self.socket"/>
+                        </raise>
+                    </onentry>
+                    <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) > 0)" target=".">
+                        <parameter name="socket"/>
+                        <parameter name="data"/>
+                        <script>
+                            self.received_data += data
+                        </script>
+                    </transition>
+                    <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) == 0)" target="../close">
+                        <parameter name="socket"/>
+                        <parameter name="data"/>
+                    </transition>
+                </state>
+                <state id="close">
+                </state>
+            </state>
+
+            <state id="sending" initial="waiting_for_data">
+                <state id="waiting_for_data">
+                    <transition cond="len(self.send_data) > 0" target="../transferring">
+                        <raise scope="output" port="socket_out" event="send_socket">
+                            <parameter expr="self.socket"/>
+                            <parameter expr="self.send_data"/>
+                        </raise>
+                    </transition>
+                </state>
+                <state id="transferring">
+                    <transition event="sent_socket" port="socket_in" cond="self.socket == socket" target="../waiting_for_data">
+                        <parameter name="socket"/>
+                        <parameter name="sent_bytes"/>
+                        <script>
+                            self.send_data = self.send_data[sent_bytes:]
+                        </script>
+                    </transition>
+                </state>
+            </state>
+
+            <state id="queueing">
+                <state id="queueing">
+                    <onentry>
+                    </onentry>
+                    <transition event="HTTP_input" target=".">
+                        <parameter name="data"/>
+                        <parameter name="destination"/>
+                        <script>
+                            self.send_data += "POST / HTTP/1.0\r\n"
+                            self.send_data += "Content-Length: %i\r\n" % len(str(data))
+                            self.send_data += "\r\n"
+                            self.send_data += data
+                            self.destinations.append(destination)
+                        </script>
+                    </transition>
+                </state>
+            </state>
+
+            <state id="parsing" initial="wait_for_header">
+                <state id="wait_for_header">
+                    <transition cond="'\r\n\r\n' in self.received_data" target="../wait_for_payload">
+                        <script>
+                            header, self.received_data = self.received_data.split("\r\n\r\n", 1)
+                            header = header.lower()
+                            if "content-length" in header:
+                                _, after = header.split("content-length:", 1)
+                                after, _ = after.split("\r\n", 1)
+                                after = after.strip()
+                                self.length = int(after)
+                            else:
+                                self.length = float('inf')
+                        </script>
+                    </transition>
+                </state>
+                <state id="wait_for_payload">
+                    <transition cond="len(self.received_data) >= self.length" target="../wait_for_header">
+                        <script>
+                            data = self.received_data[:self.length]
+                            self.received_data = self.received_data[self.length:]
+                            #params = dict([p.split('=') for p in data.split('&amp;')])
+                            #data = {k: urllib.unquote_plus(v) for k, v in params.iteritems()}
+                        </script>
+                        <raise event="HTTP_output" scope="narrow" target="self.destinations.pop(0)">
+                            <parameter expr="data"/>
+                        </raise>
+                    </transition>
+                </state>
+            </state>
+        </parallel>
+    </scxml>
+</class>

+ 58 - 0
examples/HTTP_client/classes/prompt.xml

@@ -0,0 +1,58 @@
+<class name="Prompt">
+    <relationships>
+        <association name="to_server" class="HTTPClient" min="1" max="1"/>
+    </relationships>
+    <constructor>
+        <body>
+            self.counter = 0
+        </body>
+    </constructor>
+    <scxml initial="init">
+        <state id="init">
+            <onentry>
+                <raise scope="cd" event="create_instance">
+                    <parameter expr="'to_server'"/>
+                    <parameter expr="'HTTPClient'"/>
+                    <parameter expr="'127.0.0.1'"/>
+                    <parameter expr="8080"/>
+                </raise>
+            </onentry>
+            <transition event="instance_created" target="../initializing">
+                <parameter name="instancename"/>
+                <raise scope="cd" event="start_instance">
+                    <parameter expr="instancename"/>
+                </raise>
+            </transition>
+        </state>
+
+        <state id="initializing">
+            <!-- This is only there because otherwise the thread might stop; this seems like a bug in the runtime though -->
+            <transition after="1.0" target="."/>
+            <transition event="http_client_ready" target="../send_request"/>
+        </state>
+
+        <state id="send_request">
+            <transition after="1" target="../wait_reply">
+                <raise event="HTTP_input" scope="narrow" target="'to_server'">
+                    <parameter expr="str(self.counter)"/>
+                    <parameter expr="'parent'"/>
+                </raise>
+                <script>
+                    print("Sending request: %s" % self.counter)
+                    self.counter += 1
+                </script>
+            </transition>
+        </state>
+
+        <state id="wait_reply">
+            <!-- This is only there because otherwise the thread might stop; this seems like a bug in the runtime though -->
+            <transition after="1.0" target="."/>
+            <transition event="HTTP_output" target="../send_request">
+                <parameter name="data"/>
+                <script>
+                    print("Got response: %s" % data)
+                </script>
+            </transition>
+        </state>
+    </scxml>
+</class>

+ 422 - 0
examples/HTTP_client/client.py

@@ -0,0 +1,422 @@
+"""
+Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
+
+Date:   Wed Aug 03 17:03:50 2016
+
+Model author: Yentl Van Tendeloo
+Model name:   HTTP client
+Model description:
+HTTP client in SCCD
+"""
+
+from python_runtime.statecharts_core import *
+import time
+import os
+import urllib
+import sys
+import json
+
+# package "HTTP client"
+
+class Prompt(RuntimeClassBase):
+    def __init__(self, controller):
+        RuntimeClassBase.__init__(self, controller)
+        
+        self.semantics.big_step_maximality = StatechartSemantics.TakeMany
+        self.semantics.internal_event_lifeline = StatechartSemantics.Queue
+        self.semantics.input_event_lifeline = StatechartSemantics.FirstComboStep
+        self.semantics.priority = StatechartSemantics.SourceParent
+        self.semantics.concurrency = StatechartSemantics.Single
+        
+        # build Statechart structure
+        self.build_statechart_structure()
+        
+        # call user defined constructor
+        Prompt.user_defined_constructor(self)
+    
+    def user_defined_constructor(self):
+        self.counter = 0
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, self)
+        
+        # state /init
+        self.states["/init"] = State(1, self)
+        self.states["/init"].setEnter(self._init_enter)
+        
+        # state /initializing
+        self.states["/initializing"] = State(2, self)
+        self.states["/initializing"].setEnter(self._initializing_enter)
+        self.states["/initializing"].setExit(self._initializing_exit)
+        
+        # state /send_request
+        self.states["/send_request"] = State(3, self)
+        self.states["/send_request"].setEnter(self._send_request_enter)
+        self.states["/send_request"].setExit(self._send_request_exit)
+        
+        # state /wait_reply
+        self.states["/wait_reply"] = State(4, self)
+        self.states["/wait_reply"].setEnter(self._wait_reply_enter)
+        self.states["/wait_reply"].setExit(self._wait_reply_exit)
+        
+        # add children
+        self.states[""].addChild(self.states["/init"])
+        self.states[""].addChild(self.states["/initializing"])
+        self.states[""].addChild(self.states["/send_request"])
+        self.states[""].addChild(self.states["/wait_reply"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/init"]
+        
+        # transition /init
+        _init_0 = Transition(self, self.states["/init"], [self.states["/initializing"]])
+        _init_0.setAction(self._init_0_exec)
+        _init_0.trigger = Event("instance_created", None)
+        self.states["/init"].addTransition(_init_0)
+        
+        # transition /initializing
+        _initializing_0 = Transition(self, self.states["/initializing"], [self.states["/initializing"]])
+        _initializing_0.trigger = Event("_0after")
+        self.states["/initializing"].addTransition(_initializing_0)
+        _initializing_1 = Transition(self, self.states["/initializing"], [self.states["/send_request"]])
+        _initializing_1.trigger = Event("http_client_ready", None)
+        self.states["/initializing"].addTransition(_initializing_1)
+        
+        # transition /send_request
+        _send_request_0 = Transition(self, self.states["/send_request"], [self.states["/wait_reply"]])
+        _send_request_0.setAction(self._send_request_0_exec)
+        _send_request_0.trigger = Event("_1after")
+        self.states["/send_request"].addTransition(_send_request_0)
+        
+        # transition /wait_reply
+        _wait_reply_0 = Transition(self, self.states["/wait_reply"], [self.states["/wait_reply"]])
+        _wait_reply_0.trigger = Event("_2after")
+        self.states["/wait_reply"].addTransition(_wait_reply_0)
+        _wait_reply_1 = Transition(self, self.states["/wait_reply"], [self.states["/send_request"]])
+        _wait_reply_1.setAction(self._wait_reply_1_exec)
+        _wait_reply_1.trigger = Event("HTTP_output", None)
+        self.states["/wait_reply"].addTransition(_wait_reply_1)
+    
+    def _init_enter(self):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, 'to_server', 'HTTPClient', '127.0.0.1', 8080]))
+    
+    def _initializing_enter(self):
+        self.addTimer(0, 1.0)
+    
+    def _initializing_exit(self):
+        self.removeTimer(0)
+    
+    def _send_request_enter(self):
+        self.addTimer(1, 1)
+    
+    def _send_request_exit(self):
+        self.removeTimer(1)
+    
+    def _wait_reply_enter(self):
+        self.addTimer(2, 1.0)
+    
+    def _wait_reply_exit(self):
+        self.removeTimer(2)
+    
+    def _init_0_exec(self, parameters):
+        instancename = parameters[0]
+        self.big_step.outputEventOM(Event("start_instance", None, [self, instancename]))
+    
+    def _send_request_0_exec(self, parameters):
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'to_server', Event("HTTP_input", None, [str(self.counter), 'parent'])]))
+        print("Sending request: %s" % self.counter)
+        self.counter += 1
+    
+    def _wait_reply_1_exec(self, parameters):
+        data = parameters[0]
+        print("Got response: %s" % data)
+    
+    def initializeStatechart(self):
+        # enter default state
+        states = self.states["/init"].getEffectiveTargetStates()
+        self.updateConfiguration(states)
+        for state in states:
+            if state.enter:
+                state.enter()
+
+class HTTPClient(RuntimeClassBase):
+    def __init__(self, controller, hostname, port):
+        RuntimeClassBase.__init__(self, controller)
+        
+        self.semantics.big_step_maximality = StatechartSemantics.TakeMany
+        self.semantics.internal_event_lifeline = StatechartSemantics.Queue
+        self.semantics.input_event_lifeline = StatechartSemantics.FirstComboStep
+        self.semantics.priority = StatechartSemantics.SourceParent
+        self.semantics.concurrency = StatechartSemantics.Single
+        
+        # build Statechart structure
+        self.build_statechart_structure()
+        
+        # call user defined constructor
+        HTTPClient.user_defined_constructor(self, hostname, port)
+    
+    def user_defined_constructor(self, hostname, port):
+        self.socket = None
+        self.destination = (hostname, port)
+        self.received_data = ""
+        self.send_data = ""
+        self.queue = []
+        self.destinations = []
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, self)
+        
+        # state /init
+        self.states["/init"] = State(1, self)
+        self.states["/init"].setEnter(self._init_enter)
+        
+        # state /connecting
+        self.states["/connecting"] = State(2, self)
+        self.states["/connecting"].setEnter(self._connecting_enter)
+        
+        # state /connected
+        self.states["/connected"] = ParallelState(3, self)
+        
+        # state /connected/listening
+        self.states["/connected/listening"] = State(4, self)
+        
+        # state /connected/listening/listen
+        self.states["/connected/listening/listen"] = State(5, self)
+        self.states["/connected/listening/listen"].setEnter(self._connected_listening_listen_enter)
+        
+        # state /connected/listening/close
+        self.states["/connected/listening/close"] = State(6, self)
+        
+        # state /connected/sending
+        self.states["/connected/sending"] = State(7, self)
+        
+        # state /connected/sending/waiting_for_data
+        self.states["/connected/sending/waiting_for_data"] = State(8, self)
+        
+        # state /connected/sending/transferring
+        self.states["/connected/sending/transferring"] = State(9, self)
+        
+        # state /connected/queueing
+        self.states["/connected/queueing"] = State(10, self)
+        
+        # state /connected/queueing/queueing
+        self.states["/connected/queueing/queueing"] = State(11, self)
+        self.states["/connected/queueing/queueing"].setEnter(self._connected_queueing_queueing_enter)
+        
+        # state /connected/parsing
+        self.states["/connected/parsing"] = State(12, self)
+        
+        # state /connected/parsing/wait_for_header
+        self.states["/connected/parsing/wait_for_header"] = State(13, self)
+        
+        # state /connected/parsing/wait_for_payload
+        self.states["/connected/parsing/wait_for_payload"] = State(14, self)
+        
+        # add children
+        self.states[""].addChild(self.states["/init"])
+        self.states[""].addChild(self.states["/connecting"])
+        self.states[""].addChild(self.states["/connected"])
+        self.states["/connected"].addChild(self.states["/connected/listening"])
+        self.states["/connected"].addChild(self.states["/connected/sending"])
+        self.states["/connected"].addChild(self.states["/connected/queueing"])
+        self.states["/connected"].addChild(self.states["/connected/parsing"])
+        self.states["/connected/listening"].addChild(self.states["/connected/listening/listen"])
+        self.states["/connected/listening"].addChild(self.states["/connected/listening/close"])
+        self.states["/connected/sending"].addChild(self.states["/connected/sending/waiting_for_data"])
+        self.states["/connected/sending"].addChild(self.states["/connected/sending/transferring"])
+        self.states["/connected/queueing"].addChild(self.states["/connected/queueing/queueing"])
+        self.states["/connected/parsing"].addChild(self.states["/connected/parsing/wait_for_header"])
+        self.states["/connected/parsing"].addChild(self.states["/connected/parsing/wait_for_payload"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/init"]
+        self.states["/connected/listening"].default_state = self.states["/connected/listening/listen"]
+        self.states["/connected/sending"].default_state = self.states["/connected/sending/waiting_for_data"]
+        self.states["/connected/queueing"].default_state = self.states["/connected/queueing/queueing"]
+        self.states["/connected/parsing"].default_state = self.states["/connected/parsing/wait_for_header"]
+        
+        # transition /init
+        _init_0 = Transition(self, self.states["/init"], [self.states["/connecting"]])
+        _init_0.setAction(self._init_0_exec)
+        _init_0.trigger = Event("created_socket", "socket_in")
+        self.states["/init"].addTransition(_init_0)
+        
+        # transition /connecting
+        _connecting_0 = Transition(self, self.states["/connecting"], [self.states["/connected"]])
+        _connecting_0.setAction(self._connecting_0_exec)
+        _connecting_0.trigger = Event("connected_socket", "socket_in")
+        _connecting_0.setGuard(self._connecting_0_guard)
+        self.states["/connecting"].addTransition(_connecting_0)
+        
+        # transition /connected/listening/listen
+        _connected_listening_listen_0 = Transition(self, self.states["/connected/listening/listen"], [self.states["/connected/listening/listen"]])
+        _connected_listening_listen_0.setAction(self._connected_listening_listen_0_exec)
+        _connected_listening_listen_0.trigger = Event("received_socket", "socket_in")
+        _connected_listening_listen_0.setGuard(self._connected_listening_listen_0_guard)
+        self.states["/connected/listening/listen"].addTransition(_connected_listening_listen_0)
+        _connected_listening_listen_1 = Transition(self, self.states["/connected/listening/listen"], [self.states["/connected/listening/close"]])
+        _connected_listening_listen_1.trigger = Event("received_socket", "socket_in")
+        _connected_listening_listen_1.setGuard(self._connected_listening_listen_1_guard)
+        self.states["/connected/listening/listen"].addTransition(_connected_listening_listen_1)
+        
+        # transition /connected/sending/waiting_for_data
+        _connected_sending_waiting_for_data_0 = Transition(self, self.states["/connected/sending/waiting_for_data"], [self.states["/connected/sending/transferring"]])
+        _connected_sending_waiting_for_data_0.setAction(self._connected_sending_waiting_for_data_0_exec)
+        _connected_sending_waiting_for_data_0.setGuard(self._connected_sending_waiting_for_data_0_guard)
+        self.states["/connected/sending/waiting_for_data"].addTransition(_connected_sending_waiting_for_data_0)
+        
+        # transition /connected/sending/transferring
+        _connected_sending_transferring_0 = Transition(self, self.states["/connected/sending/transferring"], [self.states["/connected/sending/waiting_for_data"]])
+        _connected_sending_transferring_0.setAction(self._connected_sending_transferring_0_exec)
+        _connected_sending_transferring_0.trigger = Event("sent_socket", "socket_in")
+        _connected_sending_transferring_0.setGuard(self._connected_sending_transferring_0_guard)
+        self.states["/connected/sending/transferring"].addTransition(_connected_sending_transferring_0)
+        
+        # transition /connected/queueing/queueing
+        _connected_queueing_queueing_0 = Transition(self, self.states["/connected/queueing/queueing"], [self.states["/connected/queueing/queueing"]])
+        _connected_queueing_queueing_0.setAction(self._connected_queueing_queueing_0_exec)
+        _connected_queueing_queueing_0.trigger = Event("HTTP_input", None)
+        self.states["/connected/queueing/queueing"].addTransition(_connected_queueing_queueing_0)
+        
+        # transition /connected/parsing/wait_for_header
+        _connected_parsing_wait_for_header_0 = Transition(self, self.states["/connected/parsing/wait_for_header"], [self.states["/connected/parsing/wait_for_payload"]])
+        _connected_parsing_wait_for_header_0.setAction(self._connected_parsing_wait_for_header_0_exec)
+        _connected_parsing_wait_for_header_0.setGuard(self._connected_parsing_wait_for_header_0_guard)
+        self.states["/connected/parsing/wait_for_header"].addTransition(_connected_parsing_wait_for_header_0)
+        
+        # transition /connected/parsing/wait_for_payload
+        _connected_parsing_wait_for_payload_0 = Transition(self, self.states["/connected/parsing/wait_for_payload"], [self.states["/connected/parsing/wait_for_header"]])
+        _connected_parsing_wait_for_payload_0.setAction(self._connected_parsing_wait_for_payload_0_exec)
+        _connected_parsing_wait_for_payload_0.setGuard(self._connected_parsing_wait_for_payload_0_guard)
+        self.states["/connected/parsing/wait_for_payload"].addTransition(_connected_parsing_wait_for_payload_0)
+    
+    def _init_enter(self):
+        self.big_step.outputEvent(Event("create_socket", "", []))
+    
+    def _connecting_enter(self):
+        self.big_step.outputEvent(Event("connect_socket", "", [self.socket, self.destination]))
+    
+    def _connected_listening_listen_enter(self):
+        self.big_step.outputEvent(Event("recv_socket", "socket_out", [self.socket]))
+    
+    def _connected_queueing_queueing_enter(self):
+        pass
+    
+    def _init_0_exec(self, parameters):
+        socket = parameters[0]
+        self.socket = socket
+    
+    def _connecting_0_exec(self, parameters):
+        socket = parameters[0]
+        self.big_step.outputEventOM(Event("broad_cast", None, [Event("http_client_ready", None, [])]))
+    
+    def _connecting_0_guard(self, parameters):
+        socket = parameters[0]
+        return self.socket == socket
+    
+    def _connected_listening_listen_0_exec(self, parameters):
+        socket = parameters[0]
+        data = parameters[1]
+        self.received_data += data
+    
+    def _connected_listening_listen_0_guard(self, parameters):
+        socket = parameters[0]
+        data = parameters[1]
+        return (self.socket == socket) and (len(data) > 0)
+    
+    def _connected_listening_listen_1_guard(self, parameters):
+        socket = parameters[0]
+        data = parameters[1]
+        return (self.socket == socket) and (len(data) == 0)
+    
+    def _connected_sending_waiting_for_data_0_exec(self, parameters):
+        self.big_step.outputEvent(Event("send_socket", "socket_out", [self.socket, self.send_data]))
+    
+    def _connected_sending_waiting_for_data_0_guard(self, parameters):
+        return len(self.send_data) > 0
+    
+    def _connected_sending_transferring_0_exec(self, parameters):
+        socket = parameters[0]
+        sent_bytes = parameters[1]
+        self.send_data = self.send_data[sent_bytes:]
+    
+    def _connected_sending_transferring_0_guard(self, parameters):
+        socket = parameters[0]
+        sent_bytes = parameters[1]
+        return self.socket == socket
+    
+    def _connected_queueing_queueing_0_exec(self, parameters):
+        data = parameters[0]
+        destination = parameters[1]
+        self.send_data += "POST / HTTP/1.0\r\n"
+        self.send_data += "Content-Length: %i\r\n" % len(str(data))
+        self.send_data += "\r\n"
+        self.send_data += data
+        self.destinations.append(destination)
+    
+    def _connected_parsing_wait_for_header_0_exec(self, parameters):
+        header, self.received_data = self.received_data.split("\r\n\r\n", 1)
+        header = header.lower()
+        if "content-length" in header:
+            _, after = header.split("content-length:", 1)
+            after, _ = after.split("\r\n", 1)
+            after = after.strip()
+            self.length = int(after)
+        else:
+            self.length = float('inf')
+    
+    def _connected_parsing_wait_for_header_0_guard(self, parameters):
+        return '\r\n\r\n' in self.received_data
+    
+    def _connected_parsing_wait_for_payload_0_exec(self, parameters):
+        data = self.received_data[:self.length]
+        self.received_data = self.received_data[self.length:]
+        #params = dict([p.split('=') for p in data.split('&')])
+        #data = {k: urllib.unquote_plus(v) for k, v in params.iteritems()}
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, self.destinations.pop(0), Event("HTTP_output", None, [data])]))
+    
+    def _connected_parsing_wait_for_payload_0_guard(self, parameters):
+        return len(self.received_data) >= self.length
+    
+    def initializeStatechart(self):
+        # enter default state
+        states = self.states["/init"].getEffectiveTargetStates()
+        self.updateConfiguration(states)
+        for state in states:
+            if state.enter:
+                state.enter()
+
+class ObjectManager(ObjectManagerBase):
+    def __init__(self, controller):
+        ObjectManagerBase.__init__(self, controller)
+    
+    def instantiate(self, class_name, construct_params):
+        if class_name == "Prompt":
+            instance = Prompt(self.controller)
+            instance.associations = {}
+            instance.associations["to_server"] = Association("HTTPClient", 1, 1)
+        elif class_name == "HTTPClient":
+            instance = HTTPClient(self.controller, construct_params[0], construct_params[1])
+            instance.associations = {}
+            instance.associations["parent"] = Association("Prompt", 1, 1)
+        return instance
+
+class Controller(ThreadsControllerBase):
+    def __init__(self, keep_running = None):
+        if keep_running == None: keep_running = True
+        ThreadsControllerBase.__init__(self, ObjectManager(self), keep_running)
+        self.addInputPort("socket_in")
+        self.addOutputPort("socket_out")
+        self.object_manager.createInstance("Prompt", [])

+ 19 - 0
examples/HTTP_client/client.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<diagram author="Yentl Van Tendeloo" name="HTTP client">
+    <description>
+        HTTP client in SCCD
+    </description>
+    <top>
+        import time
+        import os
+        import urllib
+        import sys
+        import json
+    </top>
+
+    <inport name="socket_in"/>
+    <outport name="socket_out"/>
+
+    <class src="classes/prompt.xml" default="true"/>
+    <class src="classes/http_client.xml"/>
+</diagram>

+ 1 - 0
examples/HTTP_client/make.bat

@@ -0,0 +1 @@
+..\..\python_sccd_compiler\sccdc.py -p threads -l python client.xml

+ 4 - 0
examples/HTTP_client/run.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+set -e
+./compile.sh
+python run_mvk_server.py $1

+ 8 - 0
examples/HTTP_client/run_client.py

@@ -0,0 +1,8 @@
+import sys
+
+import client
+import socket2event
+
+controller = client.Controller(sys.argv[1:])
+socket2event.boot_translation_service(controller)
+controller.start()

+ 117 - 0
examples/HTTP_client/socket2event.py

@@ -0,0 +1,117 @@
+import threading
+from python_runtime.statecharts_core import Event
+import socket
+
+send_data_queues = {}
+send_events = {}
+recv_events = {}
+run_sockets = {}
+
+def start_socket_threads(controller, sock):
+    recv_events[sock] = recv_event = threading.Event()
+    send_events[sock] = send_event = threading.Event()
+    send_data_queues[sock] = send_data_queue = []
+    run_sockets[sock] = True
+
+    thrd = threading.Thread(target=receive_from_socket, args=[controller, sock, recv_event])
+    thrd.daemon = True
+    thrd.start()
+
+    thrd = threading.Thread(target=send_to_socket, args=[controller, sock, send_data_queue, send_event])
+    thrd.daemon = True
+    thrd.start()
+
+def receive_from_socket(controller, sock, recv_event):
+    while 1:
+        recv_event.wait()
+        recv_event.clear()
+        if not run_sockets[sock]:
+            break
+        data = sock.recv(2**16)
+        controller.addInput(Event("received_socket", "socket_in", [sock, data]))
+
+def send_to_socket(controller, sock, data_queue, send_event):
+    while run_sockets[sock]:
+        send_event.wait()
+        send_event.clear()
+        while data_queue:
+            send = sock.send(data_queue.pop(0))
+            controller.addInput(Event("sent_socket", "socket_in", [sock, send]))
+        if not run_sockets[sock]:
+            break
+
+def _accept(controller, sock):
+    conn, addr = sock.accept()
+    start_socket_threads(controller, conn)
+    controller.addInput(Event("accepted_socket", "socket_in", [sock, conn]))
+
+def _connect(controller, sock, destination):
+    sock.connect(destination)
+    controller.addInput(Event("connected_socket", "socket_in", [sock]))
+
+def _close(controller, sock):
+    run_sockets[sock] = False
+    send_events[sock].set()
+    recv_events[sock].set()
+    sock.close()
+    controller.addInput(Event("closed_socket", "socket_in", [sock]))
+
+def _bind(controller, sock, addr):
+    sock.bind(addr)
+    controller.addInput(Event("bound_socket", "socket_in", [sock]))
+
+def _listen(controller, sock):
+    sock.listen(1)
+    controller.addInput(Event("listened_socket", "socket_in", [sock]))
+
+def _wrapper_func(*args):
+    func = args[0]
+    controller = args[1]
+    sock = args[2]
+    try:
+        func(*args[1:])
+    except socket.error as e:
+        print("ERROR " + str(e))
+        controller.addInput(Event("error_socket", "socket_in", [sock, e]))
+    except Exception as e:
+        print("UNKNOWN ERROR " + str(e))
+        controller.addInput(Event("unknown_error_socket", "socket_in", [sock, e]))
+
+def _start_on_daemon_thread(func, args):
+    new_args = [func]
+    new_args.extend(args)
+    args = new_args
+    thrd = threading.Thread(target=_wrapper_func, args=args)
+    thrd.daemon = True
+    thrd.start()
+
+def boot_translation_service(controller):
+    _start_on_daemon_thread(_poll, [controller, None])
+
+def _poll(controller, _):
+    socket_out = controller.addOutputListener("socket_out")
+    while 1:
+        evt = socket_out.fetch(-1)
+        name, params = evt.getName(), evt.getParameters()
+        if name == "accept_socket":
+            _start_on_daemon_thread(_accept, [controller, params[0]])
+        elif name == "recv_socket":
+            recv_events[params[0]].set()
+        elif name == "connect_socket":
+            _start_on_daemon_thread(_connect, [controller, params[0], params[1]])
+        elif name == "create_socket":
+            sock = socket.socket()
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            start_socket_threads(controller, sock)
+            controller.addInput(Event("created_socket", "socket_in", [sock]))
+        elif name == "close_socket":
+            _start_on_daemon_thread(_close, [controller, params[0]])
+        elif name == "send_socket":
+            send_data_queues[params[0]].append(params[1])
+            send_events[params[0]].set()
+        elif name == "bind_socket":
+            _start_on_daemon_thread(_bind, [controller, params[0], params[1]])
+        elif name == "listen_socket":
+            _start_on_daemon_thread(_listen, [controller, params[0]])
+        elif name == "stop":
+            break

+ 47 - 0
examples/HTTP_server/classes/echo.xml

@@ -0,0 +1,47 @@
+<class name="Echo">
+    <relationships>
+        <association name="to_server" class="Server" min="1" max="1"/>
+    </relationships>
+    <constructor>
+        <parameter name="params"/>
+        <body>
+            <![CDATA[
+            self.source = None
+            ]]>
+        </body>
+    </constructor>
+
+    <scxml initial="init_server">
+        <state id="init_server">
+            <onentry>
+                <raise scope="cd" event="create_instance">
+                    <parameter expr="'to_server'"/>
+                    <parameter expr="'Server'"/>
+                    <parameter expr="''"/>
+                    <parameter expr="8080"/>
+                </raise>
+            </onentry>
+            <transition event="instance_created" target="../wait_for_requests">
+                <parameter name="instancename"/>
+                <raise scope="cd" event="start_instance">
+                    <parameter expr="instancename"/>
+                </raise>
+            </transition>
+        </state>
+
+        <state id="wait_for_requests">
+            <state id="wait">
+                <transition event="HTTP_output" target=".">
+                    <parameter name="source"/>
+                    <parameter name="data"/>
+                    <script>
+                        print("Got input: " + str(data))
+                    </script>
+                    <raise event="HTTP_input" scope="narrow" target="'to_server/%s' % source">
+                        <parameter expr="data"/>
+                    </raise>
+                </transition>
+            </state>
+        </state>
+    </scxml>
+</class>

+ 110 - 0
examples/HTTP_server/classes/server.xml

@@ -0,0 +1,110 @@
+<class name="Server">
+    <relationships>
+        <association name="sockets" class="Socket"/>
+        <association name="parent" class="Echo" min="1" max="1"/>
+    </relationships>
+    <constructor>
+        <parameter name="address"/>
+        <parameter name="port"/>
+        <body>
+            <![CDATA[
+            self.socket = None
+            self.address = address
+            self.port = port
+            ]]>
+        </body>
+    </constructor>
+
+    <scxml initial="main">
+        <parallel id="main">
+            <state id="forward">
+                <state id="forward">
+                    <transition event="HTTP_output" target=".">
+                        <parameter name="association_name"/>
+                        <parameter name="data"/>
+                        <script>
+                            print("Forward")
+                        </script>
+                        <raise event="HTTP_output" scope="narrow" target="'parent'">
+                            <parameter expr="association_name"/>
+                            <parameter expr="data"/>
+                        </raise>
+                    </transition>
+                </state>
+            </state>
+
+            <state id="server" initial="init">
+                <state id="init">
+                    <onentry>
+                        <raise scope="output" event="create_socket" port="socket_out"/>
+                    </onentry>
+                    <transition port="socket_in" event="created_socket" target="../binding">
+                        <parameter name="socket"/>
+                        <script>
+                            self.socket = socket
+                        </script>
+                    </transition>
+                </state>
+                <state id="binding">
+                    <onentry>
+                        <raise scope="output" event="bind_socket" port="socket_out">
+                            <parameter expr="self.socket"/>
+                            <parameter expr="(self.address, self.port)"/>
+                        </raise>
+                    </onentry>
+                    <transition port="socket_in" event="bound_socket" cond="self.socket == socket" target="../listening">
+                        <parameter name="socket"/>
+                    </transition>
+                </state>
+                <state id="listening">
+                    <onentry>
+                        <raise scope="output" event="listen_socket" port="socket_out">
+                            <parameter expr="self.socket"/>
+                        </raise>
+                    </onentry>
+                    <transition port="socket_in" event="listened_socket" cond="self.socket == socket" target="../accepting">
+                        <parameter name="socket"/>
+                        <raise scope="output" port="socket_out" event="accept_socket">
+                            <parameter expr="self.socket"/>
+                        </raise>
+                    </transition>
+                </state>
+                <state id="accepting">
+                    <transition port="socket_in" event="accepted_socket" target=".">
+                        <parameter name="socket"/>
+                        <parameter name="connected_socket"/>
+                        <raise scope="cd" event="create_instance">
+                            <parameter expr="'sockets'" />
+                            <parameter expr="'Socket'" />
+                            <parameter expr="connected_socket" />
+                        </raise>
+                        <raise scope="output" port="socket_out" event="accept_socket">
+                            <parameter expr="self.socket"/>
+                        </raise>
+                    </transition>
+                    <transition event="instance_created" target=".">
+                        <parameter name="instancename"/>
+                        <raise scope="cd" event="start_instance">
+                            <parameter expr="instancename" />
+                        </raise>
+                        <raise scope="narrow" event="set_association_name" target="instancename">
+                            <parameter expr="instancename"/>
+                        </raise>
+                    </transition>
+                    <transition after="1.0" target="."/>
+                </state>
+            </state>
+
+            <state id="close_socket">
+                <state id="close">
+                    <transition event="close_socket" target=".">
+                        <parameter name="association_name"/>
+                        <raise scope="cd" event="delete_instance">
+                            <parameter expr="association_name"/>
+                        </raise>
+                    </transition>
+                </state>
+            </state>
+        </parallel>
+    </scxml>
+</class>

+ 157 - 0
examples/HTTP_server/classes/socket.xml

@@ -0,0 +1,157 @@
+<class name="Socket">
+    <relationships>
+        <association name="parent" class="Server" min="1" max="1"/>
+    </relationships>
+
+    <constructor>
+        <parameter name="my_socket"/>
+        <body>
+            <![CDATA[
+            self.socket = my_socket
+            self.received_data = ""
+            self.send_data = ""
+            self.closed = False
+            self.association_name = None
+            ]]>
+        </body>
+    </constructor>
+    <scxml initial="init">
+        <state id="init">
+            <transition event="set_association_name" target="../connected">
+                <parameter name="association_name"/>
+                <script>
+                    self.association_name = association_name
+                </script>
+            </transition>
+        </state>
+        <parallel id="connected">
+            <state id="listening" initial="listen">
+                <state id="listen">
+                    <onentry>
+                        <raise scope="output" port="socket_out" event="recv_socket">
+                            <parameter expr="self.socket"/>
+                        </raise>
+                    </onentry>
+                    <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) > 0)" target=".">
+                        <parameter name="socket"/>
+                        <parameter name="data"/>
+                        <script>
+                            self.received_data += data
+                        </script>
+                        <raise event="received_data"/>
+                    </transition>
+                    <transition event="received_socket" port="socket_in" cond="(self.socket == socket) and (len(data) == 0)" target="../closed">
+                        <parameter name="socket"/>
+                        <parameter name="data"/>
+                        <raise event="received_data"/>
+                    </transition>
+                </state>
+                <state id="closed">
+                    <onentry>
+                        <script>
+                            self.closed = True
+                        </script>
+                    </onentry>
+                </state>
+            </state>
+
+            <state id="sending" initial="waiting_for_data">
+                <state id="waiting_for_data">
+                    <transition cond="len(self.send_data) > 0" target="../transferring">
+                        <raise scope="output" port="socket_out" event="send_socket">
+                            <parameter expr="self.socket"/>
+                            <parameter expr="self.send_data"/>
+                        </raise>
+                    </transition>
+                </state>
+                <state id="transferring">
+                    <transition event="sent_socket" port="socket_in" cond="self.socket == socket" target="../waiting_for_data">
+                        <parameter name="socket"/>
+                        <parameter name="sent_bytes"/>
+                        <script>
+                            self.send_data = self.send_data[sent_bytes:]
+                        </script>
+                    </transition>
+                </state>
+            </state>
+
+            <state id="queueing">
+                <state id="queueing">
+                    <transition event="HTTP_input" target=".">
+                        <parameter name="data"/>
+                        <script>
+                            #post_data = "&amp;".join(["%s=%s" % (urllib.quote(k), urllib.quote(v)) for k, v in data.iteritems()])
+                            #post_data = "&amp;".join(["%s=%s" % (k, v) for k, v in data.iteritems()])
+                            post_data = data
+                            self.send_data += "HTTP/1.0 200 OK\r\n"
+                            self.send_data += "Content-Length: %s\r\n" % len(post_data)
+                            self.send_data += "Content-Type: %s; charset=UTF-8\r\n" % "text/plain"
+                            self.send_data += "\r\n"
+                            self.send_data += str(post_data)
+                        </script>
+                    </transition>
+                </state>
+            </state>
+
+            <state id="parsing" initial="wait_for_header">
+                <state id="wait_for_header">
+                    <transition cond="'\r\n\r\n' in self.received_data and self.received_data.startswith('POST')" target="../wait_for_payload">
+                        <script>
+                            header, self.received_data = self.received_data.split("\r\n\r\n", 1)
+                            header = header.lower()
+                            if "content-length" in header:
+                                _, after = header.split("content-length:", 1)
+                                after = after.split("\r\n", 1)[0]
+                                after = after.strip()
+                                self.length = int(after)
+                            else:
+                                self.length = float('inf')
+                        </script>
+                    </transition>
+                    <transition cond="self.closed and len(self.received_data) == 0" target="../closing"/>
+                </state>
+                <state id="closing">
+                    <transition after="0.0" target=".">
+                        <raise event="close"/>
+                    </transition>
+                </state>
+                <state id="wait_for_payload">
+                    <transition cond="len(self.received_data) >= self.length or self.closed" target="../wait_for_header">
+                        <script>
+                            if self.length == float('inf'):
+                                data = self.received_data
+                                self.received_data = ""
+                            else:
+                                data = self.received_data[:self.length]
+                                self.received_data = self.received_data[self.length:]
+
+                            print("Got data: " + str(data))
+
+                            # We support POST data only, so everything is in the data
+                            #try:
+                            #    params = dict([p.split('=') for p in data.split('&amp;')])
+                            #    data = {k: urllib.unquote_plus(v) for k, v in params.iteritems()}
+                            #except:
+                            #    data = {}
+                        </script>
+                        <raise event="HTTP_output" scope="narrow" target="'parent'">
+                            <parameter expr="self.association_name"/>
+                            <parameter expr="data"/>
+                        </raise>
+                    </transition>
+                </state>
+            </state>
+            <transition event="close" target="../close"/>
+        </parallel>
+        <state id="close">
+            <onentry>
+                <raise port="socket_out" event="close_socket">
+                    <parameter expr="self.socket"/>
+                </raise>
+                <raise scope="narrow" target="'parent'" event="close_socket">
+                    <parameter expr="self.association_name"/>
+                </raise>
+            </onentry>
+        </state>
+    </scxml>
+</class>

+ 1 - 0
examples/HTTP_server/make.bat

@@ -0,0 +1 @@
+..\..\python_sccd_compiler\sccdc.py -p threads -l python server.xml

+ 8 - 0
examples/HTTP_server/run_echo_server.py

@@ -0,0 +1,8 @@
+import sys
+
+import server
+import socket2event
+
+controller = server.Controller(sys.argv[1:])
+socket2event.boot_translation_service(controller)
+controller.start()

+ 0 - 0
examples/HTTP_server/server.py


Some files were not shown because too many files changed in this diff