فهرست منبع

Merge remote-tracking branch 'yentl/master' into jit

jonathanvdc 8 سال پیش
والد
کامیت
23e3281b92
46فایلهای تغییر یافته به همراه543 افزوده شده و 3434 حذف شده
  1. 1 1
      README.md
  2. BIN
      bootstrap/bootstrap.m.gz
  3. 10 53
      bootstrap/bootstrap.py
  4. 10 0
      bootstrap/initial_code_manager.alc
  5. 17 0
      bootstrap/initial_code_user.alc
  6. BIN
      bootstrap/minimal.m.gz
  7. 4 0
      bootstrap/user_interface.alc
  8. 20 22
      bootstrap/user_manager.alc
  9. 75 31
      hybrid_server/classes/mvkcontroller.xml
  10. 0 1
      hybrid_server/classes/server.xml
  11. 2 0
      integration/code/binary_to_decimal.alc
  12. 2 0
      integration/code/cbd_semantics.alc
  13. 2 0
      integration/code/factorial.alc
  14. 2 0
      integration/code/fibonacci.alc
  15. 2 0
      integration/code/fibonacci_smart.alc
  16. 2 0
      integration/code/fsa_semantics.alc
  17. 2 0
      integration/code/if_elif.alc
  18. 2 0
      integration/code/if_elif_else.alc
  19. 2 0
      integration/code/leap_year.alc
  20. 2 0
      integration/code/mini_modify.alc
  21. 5 1
      integration/code/pn_interface.alc
  22. 4 0
      integration/code/pn_semantics.alc
  23. 2 0
      integration/code/power.alc
  24. 2 0
      integration/code/remainder.alc
  25. 2 0
      integration/code/revert.alc
  26. 2 0
      integration/code/rpgame_semantics.alc
  27. 2 0
      interface/HUTN/hutn_compiler/bootstrap_visitor.py
  28. 3 3
      interface/HUTN/hutn_compiler/hutnparser.py
  29. 0 2
      interface/HUTN/hutn_compiler/primitives_visitor.py
  30. 13 14
      interface/HUTN/hutn_compiler/semantics_visitor.py
  31. 61 40
      kernel/modelverse_kernel/main.py
  32. 75 47
      kernel/mvk_server/classes/executor.xml
  33. 0 77
      kernel/mvk_server/classes/local_mvs.xml
  34. 93 77
      kernel/mvk_server/classes/mvkcontroller.xml
  35. 0 1
      kernel/mvk_server/classes/server.xml
  36. 2 1
      kernel/mvk_server/classes/socket.xml
  37. 53 31
      kernel/mvk_server/classes/user_statechart.xml
  38. 0 3019
      kernel/mvk_server/server.py
  39. 2 1
      kernel/mvk_server/server.xml
  40. 1 2
      scripts/check_objects.py
  41. 3 2
      scripts/compile.py
  42. 45 0
      scripts/debug_prompt.py
  43. 0 3
      scripts/execute_model.py
  44. 1 1
      scripts/make_all.py
  45. 5 4
      scripts/make_parallel.py
  46. 10 0
      scripts/run_debug_modelverse.py

+ 1 - 1
README.md

@@ -80,7 +80,7 @@ Using PyPy
 Since all scripts chain the invocation with the same interpreter as originally invoking the script, you will need to install py.test for PyPy.
 Assuming that you already have PyPy installed, you can simply install py.test using these commands:
 ```sh
-wget https://bootstrap.pypa.io/get-pip.py
+wget https://msdl.uantwerpen.be/files/get-pip.py
 pypy get-pip.py --user
 pypy -m pip install pytest --user
 ```

BIN
bootstrap/bootstrap.m.gz


+ 10 - 53
bootstrap/bootstrap.py

@@ -7,7 +7,10 @@ import gzip
 def bootstrap():
     root = ["__hierarchy"]
 
+    user_manager = "user_manager"
     bootstrap_files = glob.glob("bootstrap/*.alc")
+    initial_code_manager = "bootstrap/initial_code_manager.alc"
+    initial_code_user = "bootstrap/initial_code_user.alc"
 
     user_data = [   "input",
                     "output",
@@ -105,40 +108,6 @@ def bootstrap():
                     "time": ["Float"],
                 }
 
-    initial_user = "user_manager"
-    initial_user_code = \
-    '''
-    include "bootstrap/primitives.alc"
-    include "user_manager.alh"
-
-    Void function __main():
-    \tElement root
-    \troot = read_root()
-    \troot = root["__hierarchy"]["objects"]
-    \texec(root["bootstrap/user_manager.alc"]["initializers"])
-    \tuser_management()
-    '''
-
-    code_new_users = \
-    '''
-    include "bootstrap/primitives.alc"
-    include "user_interface.alh"
-
-    Void function __main():
-    \tElement root
-    \troot = read_root()
-    \troot = root["__hierarchy"]["objects"]
-    \texec(root["bootstrap/compilation_manager.alc"]["initializers"])
-    \texec(root["bootstrap/constructors.alc"]["initializers"])
-    \texec(root["bootstrap/library.alc"]["initializers"])
-    \texec(root["bootstrap/object_operations.alc"]["initializers"])
-    \texec(root["bootstrap/conformance_scd.alc"]["initializers"])
-    \texec(root["bootstrap/metamodels.alc"]["initializers"])
-    \texec(root["bootstrap/modelling.alc"]["initializers"])
-    \texec(root["bootstrap/user_interface.alc"]["initializers"])
-    \tnew_user()
-    '''
-
     ### Actual script to generate the file
     import os
     import sys
@@ -222,25 +191,15 @@ def bootstrap():
                     f.write("Edge __user_last_%s(_user_last_%s, ___user_last_%s)\n" % (data, data, data))
                     
                 # Bind user to the root
-                f.write('Node ___new_user("%s")\n' % initial_user)
+                f.write('Node ___new_user("%s")\n' % user_manager)
                 f.write("Edge _new_user(root, user_root)\n")
                 f.write("Edge __new_user(_new_user, ___new_user)\n")
 
-                def compile_code_AL(code, target, prepend="", is_file=False, main=False, symbols=None):
+                def compile_code_AL(filename, target, prepend="", main=False, symbols=None):
                     import sys
                     sys.path.append("interface/HUTN/")
                     from hutn_compiler.compiler import main as compile_code
-
-                    if not is_file:
-                        f = tempfile.NamedTemporaryFile()
-                        f.write(code)
-                        f.flush()
-                        filename = f.name
-                    else:
-                        filename = code
                     code = compile_code(filename, "interface/HUTN/grammars/actionlanguage.g", "BS", ["--debug", "--prepend:%s" % prepend, "--main" if main else "--not-main"], symbols=symbols)
-                    if not is_file:
-                        f.close()
                     return code.replace("auto_initial_IP", target)
 
                 # Create all library code
@@ -253,10 +212,10 @@ def bootstrap():
                 # Compile all files and add to structure manually
                 for bootstrap_file in bootstrap_files:
                     # Compile the subfile
+                    bootstrap_file = bootstrap_file.replace("\\", "/")
                     print("[COMP] %s" % bootstrap_file)
                     symbols = {}
-                    result = compile_code_AL(bootstrap_file, "initial_IP", prepend=bootstrap_file, is_file=True, symbols=symbols)
-                    f.write(result, both=False)
+                    f.write(compile_code_AL(bootstrap_file, "initial_IP", prepend=bootstrap_file, symbols=symbols, main = bootstrap_file in [initial_code_manager, initial_code_user]), both=False)
 
                     # Now link the code with the compilation manager structure
                     f.write("Node elem()\n", both=False)
@@ -285,10 +244,9 @@ def bootstrap():
                         f.write('Edge _(_, k)\n', both=False)
 
                 # Create code for initial user
-                print("[BOOT] initial_user")
-                f.write(compile_code_AL(initial_user_code, "initial_IP", prepend="user_manager", main=True), both=False)
+                print("[BOOT] user_manager")
                 f.write('Node _IP_str("IP")\n', both=False)
-                f.write("Edge _user_frame(user_frame, user_manager_initial_IP)\n", both=False)
+                f.write("Edge _user_frame(user_frame, %s_initial_IP)\n" % initial_code_manager, both=False)
                 f.write("Edge __user_frame(_user_frame, _IP_str)\n", both=False)
 
                 f.write('Node __phase("init")\n', both=False)
@@ -298,9 +256,8 @@ def bootstrap():
 
                 # Create code for new users to start at
                 print("[BOOT] new_user")
-                f.write(compile_code_AL(code_new_users, "initial_IP", prepend="new_user", main=True), both=False)
                 f.write('Node __IP_str("__IP")\n', both=False)
-                f.write("Edge _user_IP(__hierarchy, new_user_initial_IP)\n", both=False)
+                f.write("Edge _user_IP(__hierarchy, %s_initial_IP)\n" % initial_code_user, both=False)
                 f.write("Edge __user_IP(_user_IP, __IP_str)\n", both=False)
     except:
         os.remove("bootstrap/bootstrap.m.gz")

+ 10 - 0
bootstrap/initial_code_manager.alc

@@ -0,0 +1,10 @@
+include "bootstrap/primitives.alc"
+include "user_manager.alh"
+
+Void function __main():
+	Element root
+	root = read_root()
+	root = root["__hierarchy"]["objects"]
+	exec(root["bootstrap/user_manager.alc"]["initializers"])
+	user_management()
+	return!

+ 17 - 0
bootstrap/initial_code_user.alc

@@ -0,0 +1,17 @@
+include "bootstrap/primitives.alc"
+include "user_interface.alh"
+
+Void function __main():
+	Element root
+	root = read_root()
+	root = root["__hierarchy"]["objects"]
+	exec(root["bootstrap/compilation_manager.alc"]["initializers"])
+	exec(root["bootstrap/constructors.alc"]["initializers"])
+	exec(root["bootstrap/library.alc"]["initializers"])
+	exec(root["bootstrap/object_operations.alc"]["initializers"])
+	exec(root["bootstrap/conformance_scd.alc"]["initializers"])
+	exec(root["bootstrap/metamodels.alc"]["initializers"])
+	exec(root["bootstrap/modelling.alc"]["initializers"])
+	exec(root["bootstrap/user_interface.alc"]["initializers"])
+	new_user()
+	return!

BIN
bootstrap/minimal.m.gz


+ 4 - 0
bootstrap/user_interface.alc

@@ -19,5 +19,9 @@ Void function new_user():
 			compilation_manager()
 		elif (interface == 4):
 			construct_model()
+		elif (interface == -1):
+			return!
 		else:
 			log("Unsupported interface!")
+
+	return!

+ 20 - 22
bootstrap/user_manager.alc

@@ -10,26 +10,24 @@ Void function user_management():
 	
 	while (True):
 		username = input()
-		if (string_startswith(username, "__")):
-			username = string_substr(username, 2, string_len(username) - 1)
-			dict_delete(read_root(), username)
-		else:
-			if (bool_not(dict_in(read_root(), username))):
-				user_root = create_node()
-				user_frame = create_node()
-				output_value = create_node()
-				input_value = create_node()
-				dict_add(user_root, "frame", user_frame)
-				dict_add(user_root, "globals", create_node())
-				dict_add(user_root, "output", output_value)
-				dict_add(user_root, "last_output", output_value)
-				dict_add(user_root, "input", input_value)
-				dict_add(user_root, "last_input", input_value)
-				dict_add(user_frame, "evalstack", create_node())
-				dict_add(user_frame, "returnvalue", create_node())
-				dict_add(user_frame, "phase", "init")
-				dict_add(user_frame, "IP", dict_read(dict_read(read_root(), "__hierarchy"), "__IP"))
-				dict_add(user_frame, "symbols", create_node())
+		if (bool_not(dict_in(read_root(), username))):
+			user_root = create_node()
+			user_frame = create_node()
+			output_value = create_node()
+			input_value = create_node()
+			dict_add(user_root, "frame", user_frame)
+			dict_add(user_root, "globals", create_node())
+			dict_add(user_root, "output", output_value)
+			dict_add(user_root, "last_output", output_value)
+			dict_add(user_root, "input", input_value)
+			dict_add(user_root, "last_input", input_value)
+			dict_add(user_frame, "evalstack", create_node())
+			dict_add(user_frame, "returnvalue", create_node())
+			dict_add(user_frame, "phase", "init")
+			dict_add(user_frame, "IP", dict_read(dict_read(read_root(), "__hierarchy"), "__IP"))
+			dict_add(user_frame, "symbols", create_node())
 
-				//Add this only at the end, as otherwise the user will already be detected
-				dict_add(read_root(), username, user_root)
+			//Add this only at the end, as otherwise the user will already be detected
+			dict_add(read_root(), username, user_root)
+
+	return!

+ 75 - 31
hybrid_server/classes/mvkcontroller.xml

@@ -21,6 +21,10 @@
             self.source = None
             self.port = int(sys.argv[1])
             self.count = 0
+            
+            self.debugged_users = set()
+            self.debug_info = {}
+            self.done_something = False
 
             self.mvs_operations = {
                     "CN": self.mvs.create_node,
@@ -95,6 +99,8 @@
                         <script>
                             # No JSON encoding necessary, as it is not complex
                             try:
+                                print 'from_mvi %s' % data
+                                self.done_something = False
                                 if data["op"] == "set_input":
                                     if "value" in data:
                                         value = [json.loads(data["value"])]
@@ -103,6 +109,34 @@
                                     self.input_queue[data["username"]].append((source, value))
                                 elif data["op"] == "get_output":
                                     self.output_queue[data["username"]].append(source)
+                                elif data["op"] == "attach_debugger":
+                                    self.debugged_users.add(data["username"])
+                                    self.done_something = True
+                                    self.source = source
+                                    self.debug_info[data["username"]] = {'state': 'running', 'breakpoints': []}
+                                elif data["op"] == "detach_debugger":
+                                    self.debugged_users.discard(data["username"])
+                                    self.done_something = True
+                                    self.source = source
+                                    del self.debug_info[data["username"]]
+                                elif data["op"] == "pause":
+                                    if data["username"] in self.debugged_users:
+                                        self.debug_info[data["username"]]['state'] = 'paused'
+                                    self.done_something = True
+                                    self.source = source
+                                elif data["op"] == "resume":
+                                    if data["username"] in self.debugged_users:
+                                        self.debug_info[data["username"]]['state'] = 'running'
+                                    self.done_something = True
+                                    self.source = source
+                                elif data["op"] == "step_over":
+                                    pass
+                                    self.done_something = True
+                                    self.source = source
+                                elif data["op"] == "step_into":
+                                    pass
+                                    self.done_something = True
+                                    self.source = source
                                 else:
                                     raise Exception("DROPPING unknown operation: " + str(data["op"]))
                             except ValueError:
@@ -110,6 +144,15 @@
                                 raise
                         </script>
                     </transition>
+
+                    <transition cond="self.done_something" target=".">
+                        <raise event="HTTP_input" scope="narrow" target="'to_mvi/%s' % self.source">
+                            <parameter expr="json.dumps(True)"/>
+                        </raise>
+                        <script>
+                            self.done_something = False
+                        </script>
+                    </transition>
                 </state>
             </state>
 
@@ -121,37 +164,38 @@
                             self.destination = None
                             if self.users:
                                 user = self.users.pop()
-
-                                # Check if there are values to input
-                                if self.input_queue[user]:
-                                    source, args = self.input_queue[user].pop(0)
-                                    for args_entry in args:
-                                        self.execute_modelverse(user, "set_input", [args_entry])
-
-                                    self.destination = source
-                                    self.value = "OK"
-                                    self.all_failed = False
-
-                                # Now process for some steps, or until we are again blocked for input
-                                for x in xrange(100):
-                                    self.execute_modelverse(user, "execute_rule", [])
-
-                                    if not self.mvk.success:
-                                        # Blocking or broken, so quit already to stop wasting CPU
-                                        break
-
-                                    # Could at least execute one instruction, so mark it as "not failed"
-                                    self.all_failed = False
-
-                                # Check that we don't have anything to output yet, otherwise we wait
-                                if self.destination is None:
-                                    # Perform output if there is anything
-                                    if self.output_queue[user]:
-                                        self.execute_modelverse(user, "get_output", [])
-                                        if self.mvk.success:
-                                            self.destination = self.output_queue[user].pop(0)
-                                            self.value = self.mvk.returnvalue
-                                            self.all_failed = False
+                                if not user in self.debugged_users or self.debug_info[user]['state'] == 'running':
+                                    # Check if there are values to input
+                                    if self.input_queue[user]:
+                                        source, args = self.input_queue[user].pop(0)
+                                        for args_entry in args:
+                                            self.execute_modelverse(user, "set_input", [args_entry])
+
+                                        self.destination = source
+                                        self.value = "OK"
+                                        self.all_failed = False
+
+                                    nr_of_steps = 1 if user in self.debugged_users else 100
+                                    # Now process for some steps, or until we are again blocked for input
+                                    for x in xrange(nr_of_steps):
+                                        self.execute_modelverse(user, "execute_rule", [])
+
+                                        if not self.mvk.success:
+                                            # Blocking or broken, so quit already to stop wasting CPU
+                                            break
+
+                                        # Could at least execute one instruction, so mark it as "not failed"
+                                        self.all_failed = False
+
+                                    # Check that we don't have anything to output yet, otherwise we wait
+                                    if self.destination is None:
+                                        # Perform output if there is anything
+                                        if self.output_queue[user]:
+                                            self.execute_modelverse(user, "get_output", [])
+                                            if self.mvk.success:
+                                                self.destination = self.output_queue[user].pop(0)
+                                                self.value = self.mvk.returnvalue
+                                                self.all_failed = False
 
                             else:
                                 if self.count >= 2000:

+ 0 - 1
hybrid_server/classes/server.xml

@@ -88,7 +88,6 @@
                             <parameter expr="instancename"/>
                         </raise>
                     </transition>
-                    <transition after="1.0" target="."/>
                 </state>
             </state>
 

+ 2 - 0
integration/code/binary_to_decimal.alc

@@ -21,3 +21,5 @@ Integer function b2d(param : String):
 Void function main():
 	while(True):
 		output(b2d(input()))
+
+	return!

+ 2 - 0
integration/code/cbd_semantics.alc

@@ -659,3 +659,5 @@ Void function main():
 
 	while (True):
 		execute_cbd(instantiate_model(import_node("models/CausalBlockDiagrams_Design")))
+
+	return!

+ 2 - 0
integration/code/factorial.alc

@@ -9,3 +9,5 @@ Integer function factorial(n : Integer):
 Void function main():
 	while(True):
 		output(factorial(input()))
+
+	return!

+ 2 - 0
integration/code/fibonacci.alc

@@ -9,3 +9,5 @@ Integer function fib(param : Integer):
 Void function main():
 	while(True):
 		output(fib(input()))
+
+	return!

+ 2 - 0
integration/code/fibonacci_smart.alc

@@ -15,3 +15,5 @@ Void function main():
 	list_append(numbers, 1)
 	while(True):
 		output(fib(input()))
+
+	return!

+ 2 - 0
integration/code/fsa_semantics.alc

@@ -252,3 +252,5 @@ Void function main():
 
 	while (True):
 		execute_fsa(instantiate_model(import_node("models/FiniteStateAutomata_Design")))
+
+	return!

+ 2 - 0
integration/code/if_elif.alc

@@ -10,3 +10,5 @@ Integer function compare_with_zero(n : Integer):
 Void function main():
 	while(True):
 		output(compare_with_zero(input()))
+
+	return!

+ 2 - 0
integration/code/if_elif_else.alc

@@ -11,3 +11,5 @@ Integer function compare_with_zero(n : Integer):
 Void function main():
 	while(True):
 		output(compare_with_zero(input()))
+
+	return!

+ 2 - 0
integration/code/leap_year.alc

@@ -14,3 +14,5 @@ Boolean function leap_year(year : Integer):
 Void function main():
 	while (True):
 		output(leap_year(input()))
+
+	return!

+ 2 - 0
integration/code/mini_modify.alc

@@ -250,3 +250,5 @@ Element function modify(model : Element):
 		else:
 			output("Unknown command: " + cast_v2s(cmd))
 			output("Use command 'help' to get a list of available commands")
+
+	return model!

+ 5 - 1
integration/code/pn_interface.alc

@@ -277,7 +277,9 @@ Element function model_loaded(model : Element):
 			output("Unknown command: " + cast_v2s(cmd))
 			output("Use command 'help' to get a list of available commands")
 
-Element function main():
+	return model!
+
+Void function main():
 	output("Welcome to the Model Management Interface, running live on the Modelverse!")
 	output("Use 'help' command for a list of possible commands")
 	String command
@@ -361,3 +363,5 @@ Element function main():
 			output("Back in model manager!")
 		else:
 			output("Command not recognized, use 'help' for a list of possible commands")
+
+	return!

+ 4 - 0
integration/code/pn_semantics.alc

@@ -123,6 +123,8 @@ Void function main():
 			else:
 				output("Non-conforming model: " + verify_result)
 
+	return!
+
 Void function execute_petrinet(model : Element):
 	String cmd
 	while (True):
@@ -147,3 +149,5 @@ Void function execute_petrinet(model : Element):
 		else:
 			output("Did not understand command!")
 			output("Use 'help' for a list of available options")
+
+	return!

+ 2 - 0
integration/code/power.alc

@@ -9,3 +9,5 @@ Integer function power(base : Integer, exponent : Integer):
 Void function main():
 	while (True):
 		output(power(input(), input()))
+
+	return!

+ 2 - 0
integration/code/remainder.alc

@@ -3,3 +3,5 @@ include "lib_remainder.alc"
 Void function main():
 	while(True):
 		output(remainder(input(), input()))
+
+	return!

+ 2 - 0
integration/code/revert.alc

@@ -19,3 +19,5 @@ String function revert_string(a : String):
 Void function main():
 	while (True):
 		output(revert_string(input()))
+
+	return!

+ 2 - 0
integration/code/rpgame_semantics.alc

@@ -27,6 +27,8 @@ Void function main():
 			else:
 				output("Non-conforming model: " + verify_result)
 
+	return!
+
 String function getHeroTile(model : Element, hero : String):
 	return set_pop(followAssociation(model, hero, "Character_on_tile"))!
 

+ 2 - 0
interface/HUTN/hutn_compiler/bootstrap_visitor.py

@@ -33,6 +33,8 @@ class BootstrapVisitor(PrimitivesVisitor):
             self.dict(access, "var", resolve)
             self.dict(call, "func", access)
             self.dict(self.last_instruction, "next", call)
+            ret = self.value(Action("return"))
+            self.dict(call, "next", ret)
 
         output = []
         for t, data in self.output:

+ 3 - 3
interface/HUTN/hutn_compiler/hutnparser.py

@@ -29,13 +29,13 @@ from copy import deepcopy
 from position import Position
 
 class Tree(object):
-    def __init__(self, head, tail, startpos, endpos):
+    def __init__(self, head, tail, startpos, endpos, inputfile = None):
         self.head = head
         self.tail = tail
         self.startpos = startpos
         self.endpos = endpos
         self._tail = None
-        self.inputfile = None
+        self.inputfile = inputfile
         # IMPORTANT: self.replaced: replace_child defines self.replaced
 
     def is_rule(self):
@@ -111,7 +111,7 @@ class Tree(object):
             ", ".join([str(i) for i in self.get_raw_tail()]))
 
     def get_reference_line(self):
-        return "%s:%s" % (self.inputfile, self.startpos["line"])
+        return "%s:%s:%s-%s" % (self.inputfile, self.startpos["line"], self.startpos["column"], self.endpos["column"])
 
     def fix_tracability(self, inputfile):
         if self.inputfile is None:

+ 0 - 2
interface/HUTN/hutn_compiler/primitives_visitor.py

@@ -16,8 +16,6 @@ class PrimitivesVisitor(Visitor):
 
     def debug(self, node, tree, msg=""):
         if self.debug_symbols:
-            if ".alc" not in tree.get_reference_line():
-                self.debug_symbols = False
             self.dict(node, "__debug", self.value("[%s] %s" % (tree.get_reference_line(), msg)))
 
     def node(self):

+ 13 - 14
interface/HUTN/hutn_compiler/semantics_visitor.py

@@ -137,7 +137,7 @@ class SemanticsVisitor(Visitor):
                         tree.startpos['column']
                     ))
             call_name = SemanticsVisitor.call_name_binary(l_type, op)
-            call_tree = SemanticsVisitor.func_call(call_name, [l, r])
+            call_tree = SemanticsVisitor.func_call(call_name, [l, r], tree)
             try:
                 self.visit(call_tree)
             except RuntimeError:
@@ -162,7 +162,7 @@ class SemanticsVisitor(Visitor):
             op, l = child.get_tail()
             l_type = self.get_type(l)
             call_name = SemanticsVisitor.call_name_unary(l_type, op)
-            call_tree = SemanticsVisitor.func_call(call_name, [l])
+            call_tree = SemanticsVisitor.func_call(call_name, [l], tree)
             try:
                 self.visit(call_tree)
             except RuntimeError:
@@ -200,29 +200,28 @@ class SemanticsVisitor(Visitor):
         self.perform_implicit_cast(tree, l, l_type, p_type)
 
     @staticmethod
-    def func_call(name, params):
-        zero = {'line': 0, 'column': 0}
+    def func_call(name, params, old_tree):
+        startpos = old_tree.startpos
+        endpos = old_tree.endpos
+        inputfile = old_tree.inputfile
 
         tree = hp.Tree(
             "func_call",
             [
                 hp.Tree("rvalue",
                         [
-                            hp.Tree("ID", [name], zero, zero)
+                            hp.Tree("ID", [name], startpos, endpos, inputfile)
                         ],
-                        zero, zero),
+                        startpos, endpos, inputfile),
                 # Tokens have no impact on visit_func_call. So leave them out.
-                # hp.Tree("LPAREN", ["("], zero, zero),
-                # hp.Tree("COMMA", [","], zero, zero),
-                # hp.Tree("RPAREN", [")"], zero, zero),
             ],
-            zero, zero)
+            startpos, endpos, inputfile)
 
-        params = [hp.Tree("expression", [p], zero, zero) for p in params]
+        params = [hp.Tree("expression", [p], startpos, endpos, inputfile) for p in params]
 
         tree.tail.extend(params)
 
-        return hp.Tree("expression", [tree], zero, zero)
+        return hp.Tree("expression", [tree], startpos, endpos, inputfile)
 
     @staticmethod
     def cast_name(from_type, to_type):
@@ -251,7 +250,7 @@ class SemanticsVisitor(Visitor):
             return
         cast_name = SemanticsVisitor.cast_name(from_type, to_type)
         cast_tree = \
-            SemanticsVisitor.func_call(cast_name, [child])
+            SemanticsVisitor.func_call(cast_name, [child], tree)
         try:
             self.visit(cast_tree)
         except RuntimeError:
@@ -504,7 +503,7 @@ class SemanticsVisitor(Visitor):
             node = tree.get_child("rvalue")
             expression = tree.get_child("expression")
             operation = "dict_read"
-            call_tree = SemanticsVisitor.func_call(operation, [node, expression])
+            call_tree = SemanticsVisitor.func_call(operation, [node, expression], tree)
             self.visit(call_tree)
             tree.head = call_tree.head
             tree._tail = call_tree.tail

+ 61 - 40
kernel/modelverse_kernel/main.py

@@ -2,6 +2,7 @@ import modelverse_kernel.primitives as primitive_functions
 import modelverse_kernel.compiled as compiled_functions
 import modelverse_jit.jit as jit
 import modelverse_jit.intrinsics as jit_intrinsics
+from collections import defaultdict
 import sys
 import time
 
@@ -34,11 +35,12 @@ class ModelverseKernel(object):
 
         # To disable the JIT, uncomment the line below:
         #     self.jit.set_jit_enabled(False)
-        self.debug_info = "(no debug information found)"
+        self.debug_info = defaultdict(list)
 
     def execute_yields(self, username, operation, params, reply):
         try:
             self.success = True
+            self.username = username
             if username not in self.generators:
                 self.generators[username] = {}
             if operation not in self.generators[username]:
@@ -54,42 +56,49 @@ class ModelverseKernel(object):
             del self.generators[username][operation]
             return None
         except:
-            print("Unknown error @ %s" % self.debug_info)
+            print("Unknown error @ %s" % self.debug_info[username])
             raise
 
     def execute_rule(self, username):
         user_root, =    yield [("RD", [self.root, username])]
-        user_frame, =   yield [("RD", [user_root, "frame"])]
-        inst, phase =   yield [("RD", [user_frame, "IP"]),
-                               ("RD", [user_frame, "phase"]),
-                              ]
-        self.new_debug, phase_v, inst_v = \
-                        yield [("RD", [inst, "__debug"]),
-                               ("RV", [phase]),
-                               ("RV", [inst]),
-                              ]
-        if self.new_debug is not None:
-            self.debug_info, = yield [("RV", [self.new_debug])]
-
-        if phase_v == "finish":
-            gen = self.helper_init(user_root)
-        elif inst is None:
-            raise Exception("Instruction pointer could not be found!")
-        elif isinstance(phase_v, string_types):
-            if phase_v == "init" and self.jit.is_jittable_entry_point(inst):
-                #print("%-30s(%s)" % ("COMPILED " + str(self.jit.jitted_entry_points[inst]), phase_v))
-                gen = self.execute_jit(user_root, inst, username)
+        if user_root is None:
+            self.success = False
+            self.returnvalue = None
+            yield None
+        else:
+            user_frame, = yield [("RD", [user_root, "frame"])]
+            self.inst, phase = yield [("RD", [user_frame, "IP"]),
+                                      ("RD", [user_frame, "phase"]),
+                                     ]
+            self.new_debug, self.phase_v, inst_v = \
+                            yield [("RD", [self.inst, "__debug"]),
+                                   ("RV", [phase]),
+                                   ("RV", [self.inst]),
+                                  ]
+            if self.new_debug is not None:
+                if self.debug_info[username]:
+                    self.debug_info[username][-1], = yield [("RV", [self.new_debug])]
+
+            if self.phase_v == "finish":
+                gen = self.helper_init(user_root)
+            elif self.inst is None:
+                raise Exception("Instruction pointer could not be found!")
+            elif isinstance(self.phase_v, string_types):
+                if self.phase_v == "init" and self.jit.is_jittable_entry_point(self.inst):
+                    #print("%-30s(%s)" % ("COMPILED " + str(self.jit.jitted_entry_points[self.inst]), phase_v))
+                    gen = self.execute_jit(user_root, self.inst, username)
+                elif inst_v is None:
+                    raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info[username], inst_v, self.phase_v))
+                else:
+                    #print("%-30s(%s) -- %s" % (inst_v["value"], self.phase_v, username))
+                    gen = self.get_inst_phase_generator(inst_v, self.phase_v, user_root)
             elif inst_v is None:
-                raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, phase_v))
+                raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info[username], inst_v, self.phase_v))
+            elif inst_v["value"] == "call":
+                #print("%-30s(%s)" % ("call", "param"))
+                gen = self.call_param(user_root)
             else:
-                gen = self.get_inst_phase_generator(inst_v, phase_v, user_root)
-        elif inst_v is None:
-            raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, phase_v))
-        elif inst_v["value"] == "call":
-            #print("%-30s(%s)" % ("call", "param"))
-            gen = self.call_param(user_root)
-        else:
-            raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, phase_v))
+                raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info[username], inst_v, self.phase_v))
 
         try:
             inp = None
@@ -100,7 +109,7 @@ class ModelverseKernel(object):
         except jit.JitCompilationFailedException as e:
             # Try again, but this time without the JIT.
             # print(e.message)
-            gen = self.get_inst_phase_generator(inst_v, phase_v, user_root)
+            gen = self.get_inst_phase_generator(inst_v, self.phase_v, user_root)
             try:
                 inp = None
                 while 1:
@@ -171,7 +180,7 @@ class ModelverseKernel(object):
                 inp = yield prim.send(inp)
         except StopIteration:
             # Execution has ended without return value, so we have no idea what to do
-            raise Exception("%s: primitive finished without returning a value!" % (self.debug_info))
+            raise Exception("%s: primitive finished without returning a value!" % (self.debug_info[username]))
         except primitive_functions.PrimitiveFinished as e:
             # Execution has ended with a returnvalue, so read it out from the exception being thrown
             result = e.result
@@ -187,6 +196,8 @@ class ModelverseKernel(object):
                                ("DE", [lnk]),
                                ("DN", [user_frame]),
                               ]
+        if self.debug_info[self.username]:
+            self.debug_info[self.username].pop()
 
     ########################################
     ### Execute input and output methods ###
@@ -464,7 +475,7 @@ class ModelverseKernel(object):
                                    ("CNV", ["finish"]),
                                   ]
             if variable is None:
-                raise Exception("%s: not found as global: %s" % (self.debug_info, var_name))
+                raise Exception("Not found as global: %s" % var_name)
 
             # Resolved a global, so this is a string
             # Potentially, this might even be a function that we have precompiled already!
@@ -579,14 +590,20 @@ class ModelverseKernel(object):
 
         if value is None:
             prev_frame, =   yield [("RD", [user_frame, "prev"])]
-            _, _ =          yield [("CD", [user_root, "frame", prev_frame]),
-                                   ("DN", [user_frame]),
-                                  ]
-
             # If the callee's frame is marked with the '__primitive_return' key, then
             # we need to throw an exception instead of just finishing here. This design
             # gives us O(1) state reads per jit-interpreter transition.
             exception_return, = yield [("RD", [user_frame, primitive_functions.PRIMITIVE_RETURN_KEY])]
+            if prev_frame is None:
+                _, =            yield [("DN", [user_root])]
+                del self.debug_info[self.username]
+            else:
+                if self.debug_info[self.username]:
+                    self.debug_info[self.username].pop()
+                _, _ =          yield [("CD", [user_root, "frame", prev_frame]),
+                                       ("DN", [user_frame]),
+                                      ]
+
             if exception_return is not None:
                 raise primitive_functions.PrimitiveFinished(None)
         else:
@@ -608,6 +625,9 @@ class ModelverseKernel(object):
                                   ]
 
     def return_eval(self, user_root):
+        if self.debug_info[self.username]:
+            self.debug_info[self.username].pop()
+
         user_frame, = yield [("RD", [user_root, "frame"])]
         prev_frame, exception_return, returnvalue = yield [
             ("RD", [user_frame, "prev"]),
@@ -726,6 +746,7 @@ class ModelverseKernel(object):
                                   ]
 
     def call_call(self, user_root):
+        self.debug_info[self.username].append("None")
         user_frame, =       yield [("RD", [user_root, "frame"])]
         inst, =             yield [("RD", [user_frame, "IP"])]
         param, =            yield [("RD", [inst, "last_param"])]
@@ -805,9 +826,9 @@ class ModelverseKernel(object):
         if len(matches) == 1:
             return matches[0]
         elif len(matches) > 1:
-            raise Exception("%s: error: multiple overlapping elements" % self.debug_info)
+            raise Exception("Error: multiple overlapping elements")
         else:
-            raise Exception("%s: error: could not find any overlap" % self.debug_info)
+            raise Exception("Error: could not find any overlap")
 
     def call_param(self, user_root):
         user_frame, =       yield [("RD", [user_root, "frame"])]

+ 75 - 47
kernel/mvk_server/classes/executor.xml

@@ -3,18 +3,64 @@
         <association name="parent" class="MvKController" min="1" max="1"/>
     </relationships>
     <constructor>
-        <parameter name="mvk"/>
         <body>
             <![CDATA[
-            self.request_queue = [("", "", "load_primitives", [], None)]
-            self.mvk = mvk
+            self.mvs = ModelverseState("../../bootstrap/bootstrap.m.gz")
+            self.request_queue = [("", "", "load_primitives", [], None, False)]
+            self.mvs.GC = True
+            self.mvk = ModelverseKernel(self.mvs.read_root()[0])
             self.first = True
             self.mvs_response = None
+            
+            self.mvs_operations = {
+                    "CN": self.mvs.create_node,
+                    "CE": self.mvs.create_edge,
+                    "CNV": self.mvs.create_nodevalue,
+                    "CD": self.mvs.create_dict,
+
+                    "RV": self.mvs.read_value,
+                    "RO": self.mvs.read_outgoing,
+                    "RI": self.mvs.read_incoming,
+                    "RE": self.mvs.read_edge,
+                    "RD": self.mvs.read_dict,
+                    "RDN": self.mvs.read_dict_node,
+                    "RDNE": self.mvs.read_dict_node_edge,
+                    "RDE": self.mvs.read_dict_edge,
+                    "RRD": self.mvs.read_reverse_dict,
+                    "RR": self.mvs.read_root,
+                    "RDK": self.mvs.read_dict_keys,
+
+                    "DE": self.mvs.delete_edge,
+                    "DN": self.mvs.delete_node,
+                }
+
             ]]>
         </body>
     </constructor>
+
     <scxml initial="init">
         <parallel id="init">
+            <state id="raw_exec">
+                <state id="raw_exec">
+                    <transition event="raw_exec" target=".">
+                        <parameter name="operations"/>
+                        <parameter name="source"/>
+                        <script>
+                            reply = [self.mvs_operations[command[0]](*command[1]) for command in operations]
+                        </script>
+                        <raise event="raw_exec_reply" scope="narrow" target="source">
+                            <parameter expr="reply"/>
+                        </raise>
+                    </transition>
+                    <transition event="get_mvk" target=".">
+                        <parameter name="source"/>
+                        <raise event="get_mvk_reply" scope="narrow" target="source">
+                            <parameter expr="self.mvk"/>
+                        </raise>
+                    </transition>
+                </state>
+            </state>
+
             <state id="queue">
                 <state id="queue">
                     <transition event="execute" target=".">
@@ -24,7 +70,17 @@
                         <parameter name="params"/>
                         <parameter name="request_id"/>
                         <script>
-                            self.request_queue.append(("/" + returnpath, username, operation, params, request_id))
+                            self.request_queue.append((("/" + returnpath) if returnpath is not None else None, username, operation, params, request_id, True))
+                        </script>
+                    </transition>
+                    <transition event="execute_debug" target=".">
+                        <parameter name="returnpath"/>
+                        <parameter name="username"/>
+                        <parameter name="operation"/>
+                        <parameter name="params"/>
+                        <parameter name="request_id"/>
+                        <script>
+                            self.request_queue.append((("/" + returnpath) if returnpath is not None else None, username, operation, params, request_id, False))
                         </script>
                     </transition>
                 </state>
@@ -38,57 +94,29 @@
                 <state id="execution">
                     <onentry>
                         <script>
-                            try:
-                                _, username, operation, params, _ = self.request_queue[0]
-                                self.mvs_commands = self.mvk.execute_yields(username, operation, params, self.mvs_response)
-                            except:
-                                import traceback
-                                traceback.print_exc()
-                                print("Exec error")
-                                #TODO for debugging
-                                sys.exit(0)
+                            self.mvk.returnvalue = None
+                            self.mvk.success = True
+                            self.first = True
 
-                                self.mvs_commands = None
+                            self.returnpath, username, operation, params, self.request_id, self.mvk.allow_compiled = self.request_queue.pop(0)
+                            reply = None
+                            commands = []
+                            while 1:
+                                commands = self.mvk.execute_yields(username, operation, params, reply)
+                                if commands is None:
+                                    break
+                                reply = [self.mvs_operations[command[0]](*(command[1]))[0] for command in commands]
                         </script>
                     </onentry>
 
-                    <transition cond="self.mvs_commands is None" target="../idle">
-                        <script>
-                            returnpath, _, _, _, request_id = self.request_queue.pop(0)
-                            self.mvs_response = None
-                        </script>
-                        <raise event="executed" scope="narrow" target="'parent' + returnpath">
+                    <transition cond="self.returnpath is not None" target="../idle">
+                        <raise event="executed" scope="narrow" target="'parent' + self.returnpath">
                             <parameter expr="self.mvk.returnvalue"/>
                             <parameter expr="self.mvk.success"/>
-                            <parameter expr="request_id"/>
-                        </raise>
-                        <script>
-                            self.mvk.returnvalue = None
-                            self.mvk.success = True
-                            self.first = True
-                        </script>
-                    </transition>
-
-                    <transition cond="len(self.mvs_commands) > 0" target="../waiting_for_response">
-                        <raise event="HTTP_input" scope="narrow" target="'parent/to_mvs'">
-                            <parameter expr="'requests=%s' % json.dumps(self.mvs_commands)"/>
-                            <parameter expr="'parent/executor'"/>
+                            <parameter expr="self.request_id"/>
                         </raise>
                     </transition>
-
-                    <transition cond="len(self.mvs_commands) == 0" target=".">
-                    </transition>
-                </state>
-
-                <state id="waiting_for_response">
-                    <transition event="HTTP_output" target="../execution">
-                        <parameter name="data"/>
-                        <script>
-                            self.mvs_response = [v[0] for v in json.loads(data["data"])]
-                            if len(self.mvs_response) == 1:
-                                self.mvs_response = self.mvs_response[0]
-                        </script>
-                    </transition>
+                    <transition cond="self.returnpath is None" target="../idle"/>
                 </state>
             </state>
         </parallel>

+ 0 - 77
kernel/mvk_server/classes/local_mvs.xml

@@ -1,77 +0,0 @@
-<class name="LocalMvS">
-    <relationships>
-        <association name="parent" class="MvKController" min="1" max="1"/>
-    </relationships>
-    <constructor>
-        <parameter name="params"/>
-        <body>
-            <![CDATA[
-            self.queue = []
-            self.destinations = []
-            import sys
-            sys.path.append("../../state")
-            from modelverse_state.main import ModelverseState
-            self.mvs = ModelverseState(params[0])
-            self.mvs_operations = {
-               "CN": self.mvs.create_node,
-               "CE": self.mvs.create_edge,
-               "CNV": self.mvs.create_nodevalue,
-               "CD": self.mvs.create_dict,
-
-               "RV": self.mvs.read_value,
-               "RO": self.mvs.read_outgoing,
-               "RI": self.mvs.read_incoming,
-               "RE": self.mvs.read_edge,
-               "RD": self.mvs.read_dict,
-               "RDN": self.mvs.read_dict_node,
-               "RDNE": self.mvs.read_dict_node_edge,
-               "RDE": self.mvs.read_dict_edge,
-               "RRD": self.mvs.read_reverse_dict,
-               "RR": self.mvs.read_root,
-               "RDK": self.mvs.read_dict_keys,
-
-               "DE": self.mvs.delete_edge,
-               "DN": self.mvs.delete_node,
-
-               "DUMP": self.mvs.dump_modelverse,
-            }
-            ]]>
-        </body>
-    </constructor>
-
-    <method name="process_message">
-        <parameter name="operation_name"/>
-        <parameter name="parameters"/>
-        <body>
-            <![CDATA[
-            op = self.mvs_operations[operation_name]
-            return op(*parameters)
-            ]]>
-        </body>
-    </method>
-
-    <scxml initial="init">
-        <state id="init">
-            <transition target="../running">
-                <raise event="http_client_ready" scope="narrow" target="'parent'"/>
-            </transition>
-        </state>
-
-        <state id="running">
-            <transition event="HTTP_input" target=".">
-                <parameter name="data"/>
-                <parameter name="destination"/>
-                <script>
-                    decoded_data = json.loads(data.split("=",1)[1])
-                    result = []
-                    for command, params in decoded_data:
-                        result.append(self.process_message(command, params))
-                    data = {"data": json.dumps(result)}
-                </script>
-                <raise event="HTTP_output" scope="narrow" target="destination">
-                    <parameter expr="data"/>
-                </raise>
-            </transition>
-        </state>
-    </scxml>
-</class>

+ 93 - 77
kernel/mvk_server/classes/mvkcontroller.xml

@@ -9,62 +9,18 @@
         <parameter name="params"/>
         <body>
             <![CDATA[
-            self.mvk = None
             self.users = []
             self.user_statecharts = {"__hierarchy": None}
             self.input_queue = []
             self.user_queue = {}
             self.source = None
+            self.root = None
 
             self.params = params
             ]]>
         </body>
     </constructor>
-    <scxml initial="init">
-        <state id="init">
-            <!-- XXX For HTTP sockets
-            <onentry>
-                <raise scope="cd" event="create_instance">
-                    <parameter expr="'to_mvs'"/>
-                    <parameter expr="'HTTPClient'"/>
-                    <parameter expr="'127.0.0.1'"/>
-                    <parameter expr="8000"/>
-                </raise>
-            </onentry>
-            -->
-            <onentry>
-                <raise scope="cd" event="create_instance">
-                    <parameter expr="'to_mvs'"/>
-                    <parameter expr="'LocalMvS'"/>
-                    <parameter expr="self.params"/>
-                </raise>
-            </onentry>
-            <transition event="instance_created" target="../get_root">
-                <parameter name="instancename"/>
-                <raise scope="cd" event="start_instance">
-                    <parameter expr="instancename"/>
-                </raise>
-            </transition>
-        </state>
-
-        <state id="get_root">
-            <transition event="http_client_ready" target=".">
-                <raise event="HTTP_input" scope="narrow" target="'to_mvs'">
-                    <parameter expr="'requests=%s' % json.dumps([['RR', []]])"/>
-                    <parameter expr="'parent'"/>
-                </raise>
-            </transition>
-
-            <transition event="HTTP_output" target="../init_server">
-                <parameter name="data"/>
-                <script>
-                    self.mvk = ModelverseKernel(json.loads(data["data"])[0][0])
-                    self.mvk_next_op = "load_primitives"
-                    self.mvk_params = []
-                </script>
-            </transition>
-        </state>
-
+    <scxml initial="init_server">
         <state id="init_server">
             <onentry>
                 <raise scope="cd" event="create_instance">
@@ -87,10 +43,9 @@
                 <raise scope="cd" event="create_instance">
                     <parameter expr="'executor'"/>
                     <parameter expr="'Executor'"/>
-                    <parameter expr="self.mvk"/>
                 </raise>
             </onentry>
-            <transition event="instance_created" target="../running">
+            <transition event="instance_created" target="../get_mvk">
                 <parameter name="instancename"/>
                 <raise scope="cd" event="start_instance">
                     <parameter expr="instancename"/>
@@ -98,32 +53,63 @@
             </transition>
         </state>
 
+        <state id="get_mvk">
+            <onentry>
+                <raise event="get_mvk" scope="narrow" target="'executor'">
+                    <parameter expr="'parent'"/>
+                </raise>
+            </onentry>
+
+            <transition event="get_mvk_reply" target="../read_root">
+                <parameter name="mvk"/>
+                <script>
+                    self.mvk = mvk
+                </script>
+            </transition>
+        </state>
+
+        <state id="read_root">
+            <onentry>
+                <raise event="raw_exec" scope="narrow" target="'executor'">
+                    <parameter expr="[['RR', []]]"/>
+                    <parameter expr="'parent'"/>
+                </raise>
+            </onentry>
+
+            <transition event="raw_exec_reply" target="../running">
+                <parameter name="data"/>
+                <script>
+                    self.root = data[0][0]
+                </script>
+            </transition>
+        </state>
+
         <parallel id="running">
             <state id="wait_for_requests">
                 <state id="wait">
                     <transition event="from_mvi" target=".">
                         <parameter name="source"/>
                         <parameter name="data"/>
-                        <script>
+                        <script>                                
                             # No JSON encoding necessary, as it is not complex
+                            print("Got from MVI")
                             try:
+                                args = None
                                 if data["op"] == "set_input":
-                                    if data["element_type"] == "V":
-                                        value = json.loads(data["value"])
+                                    if "value" in data:
+                                        value = [json.loads(data["value"])]
                                     else:
-                                        value = data["value"]
-                                    args = (data["element_type"], value)
-                                    self.input_queue.append((source, "set_input", args, data["username"]))
-                                elif data["op"] == "get_output":
-                                    args = []
-                                    self.input_queue.append((source, "get_output", args, data["username"]))
+                                        value = json.loads(data["data"])
+                                    for v in value[:-1]:
+                                        self.input_queue.append((None, data["op"], [v], data["username"]))
+                                    self.input_queue.append((source, data["op"], [value[-1]], data["username"]))
+                                    print("Added to input queue")
                                 else:
-                                    print("DROPPING unknown operation: " + str(data["op"]))
-                            except:
-                                import traceback
-                                traceback.print_exc()
-                                print("DROPPING deserialization error")
-                                print("Decoding value " + str(data["value"]))
+                                    print("Appending " + data["op"])
+                                    self.input_queue.append((source, data["op"], args, data["username"]))
+                            except ValueError:
+                                print("Error when deserializing request: " + str(data))
+                                raise
                         </script>
                     </transition>
                 </state>
@@ -136,6 +122,7 @@
                     <transition cond="self.input_queue and self.input_queue[0][3] not in self.user_statecharts" target=".">
                         <!-- Move it to the back of the list, so we can process other users first -->
                         <script>
+                            print("Queue user")
                             self.user_queue.setdefault(self.input_queue[0][3], []).append(self.input_queue.pop(0))
                         </script>
                         <!-- Force a refresh too -->
@@ -164,30 +151,51 @@
                             <parameter expr="args"/>
                         </raise>
                     </transition>
+                    
+                    <transition cond="self.input_queue[0][1] == 'pause'" target="../wait">
+                        <script>
+                            print("Sending pause")
+                            source, op, args, username = self.input_queue.pop(0)
+                        </script>
+                        <raise event="pause" scope="narrow" target="self.user_statecharts[username]">
+                            <parameter expr="source"/>
+                            <parameter expr="args"/>
+                        </raise>
+                    </transition>
+                    
+                    <transition cond="self.input_queue[0][1] == 'resume'" target="../wait">
+                        <script>
+                            source, op, args, username = self.input_queue.pop(0)
+                        </script>
+                        <raise event="resume" scope="narrow" target="self.user_statecharts[username]">
+                            <parameter expr="source"/>
+                            <parameter expr="args"/>
+                        </raise>
+                    </transition>
                 </state>
             </state>
 
             <state id="find_users" initial="get_all_links">
                 <state id="get_all_links">
                     <onentry>
-                        <raise event="HTTP_input" scope="narrow" target="'to_mvs'">
-                            <parameter expr="'requests=%s' % json.dumps([['RDK', [self.mvk.root]]])"/>
+                        <raise event="raw_exec" scope="narrow" target="'executor'">
+                            <parameter expr="[['RDK', [self.root]]]"/>
                             <parameter expr="'parent'"/>
                         </raise>
                     </onentry>
 
-                    <transition event="HTTP_output" target="../retrieve_users">
+                    <transition event="raw_exec_reply" target="../retrieve_users">
                         <parameter name="data"/>
                         <script>
-                            self.users = json.loads(data["data"])[0][0]
+                            self.users = data[0][0]
                         </script>
                     </transition>
                 </state>
 
                 <state id="retrieve_users">
                     <transition cond="self.users" target="../got_usernames">
-                        <raise event="HTTP_input" scope="narrow" target="'to_mvs'">
-                            <parameter expr="'requests=%s' % json.dumps([['RV', [user]] for user in self.users])"/>
+                        <raise event="raw_exec" scope="narrow" target="'executor'">
+                            <parameter expr="[['RV', [user]] for user in self.users]"/>
                             <parameter expr="'parent'"/>
                         </raise>
                     </transition>
@@ -195,21 +203,29 @@
                 </state>
 
                 <state id="got_usernames">
-                    <transition event="HTTP_output" target="../process_users">
+                    <transition event="raw_exec_reply" target="../process_users">
                         <parameter name="data"/>
                         <script>
-                            self.users = [v[0] for v in json.loads(data["data"]) if v[0] not in self.user_statecharts]
+                            data = set([v[0] for v in data])
+                            self.add_users = [v for v in data if v not in self.user_statecharts]
+                            self.delete_users = [v for v in self.user_statecharts if v not in data]
                         </script>
                     </transition>
                 </state>
 
                 <state id="process_users">
-                    <transition cond="not self.users" target="../wait"/>
-                    <transition cond="self.users" target="../creating_user">
+                    <transition cond="not self.add_users and not self.delete_users" target="../wait"/>
+                    <transition cond="self.add_users and not self.delete_users" target="../creating_user">
                         <raise event="create_instance" scope="cd">
                             <parameter expr="'users'"/>
                             <parameter expr="'UserStatechart'"/>
-                            <parameter expr="self.users[0]"/>
+                            <parameter expr="self.add_users[0]"/>
+                            <parameter expr="self.mvk"/>
+                        </raise>
+                    </transition>
+                    <transition cond="self.delete_users" target=".">
+                        <raise event="delete_instance" scope="cd">
+                            <parameter expr="self.user_statecharts.pop(self.delete_users.pop(0))"/>
                         </raise>
                     </transition>
                 </state>
@@ -224,10 +240,10 @@
                             <parameter expr="instancename"/>
                         </raise>
                         <script>
-                            self.user_statecharts[self.users[0]] = instancename
+                            self.user_statecharts[self.add_users[0]] = instancename
                             # Repush all this user's messages in the input queue
-                            self.input_queue.extend(self.user_queue.pop(self.users[0], []))
-                            self.users.pop(0)
+                            self.input_queue.extend(self.user_queue.pop(self.add_users[0], []))
+                            self.add_users.pop(0)
                         </script>
                     </transition>
                 </state>

+ 0 - 1
kernel/mvk_server/classes/server.xml

@@ -88,7 +88,6 @@
                             <parameter expr="instancename"/>
                         </raise>
                     </transition>
-                    <transition after="1.0" target="."/>
                 </state>
             </state>
 

+ 2 - 1
kernel/mvk_server/classes/socket.xml

@@ -81,7 +81,8 @@
                         <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 = "&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"

+ 53 - 31
kernel/mvk_server/classes/user_statechart.xml

@@ -4,9 +4,11 @@
     </relationships>
     <constructor>
         <parameter name="username"/>
+        <parameter name="mvk" />
         <body>
             <![CDATA[
             self.username = username
+            self.mvk = mvk
 
             self.output_queue = []
             self.source_execution = None
@@ -29,36 +31,55 @@
         </state>
 
         <parallel id="running">
-            <state id="execution" initial="init">
-                <state id="init">
-                    <onentry>
-                        <raise event="execute" scope="narrow" target="'parent/executor'">
-                            <parameter expr="self.returnpath"/>
-                            <parameter expr="self.username"/>
-                            <parameter expr="'execute_rule'"/>
-                            <parameter expr="[]"/>
-                            <parameter expr="self.request_id"/>
+            <state id="execution" initial="executing">
+                <state id="executing" initial="executing">
+                    <state id="executing">
+                        <onentry>
+                            <raise event="execute" scope="narrow" target="'parent/executor'">
+                                <parameter expr="self.returnpath"/>
+                                <parameter expr="self.username"/>
+                                <parameter expr="'execute_rule'"/>
+                                <parameter expr="[]"/>
+                                <parameter expr="self.request_id"/>
+                            </raise>
+                            <script>
+                                self.outstanding_execution = self.request_id
+                                self.request_id += 1
+                            </script>
+                        </onentry>
+                        <transition event="executed" cond="success and self.outstanding_execution == request_id" target=".">
+                            <parameter name="returnvalue"/>
+                            <parameter name="success"/>
+                            <parameter name="request_id"/>
+                        </transition>
+                        <transition event="executed" cond="not success and self.outstanding_execution == request_id" target="../timeout">
+                            <parameter name="returnvalue"/>
+                            <parameter name="success"/>
+                            <parameter name="request_id"/>
+                        </transition>
+                    </state>
+
+                    <state id="timeout">
+                        <transition after="1.0" target="../executing"/>
+                        <transition event="set_input_done" target="../executing"/>
+                    </state>
+                    
+                    <transition target="../paused" event="pause">
+                        <parameter name="source"/>
+                        <parameter name="args"/>
+                        <raise event="HTTP_input" scope="narrow" target="'parent/to_mvi/' + source">
+                            <parameter expr="json.dumps({'user': self.username, 'state': 'paused', 'info': self.mvk.debug_info[self.username]})"/>
                         </raise>
-                        <script>
-                            self.outstanding_execution = self.request_id
-                            self.request_id += 1
-                        </script>
-                    </onentry>
-                    <transition event="executed" cond="success and self.outstanding_execution == request_id" target=".">
-                        <parameter name="returnvalue"/>
-                        <parameter name="success"/>
-                        <parameter name="request_id"/>
-                    </transition>
-                    <transition event="executed" cond="not success and self.outstanding_execution == request_id" target="../timeout">
-                        <parameter name="returnvalue"/>
-                        <parameter name="success"/>
-                        <parameter name="request_id"/>
                     </transition>
                 </state>
-
-                <state id="timeout">
-                    <transition after="1.0" target="../init"/>
-                    <transition event="set_input_done" target="../init"/>
+                <state id="paused">
+                    <transition target="../executing" event="resume">
+                        <parameter name="source"/>
+                        <parameter name="args"/>
+                        <raise event="HTTP_input" scope="narrow" target="'parent/to_mvi/' + source">
+                            <parameter expr="json.dumps({'user': self.username, 'state': 'running'})"/>
+                        </raise>
+                    </transition>
                 </state>
             </state>
 
@@ -75,8 +96,9 @@
                             <parameter expr="self.request_id"/>
                         </raise>
                         <script>
-                            self.outstanding_input[self.request_id] = source
-                            self.request_id += 1
+                            if source is not None:
+                                self.outstanding_input[self.request_id] = source
+                                self.request_id += 1
                         </script>
                     </transition>
                     <transition event="executed" cond="request_id in self.outstanding_input" target=".">
@@ -87,7 +109,7 @@
                             source = self.outstanding_input.pop(request_id)
                         </script>
                         <raise event="HTTP_input" scope="narrow" target="'parent/to_mvi/' + source">
-                            <parameter expr="returnvalue"/>
+                            <parameter expr="json.dumps(returnvalue)"/>
                         </raise>
                         <raise event="set_input_done"/>
                     </transition>
@@ -126,7 +148,7 @@
                         <parameter name="success"/>
                         <parameter name="request_id"/>
                         <raise event="HTTP_input" scope="narrow" target="'parent/to_mvi/' + self.output_queue.pop(0)">
-                            <parameter expr="returnvalue"/>
+                            <parameter expr="json.dumps(returnvalue)"/>
                         </raise>
                         <script>
                             self.outstanding_output = None

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 3019
kernel/mvk_server/server.py


+ 2 - 1
kernel/mvk_server/server.xml

@@ -11,6 +11,8 @@
         import json
 
         from modelverse_kernel.main import ModelverseKernel
+        sys.path.append("../../state")
+        from modelverse_state.main import ModelverseState
     </top>
 
     <inport name="socket_in"/>
@@ -20,7 +22,6 @@
     <class src="classes/server.xml"/>
     <class src="classes/socket.xml"/>
     <class src="classes/http_client.xml"/>
-    <class src="classes/local_mvs.xml"/>
     <class src="classes/user_statechart.xml"/>
     <class src="classes/executor.xml"/>
 </diagram>

+ 1 - 2
scripts/check_objects.py

@@ -43,6 +43,5 @@ def to_recompile(address, files):
             # Different, so rebuild
             rebuild.append(f)
 
-    # Remove user again
-    urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '"__%s"' % username, "username": "user_manager"}))).read()
+    urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '-1', "username": username}))).read()
     return rebuild

+ 3 - 2
scripts/compile.py

@@ -1,6 +1,7 @@
 import sys
 import os
 import urllib2
+import urllib
 import subprocess
 
 def do_compile(address, filename, username, modulename, mode, optionals=[], grammar="grammars/actionlanguage.g"):
@@ -11,9 +12,9 @@ def do_compile(address, filename, username, modulename, mode, optionals=[], gram
     except urllib2.URLError:
         return 2
     except:
-        urllib2.urlopen(urllib2.Request(address, 'op=set_input&username=user_manager&value="__%s"' % username)).read()
+        urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '-1', "username": username}))).read()
         return 1
-    urllib2.urlopen(urllib2.Request(address, 'op=set_input&username=user_manager&value="__%s"' % username)).read()
+    urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "set_input", "value": '-1', "username": username}))).read()
     return 0
 
 if __name__ == "__main__":

+ 45 - 0
scripts/debug_prompt.py

@@ -0,0 +1,45 @@
+import urllib
+import urllib2
+import threading
+import subprocess
+import os
+import sys
+import json
+
+def local_print(string):
+    if os.name == "posix":
+        # Nicer colour output when using posix (and thus supporting colour)
+        string = "\033[92m%s\033[0m" % string
+    print(string)
+
+def remote_print(string):
+    if os.name == "posix":
+        # Nicer colour output when using posix (and thus supporting colour)
+        string = "\033[94m%s\033[0m" % string
+    print(string)
+
+local_print("Welcome to the debugging shell!")
+local_print("Please specify Modelverse location (default: 127.0.0.1:8001)")
+
+location = raw_input()
+if location == "":
+    address = "http://127.0.0.1:8001/"
+    
+local_print("Please specify user name (default: test)")
+
+username = raw_input()
+if location == "":
+    username = "test"
+
+local_print("Switching context to Modelverse: all data is piped.")
+local_print("Available commands: 'pause', 'resume'")
+local_print("To quit: execute command 'quit'")
+
+while 1:
+    inp = raw_input().split(" ")
+    action = inp[0]
+    if action == "quit":
+        local_print("Received quit: breaking connection to Modelverse immediately!")
+        break
+
+    print json.loads(urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": action, "username": username}))).read())

+ 0 - 3
scripts/execute_model.py

@@ -50,7 +50,4 @@ for m in models:
     print("[MODEL] %s" % m)
     do_compile_wrapper(m, "MO", "grammars/modelling.g")
 
-#p = multiprocessing.Pool(multiprocessing.cpu_count() * 2)
-#p.map(lambda i: do_compile_wrapper(i, "PO", grammar="grammars/actionlanguage.g"), code)
-#link_and_load(address, username, code)
 main(address, username, code)

+ 1 - 1
scripts/make_all.py

@@ -17,6 +17,6 @@ if __name__ == "__main__":
 
         new_files = to_recompile(address, files)
         for f in new_files:
-            do_compile(address, f, str(random.random()), f, "CO")
+            do_compile(address, f, str(random.random()), f, "PO", ["--debug"])
 
         link_and_load(address, username, files)

+ 5 - 4
scripts/make_parallel.py

@@ -7,13 +7,14 @@ import random
 import multiprocessing
 import glob
 
-def main(address, username, files):
-    def do_compile_wrapper(filename):
-        do_compile(address, filename, str(random.random()), filename, "PO", ["--debug"])
+def do_compile_wrapper(args):
+    address, username, filename = args
+    do_compile(address, filename, str(random.random()), filename, "PO", ["--debug"])
 
+def main(address, username, files):
     p = multiprocessing.Pool(multiprocessing.cpu_count() * 2)
     new_files = to_recompile(address, files)
-    p.map(do_compile_wrapper, new_files)
+    p.map(do_compile_wrapper, [[address, username, f] for f in new_files])
     link_and_load(address, username, files)
 
 if __name__ == "__main__":

+ 10 - 0
scripts/run_debug_modelverse.py

@@ -0,0 +1,10 @@
+import subprocess
+import sys
+
+# sys.executable to use the same Python interpreter used to invoke this command
+if len(sys.argv) != 2:
+    sys.stderr.write("Expected different parameters!\n")
+    sys.stderr.write("    %s port\n" % sys.argv[0])
+else:
+    subprocess.check_call([sys.executable, "-m", "sccd.compiler.sccdc", "-p", "threads", "server.xml"], cwd="kernel/mvk_server")
+    subprocess.call([sys.executable, "run_mvk_server.py", sys.argv[1]], cwd="kernel/mvk_server")