added optimizer and got language/VM mostly working
--HG-- branch : mung
This commit is contained in:
parent
fe0ea2a7f9
commit
bae69502bd
13 changed files with 708 additions and 99 deletions
153
builtins.py
153
builtins.py
|
@ -1,104 +1,113 @@
|
||||||
|
from builtins_code import bi
|
||||||
builtin_map = {}
|
builtin_map = {}
|
||||||
|
|
||||||
# decorator for builtin function with "n" args
|
|
||||||
def bi(func, n):
|
|
||||||
def builtin_varg(vm):
|
|
||||||
args = vm.pop(n)
|
|
||||||
rv = func(args)
|
|
||||||
vm.push(rv)
|
|
||||||
return builtin_varg
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# manage properties
|
# manage properties
|
||||||
builtin_map.update({
|
builtin_map.update({
|
||||||
'properties': bi_properties,
|
'properties': bi.properties,
|
||||||
'add_property': bi_add_property,
|
'add_property': bi.add_property,
|
||||||
'delete_property': bi_delete_property,
|
'delete_property': bi.delete_property,
|
||||||
'clear_property': bi_clear_property,
|
'clear_property': bi.clear_property,
|
||||||
'set_property_opts': bi_set_property_opts,
|
'set_property_opts': bi.set_property_opts,
|
||||||
'get_property_opts': bi_get_property_opts,
|
'get_property_opts': bi.get_property_opts,
|
||||||
'set_property_owner': bi_set_property_owner,
|
'set_property_owner': bi.set_property_owner,
|
||||||
'get_property_owner': bi_get_property_owner,
|
'get_property_owner': bi.get_property_owner,
|
||||||
})
|
})
|
||||||
|
|
||||||
# manage files
|
# manage files
|
||||||
builtin_map.update({
|
builtin_map.update({
|
||||||
'files': bi_files,
|
'files': bi.files,
|
||||||
'add_file': bi_add_file,
|
'add_file': bi.add_file,
|
||||||
'delete_file': bi_delete_file,
|
'delete_file': bi.delete_file,
|
||||||
'set_file_opts': bi_set_file_opts,
|
'set_file_opts': bi.set_file_opts,
|
||||||
'get_file_opts': bi_get_file_opts,
|
'get_file_opts': bi.get_file_opts,
|
||||||
'set_file_owner': bi_set_file_owner,
|
'set_file_owner': bi.set_file_owner,
|
||||||
'get_file_owner': bi_get_file_owner,
|
'get_file_owner': bi.get_file_owner,
|
||||||
})
|
})
|
||||||
|
|
||||||
# manage functions
|
# manage functions
|
||||||
builtin_map.update({
|
builtin_map.update({
|
||||||
'functions': bi_functions,
|
'functions': bi.functions,
|
||||||
'add_function': bi_add_function,
|
'add_function': bi.add_function,
|
||||||
'delete_function': bi_delete_function,
|
'delete_function': bi.delete_function,
|
||||||
'set_function_code': bi_set_function_code,
|
'set_function_code': bi.set_function_code,
|
||||||
'get_function_code': bi_get_function_code,
|
'get_function_code': bi.get_function_code,
|
||||||
'set_function_opts': bi_set_function_opts,
|
'set_function_opts': bi.set_function_opts,
|
||||||
'get_function_opts': bi_get_function_opts,
|
'get_function_opts': bi.get_function_opts,
|
||||||
'set_function_args': bi_set_function_args,
|
'set_function_args': bi.set_function_args,
|
||||||
'get_function_args': bi_get_function_args,
|
'get_function_args': bi.get_function_args,
|
||||||
'set_function_owner': bi_set_function_owner,
|
'set_function_owner': bi.set_function_owner,
|
||||||
'get_function_owner': bi_get_function_owner,
|
'get_function_owner': bi.get_function_owner,
|
||||||
})
|
})
|
||||||
|
|
||||||
# server configuration
|
# server configuration
|
||||||
builtin_map.update({
|
builtin_map.update({
|
||||||
'set_server_var': bi_set_server_var,
|
'set_server_var': bi.set_server_var,
|
||||||
'get_server_var': bi_get_server_var,
|
'get_server_var': bi.get_server_var,
|
||||||
'save_database': bi_save_database,
|
'save_database': bi.save_database,
|
||||||
'shutdown': bi_shutdown,
|
'shutdown': bi.shutdown,
|
||||||
'server_info': bi_server_info,
|
'server_info': bi.server_info,
|
||||||
'time': bi_time,
|
'time': bi.time,
|
||||||
'format_time': bi_format_time,
|
'format_time': bi.format_time,
|
||||||
})
|
})
|
||||||
|
|
||||||
# manage running tasks
|
# manage running tasks
|
||||||
builtin_map.update({
|
builtin_map.update({
|
||||||
'set_perms': bi_set_perms,
|
'set_perms': bi.set_perms,
|
||||||
'get_perms': bi_get_perms,
|
'get_perms': bi.get_perms,
|
||||||
'task_id': bi_task_id,
|
'task_id': bi.task_id,
|
||||||
'kill_task': bi_kill_task,
|
'kill_task': bi.kill_task,
|
||||||
'eval': bi_eval,
|
'eval': bi.eval,
|
||||||
'fork': bi_fork,
|
'fork': bi.fork,
|
||||||
'sleep': bi_sleep,
|
'sleep': bi.sleep,
|
||||||
'resume': bi_resume,
|
'resume': bi.resume,
|
||||||
'raise': bi_raise,
|
'raise': bi.raise,
|
||||||
'stack': bi_stack,
|
'stack': bi.stack,
|
||||||
})
|
})
|
||||||
|
|
||||||
# manage objects
|
# manage objects
|
||||||
builtin_map.update({
|
builtin_map.update({
|
||||||
'create': bi_create,
|
'create': bi.create,
|
||||||
'destroy': bi_destroy,
|
'destroy': bi.destroy,
|
||||||
'set_parent': bi_set_parent,
|
'set_parent': bi.set_parent,
|
||||||
'parent': bi_parent,
|
'parent': bi.parent,
|
||||||
'children': bi_children,
|
'children': bi.children,
|
||||||
'set_owner': bi_set_owner,
|
'set_owner': bi.set_owner,
|
||||||
'owner': bi_owner,
|
'owner': bi.owner,
|
||||||
'max_object': bi_max_object,
|
'max_object': bi.max_object,
|
||||||
'renumber': bi_renumber,
|
'renumber': bi.renumber,
|
||||||
})
|
})
|
||||||
|
|
||||||
# manage connections and ports
|
# manage connections and ports
|
||||||
builtin_map.update({
|
builtin_map.update({
|
||||||
'connect': bi_connect,
|
'connect': bi.connect,
|
||||||
'disconnect': bi_disconnect,
|
'disconnect': bi.disconnect,
|
||||||
'open_connection': bi_open_connection,
|
'open_connection': bi.open_connection,
|
||||||
'close_connection': bi_close_connection,
|
'close_connection': bi.close_connection,
|
||||||
'incoming_connections': bi_incoming_connections,
|
'incoming_connections': bi.incoming_connections,
|
||||||
'outgoing_connections': bi_outgoing_connections,
|
'outgoing_connections': bi.outgoing_connections,
|
||||||
'get_connection_info': bi_get_connection_info,
|
'get_connection_info': bi.get_connection_info,
|
||||||
'set_connection_opts': bi_set_connection_opts,
|
'set_connection_opts': bi.set_connection_opts,
|
||||||
'send': bi_send,
|
'send': bi.send,
|
||||||
'recv': bi_recv,
|
'recv': bi.recv,
|
||||||
'listen': bi_listen,
|
'listen': bi.listen,
|
||||||
'unlisten': bi_unlisten,
|
'unlisten': bi.unlisten,
|
||||||
'setuid': bi_setuid,
|
'setuid': bi.setuid,
|
||||||
|
})
|
||||||
|
"""
|
||||||
|
|
||||||
|
builtin_map.update({
|
||||||
|
'serverlog': bi.serverlog,
|
||||||
|
})
|
||||||
|
|
||||||
|
"""
|
||||||
|
# builtin functions for list types
|
||||||
|
listbi_map = {}
|
||||||
|
listbi_map.update({
|
||||||
|
'length': bi.list_len,
|
||||||
|
'len': bi.list_len,
|
||||||
|
'sort': bi.list_sort,
|
||||||
})
|
})
|
||||||
"""
|
"""
|
10
builtins_code.py
Executable file
10
builtins_code.py
Executable file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
class builtin_functions(object):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def serverlog(vm, args):
|
||||||
|
print "serverlog: %s" % (args,)
|
||||||
|
|
||||||
|
bi = builtin_functions()
|
192
database.py
Executable file
192
database.py
Executable file
|
@ -0,0 +1,192 @@
|
||||||
|
from parse import static_parser
|
||||||
|
|
||||||
|
class ObjRef(object):
|
||||||
|
def __init__(self, objnum):
|
||||||
|
self.objnum = objnum
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.objnum == other.objnum
|
||||||
|
|
||||||
|
|
||||||
|
class DBObject(object):
|
||||||
|
def __init__(self, objref):
|
||||||
|
self.obj = objref
|
||||||
|
self.parent = ObjRef(-1)
|
||||||
|
self.children = []
|
||||||
|
self.props = {}
|
||||||
|
self.funcs = []
|
||||||
|
|
||||||
|
def match_local_func(self, name, flags=""):
|
||||||
|
for func in self.funcs:
|
||||||
|
skip = False
|
||||||
|
for f in flags:
|
||||||
|
if not f in o.flags:
|
||||||
|
skip = True
|
||||||
|
if not skip and func.match(name):
|
||||||
|
return func
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_property(self, prop):
|
||||||
|
if prop in self.props:
|
||||||
|
rv = self.props[prop]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def add_func(self, name):
|
||||||
|
self.funcs.append(DBFunc(self.obj, name))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DBFunc(object):
|
||||||
|
def __init__(self, objref, name):
|
||||||
|
self.obj = objref
|
||||||
|
self.name = name
|
||||||
|
self.names = name.split(' ')
|
||||||
|
self.flags = ""
|
||||||
|
self.bytecode = []
|
||||||
|
self.code = ""
|
||||||
|
|
||||||
|
def compile(self, code):
|
||||||
|
try:
|
||||||
|
bytecode = static_parser.parse(code)
|
||||||
|
except ParseError:
|
||||||
|
return [0, "Compile error in line <unknown>"]
|
||||||
|
|
||||||
|
self.bytecode = bytecode
|
||||||
|
self.code = code
|
||||||
|
return [1, "Success"]
|
||||||
|
|
||||||
|
def match(self, name):
|
||||||
|
for test in self.names:
|
||||||
|
if test[-1] == '*':
|
||||||
|
if name[:len(test)-1] == test[:-1]:
|
||||||
|
"partial match"
|
||||||
|
return True
|
||||||
|
elif test == name:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def ref(self):
|
||||||
|
return self.obj
|
||||||
|
|
||||||
|
|
||||||
|
class Database(object):
|
||||||
|
def __init__(self, dbname):
|
||||||
|
self.dbname = dbname
|
||||||
|
self.objects = []
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
raise NotImplementedError, "This function should be overridden by a derived class"
|
||||||
|
def checkpoint(self):
|
||||||
|
raise NotImplementedError, "This function should be overridden by a derived class"
|
||||||
|
def save(self):
|
||||||
|
raise NotImplementedError, "This function should be overridden by a derived class"
|
||||||
|
|
||||||
|
def bootstrap_minimal(self):
|
||||||
|
so = DBObject(ObjRef(0))
|
||||||
|
self.objects = [so]
|
||||||
|
|
||||||
|
so.
|
||||||
|
|
||||||
|
def set_property(self, obj, prop, val):
|
||||||
|
o = self.get(obj)
|
||||||
|
o.set_property(prop, val)
|
||||||
|
|
||||||
|
def set_file(self, obj, fn, val):
|
||||||
|
o = self.get(obj)
|
||||||
|
o.set_file(fn, val)
|
||||||
|
|
||||||
|
def get_property(self, obj, prop):
|
||||||
|
o = self.get(obj)
|
||||||
|
return o.get_property(prop)
|
||||||
|
|
||||||
|
def get_file(self, obj, fn):
|
||||||
|
o = self.get(obj)
|
||||||
|
return o.get_file(fn)
|
||||||
|
|
||||||
|
def create(self):
|
||||||
|
for i in xrange(len(self.objects)):
|
||||||
|
if self.objects[i] == None:
|
||||||
|
newref = ObjRef(i)
|
||||||
|
self.objects[i] = DBObject(newref)
|
||||||
|
return newref
|
||||||
|
|
||||||
|
newref = ObjRef(len(self.objects))
|
||||||
|
self.objects.append(DBObject(newref))
|
||||||
|
return newref
|
||||||
|
|
||||||
|
def destroy(self, ref):
|
||||||
|
if ref.objnum >= len(self.objects) or ref.objnum < 0:
|
||||||
|
raise ValueError, "Invalid object number"
|
||||||
|
|
||||||
|
obj = self.objects[ref.objnum]
|
||||||
|
if obj == None:
|
||||||
|
raise ValueError, "Object already destroyed"
|
||||||
|
|
||||||
|
for child in obj.children:
|
||||||
|
child.parent = ObjRef(-1)
|
||||||
|
|
||||||
|
self.objects[ref.objnum] = None
|
||||||
|
self.objects_cleanup()
|
||||||
|
|
||||||
|
def objects_cleanup(self):
|
||||||
|
i = len(self.objects)
|
||||||
|
while i > 0:
|
||||||
|
i -= 1
|
||||||
|
if self.objects[i] != None:
|
||||||
|
i += 1
|
||||||
|
break
|
||||||
|
|
||||||
|
if i < len(self.objects):
|
||||||
|
self.objects[i:] = []
|
||||||
|
|
||||||
|
def get(self, objref):
|
||||||
|
return self.objects[objref.objnum]
|
||||||
|
|
||||||
|
def match_command(self, player, cmd, vars):
|
||||||
|
vars['player'] = player
|
||||||
|
vars['caller'] = player
|
||||||
|
|
||||||
|
match_order = [player]
|
||||||
|
for ref in match_order:
|
||||||
|
match = self.match_func(self, ref, cmd)
|
||||||
|
if match:
|
||||||
|
obj, func = match
|
||||||
|
vars['this'] = ref
|
||||||
|
vars['funcname'] = func.name
|
||||||
|
vars['funcobj'] = obj
|
||||||
|
return [func, vars]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def match_func(self, obj, funcname, flags=""):
|
||||||
|
o = self.get(obj)
|
||||||
|
func = o.match_func(funcname, flags)
|
||||||
|
if func != None:
|
||||||
|
return [obj, func]
|
||||||
|
ancestor = o.parent
|
||||||
|
while ancestor != ObjRef(-1):
|
||||||
|
o = self.get(ancestor)
|
||||||
|
func = o.match_func(funcname, flags)
|
||||||
|
if func != None:
|
||||||
|
return [ancestor, func]
|
||||||
|
ancestor = o.parent
|
||||||
|
return None
|
||||||
|
|
||||||
|
def match_property(self, obj, propname):
|
||||||
|
o = self.get(obj)
|
||||||
|
prop = o.get_property(propname)
|
||||||
|
if prop != None:
|
||||||
|
return [obj, prop]
|
||||||
|
ancestor = o.parent
|
||||||
|
while ancestor != ObjRef(-1):
|
||||||
|
o = self.get(ancestor)
|
||||||
|
prop = o.get_property(propname)
|
||||||
|
if prop != None:
|
||||||
|
return [ancestor, prop]
|
||||||
|
ancestor = o.parent
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
class DSDB_Database(object):
|
class DSDB_Database(Database):
|
||||||
def __init__(self, dbname):
|
def __init__(self, dbname):
|
||||||
self.dbname = dbname
|
self.dbname = dbname
|
||||||
self.fn = "%s.dsdb" % (dbname,)
|
self.fn = "%s.dsdb" % (dbname,)
|
||||||
|
|
|
@ -3,14 +3,5 @@ class Fake_Database(object):
|
||||||
def __init__(self, dbname):
|
def __init__(self, dbname):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def set_property(self, obj, prop, val):
|
|
||||||
pass
|
|
||||||
def set_file(self, obj, fn, val):
|
|
||||||
pass
|
|
||||||
def get_property(self, obj, prop):
|
|
||||||
pass
|
|
||||||
def get_file(self, obj, fn):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
|
|
53
language.py
53
language.py
|
@ -1,6 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from builtins import builtin_map
|
from builtins import builtin_map
|
||||||
|
from database import ObjRef
|
||||||
import bisect
|
import bisect
|
||||||
import optimizer
|
import optimizer
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -65,6 +66,26 @@ def tokenparser(func):
|
||||||
|
|
||||||
return newfunc
|
return newfunc
|
||||||
|
|
||||||
|
def disallow_keywords(tokens,keywords=None):
|
||||||
|
if keywords == None:
|
||||||
|
keywords = disallow_keywords.keywords
|
||||||
|
else:
|
||||||
|
keywords = set(keywords)
|
||||||
|
|
||||||
|
for t in tokens:
|
||||||
|
if isinstance(t, VMIdent):
|
||||||
|
if t.name in keywords:
|
||||||
|
raise ParseException, "Restricted keyword: %s" % (t.name,)
|
||||||
|
elif isinstance(t, unicode):
|
||||||
|
tstr = t.encode('ascii', 'ignore')
|
||||||
|
if tstr in keywords:
|
||||||
|
raise ParseException, "Restricted keyword: %s" % (tstr,)
|
||||||
|
elif isinstance(t, str):
|
||||||
|
if t in keywords:
|
||||||
|
raise ParseException, "Restricted keyword: %s" % (t,)
|
||||||
|
|
||||||
|
disallow_keywords.keywords = set('if,elseif,else,endif,try,except,finally,endtry,while,endwhile,continue,break,for,foreach,endfor'.split(','))
|
||||||
|
|
||||||
def codejoin(*args):
|
def codejoin(*args):
|
||||||
rv = []
|
rv = []
|
||||||
for arg in args:
|
for arg in args:
|
||||||
|
@ -103,10 +124,6 @@ def uncoerce(value):
|
||||||
return value.value
|
return value.value
|
||||||
|
|
||||||
|
|
||||||
class ObjRef(object):
|
|
||||||
def __init__(self, objnum):
|
|
||||||
self.objnum = objnum
|
|
||||||
|
|
||||||
class VMBaseObject(object):
|
class VMBaseObject(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.pos = None
|
self.pos = None
|
||||||
|
@ -161,7 +178,7 @@ class VMTable(VMType):
|
||||||
class VMList(VMType):
|
class VMList(VMType):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
VMType.__init__(self)
|
VMType.__init__(self)
|
||||||
self.value = dict(value)
|
self.value = list(value)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@tokenparser
|
@tokenparser
|
||||||
|
@ -222,11 +239,12 @@ class VMIdent(VMRef):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def bytecode(self):
|
def bytecode(self):
|
||||||
return [StackLiteral(self.name)]
|
return [StackLiteral(unicode(self.name))]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@tokenparser
|
@tokenparser
|
||||||
def parse(tokens):
|
def parse(tokens):
|
||||||
|
disallow_keywords(tokens)
|
||||||
return VMIdent(tokens[0])
|
return VMIdent(tokens[0])
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -239,7 +257,7 @@ class VMVariable(VMRef):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def ref(self):
|
def ref(self):
|
||||||
return [StackLiteral(self.name)]
|
return [StackLiteral(unicode(self.name))]
|
||||||
|
|
||||||
def bytecode(self):
|
def bytecode(self):
|
||||||
return codejoin(self.ref(), GetVariable())
|
return codejoin(self.ref(), GetVariable())
|
||||||
|
@ -247,6 +265,7 @@ class VMVariable(VMRef):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@tokenparser
|
@tokenparser
|
||||||
def parse(tokens):
|
def parse(tokens):
|
||||||
|
disallow_keywords(tokens)
|
||||||
return VMVariable(tokens[0])
|
return VMVariable(tokens[0])
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -388,15 +407,17 @@ class GetVariable(CodeOp):
|
||||||
|
|
||||||
class CallBuiltin(CodeOp):
|
class CallBuiltin(CodeOp):
|
||||||
def execute(self, vm):
|
def execute(self, vm):
|
||||||
funcname, = vm.pop(1)
|
funcname, args = vm.pop(2)
|
||||||
builtin_map[funcname](vm)
|
funcname = funcname.encode('ascii', 'ignore')
|
||||||
|
retval = builtin_map[funcname](vm, args)
|
||||||
|
vm.push(retval)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@tokenparser
|
@tokenparser
|
||||||
def parse(tokens):
|
def parse(tokens):
|
||||||
if not tokens[0] in builtin_map:
|
#if not tokens[0] in builtin_map:
|
||||||
raise ParseException, 'Attempt to call undefined builtin function: "%s"' % (tokens[0],)
|
# raise ParseException, 'Attempt to call undefined builtin function: "%s"' % (tokens[0],)
|
||||||
return codejoin(StackLiteral(VMString(tokens[0])), tokens[1], CallBuiltin())
|
return codejoin(tokens[0], tokens[1], CallBuiltin())
|
||||||
|
|
||||||
class CallFunction(CodeOp):
|
class CallFunction(CodeOp):
|
||||||
def execute(self, vm):
|
def execute(self, vm):
|
||||||
|
@ -555,7 +576,7 @@ class Assignment(CodeOp):
|
||||||
|
|
||||||
class StackLiteral(StackCodeOp):
|
class StackLiteral(StackCodeOp):
|
||||||
def execute(self, vm):
|
def execute(self, vm):
|
||||||
vm.push(self.value)
|
vm.push(self.stack_value)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@tokenparser
|
@tokenparser
|
||||||
|
@ -563,6 +584,10 @@ class StackLiteral(StackCodeOp):
|
||||||
return StackLiteral(tokens[0])
|
return StackLiteral(tokens[0])
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
try:
|
||||||
|
nv = coerce(self.stack_value)
|
||||||
|
except TypeError:
|
||||||
|
return "<** INVALID STACKLITERAL: %r **>" % (self.stack_value,)
|
||||||
return "<StackLiteral %s>" % (coerce(self.stack_value),)
|
return "<StackLiteral %s>" % (coerce(self.stack_value),)
|
||||||
|
|
||||||
|
|
||||||
|
@ -585,6 +610,8 @@ class StackToList(CodeOp):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@tokenparser
|
@tokenparser
|
||||||
def parse(tokens):
|
def parse(tokens):
|
||||||
|
if not tokens:
|
||||||
|
return codejoin(StackLiteral(0), StackToList())
|
||||||
rv = codejoin(tokens[0][0], StackLiteral(len(tokens)), StackToList())
|
rv = codejoin(tokens[0][0], StackLiteral(len(tokens)), StackToList())
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
|
75
listener.py
75
listener.py
|
@ -4,6 +4,65 @@ import select
|
||||||
import random
|
import random
|
||||||
from ringbuffer import RingBuffer
|
from ringbuffer import RingBuffer
|
||||||
|
|
||||||
|
class Poller(object):
|
||||||
|
POLLIN = 1
|
||||||
|
POLLERR = 2
|
||||||
|
POLLRD = 3 # POLLIN | POLLERR
|
||||||
|
POLLWR = 4
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
try:
|
||||||
|
self.mode = select.poll()
|
||||||
|
Poller.POLLIN = select
|
||||||
|
Poller.POLLRD = select.POLLIN|select.POLLPRI|select.POLLHUP|select.POLLERR|select.POLLNVAL
|
||||||
|
Poller.POLLWR = select.POLLOUT
|
||||||
|
except:
|
||||||
|
self.mode = select.select
|
||||||
|
Poller.POLLIN = 1
|
||||||
|
Poller.POLLERR = 2
|
||||||
|
Poller.POLLRD = Poller.POLLIN|Poller.POLLERR
|
||||||
|
Poller.POLLWR = 4
|
||||||
|
|
||||||
|
self.registered = {}
|
||||||
|
|
||||||
|
def register_read(self, listener, fd):
|
||||||
|
if not fd in self.registered:
|
||||||
|
self.registered[fd.fileno()] = [0, listener, fd]
|
||||||
|
self.registered[fd.fileno()][0] |= Poller.POLLRD
|
||||||
|
if self.mode != select.select:
|
||||||
|
self.mode.register(fd.fileno(), Poller.POLLRD)
|
||||||
|
|
||||||
|
def register_write(self, listener, fd):
|
||||||
|
if not fd in self.registered:
|
||||||
|
self.registered[fd.fileno()] = [0, listener, fd]
|
||||||
|
self.registered[fd.fileno()][0] |= Poller.POLLWR
|
||||||
|
if self.mode != select.select:
|
||||||
|
self.mode.register(fd.fileno(), Poller.POLLRD|Poller.POLLWR)
|
||||||
|
|
||||||
|
def unregister(self, fd):
|
||||||
|
if self.mode == select.select and fd in self.registered:
|
||||||
|
del self.registered[fd.fileno()]
|
||||||
|
else:
|
||||||
|
self.mode.unregister(fd.fileno())
|
||||||
|
|
||||||
|
def get_fd(self, fd, flags):
|
||||||
|
return (self.registered[fd][1], self.registered[fd][2], flags)
|
||||||
|
|
||||||
|
def poll(self, timeout):
|
||||||
|
if self.mode == select.select:
|
||||||
|
rdfd = []
|
||||||
|
wrfd = []
|
||||||
|
for fd, flags in self.registered.items():
|
||||||
|
if flags & Poller.POLLRD:
|
||||||
|
rdfd.append(fd)
|
||||||
|
if flags & Poller.POLLWR:
|
||||||
|
wrfd.append(fd)
|
||||||
|
r, w, x = select.select(rdfd, wrfd, rdfd, timeout)
|
||||||
|
return [self.get_fd(fd, Poller.POLLIN) for fd in r] + [self.get_fd(fd, Poller.POLLWR) for fd in w] + [self.get_fd(fd, Poller.POLLERR) for fd in x]
|
||||||
|
else:
|
||||||
|
timeout = int(round(timeout * 1000.0, 0))
|
||||||
|
return [self.get_fd(fd, flags) for fd, flags in self.mode.poll(timeout)]
|
||||||
|
|
||||||
class Connection(object):
|
class Connection(object):
|
||||||
def __init__(self, id, conn, addr):
|
def __init__(self, id, conn, addr):
|
||||||
self.id = id
|
self.id = id
|
||||||
|
@ -75,6 +134,7 @@ class Listener(object):
|
||||||
self.connections = {}
|
self.connections = {}
|
||||||
self.connection_list = []
|
self.connection_list = []
|
||||||
self.connection_list_dirty = False
|
self.connection_list_dirty = False
|
||||||
|
self.remove_from_poller = []
|
||||||
|
|
||||||
self.MAX_CONN = 3000
|
self.MAX_CONN = 3000
|
||||||
|
|
||||||
|
@ -108,6 +168,7 @@ class Listener(object):
|
||||||
def delete_connection(self, conn):
|
def delete_connection(self, conn):
|
||||||
print "%s disconnected." % (conn.id,)
|
print "%s disconnected." % (conn.id,)
|
||||||
del self.connections[conn.id]
|
del self.connections[conn.id]
|
||||||
|
self.remove_from_poller.append(conn.conn)
|
||||||
self.connection_list_dirty = True
|
self.connection_list_dirty = True
|
||||||
|
|
||||||
def all_connections(self):
|
def all_connections(self):
|
||||||
|
@ -147,10 +208,22 @@ class Listener(object):
|
||||||
else:
|
else:
|
||||||
callback(conn, input)
|
callback(conn, input)
|
||||||
|
|
||||||
|
def update_poller(self, poll):
|
||||||
|
for dconn in self.delete_from_poller:
|
||||||
|
poll.unregister(dconn)
|
||||||
|
self.delete_from_poller = []
|
||||||
|
for conn in self.all_connections():
|
||||||
|
if conn.output_waiting():
|
||||||
|
poll.register_write(self, conn.conn)
|
||||||
|
else:
|
||||||
|
poll.register_read(self, conn.conn)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def flush_output(self):
|
def flush_output(self):
|
||||||
for conn in self.all_connections():
|
for conn in self.all_connections():
|
||||||
if conn.output_waiting():
|
if conn.output_waiting():
|
||||||
conn.flush_output()
|
conn.flush_buffer()
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
for x in self.connection_list:
|
for x in self.connection_list:
|
||||||
|
|
54
optimizer.py
Executable file
54
optimizer.py
Executable file
|
@ -0,0 +1,54 @@
|
||||||
|
from pyparsing import ParseResults
|
||||||
|
|
||||||
|
def flatten_orig(l, ltypes=(list, tuple)):
|
||||||
|
ltype = type(l)
|
||||||
|
l = list(l)
|
||||||
|
i = 0
|
||||||
|
while i < len(l):
|
||||||
|
while isinstance(l[i], ltypes):
|
||||||
|
if not l[i]:
|
||||||
|
l.pop(i)
|
||||||
|
i -= 1
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
l[i:i + 1] = l[i]
|
||||||
|
i += 1
|
||||||
|
return ltype(l)
|
||||||
|
|
||||||
|
def bytecode_flatten(l, ltypes=(list, tuple, ParseResults)):
|
||||||
|
l = list(l)
|
||||||
|
i = 0
|
||||||
|
while i < len(l):
|
||||||
|
broken = False
|
||||||
|
while isinstance(l[i], ltypes):
|
||||||
|
if not l[i]:
|
||||||
|
l.pop(i)
|
||||||
|
broken = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
l[i:i + 1] = list(l[i])
|
||||||
|
if broken:
|
||||||
|
continue
|
||||||
|
assert not isinstance(l[i], ltypes)
|
||||||
|
assert not isinstance(l[i], (str, unicode, dict))
|
||||||
|
bc = l[i].bytecode()
|
||||||
|
if len(bc) > 1 or bc[0] != l[i]:
|
||||||
|
l[i:i+1] = bc
|
||||||
|
continue
|
||||||
|
i += 1
|
||||||
|
return l
|
||||||
|
|
||||||
|
def optimize(data):
|
||||||
|
"""
|
||||||
|
yeah, this is some pretty intense optimiziation, I know...
|
||||||
|
it will hopefully be expanded on later...
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = bytecode_flatten(data)
|
||||||
|
|
||||||
|
for x in data:
|
||||||
|
if not hasattr(x, "pos"):
|
||||||
|
print "Missing position on element %s" % (x,)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
18
parse.py
18
parse.py
|
@ -61,7 +61,7 @@ class Parser(object):
|
||||||
propref = (objrefexpr + point + ident).setParseAction(VMPropRef.parse) | coreref
|
propref = (objrefexpr + point + ident).setParseAction(VMPropRef.parse) | coreref
|
||||||
fileref = (objrefexpr + excl + ident).setParseAction(VMFileRef.parse)
|
fileref = (objrefexpr + excl + ident).setParseAction(VMFileRef.parse)
|
||||||
|
|
||||||
argspec = delimitedList(expr)
|
argspec = Optional(delimitedList(expr))
|
||||||
argspec.setParseAction(StackToList.parse)
|
argspec.setParseAction(StackToList.parse)
|
||||||
funccall = objrefexpr + call + identexpr + lpar + argspec + rpar
|
funccall = objrefexpr + call + identexpr + lpar + argspec + rpar
|
||||||
|
|
||||||
|
@ -174,12 +174,25 @@ class Parser(object):
|
||||||
self.parser = block
|
self.parser = block
|
||||||
#print argspec.parseString("hello(hi.xyz)", parseAll=True)
|
#print argspec.parseString("hello(hi.xyz)", parseAll=True)
|
||||||
#print block.parseString(u"hi.xyz + #555.test;", parseAll=True)
|
#print block.parseString(u"hi.xyz + #555.test;", parseAll=True)
|
||||||
|
#print block.parseString("""serverlog();""")
|
||||||
|
|
||||||
def parse(self, data):
|
def parse(self, data):
|
||||||
rv = self.parser.parseString(data, parseAll=True)
|
rv = self.parser.parseString(data, parseAll=True)
|
||||||
|
|
||||||
return optimizer.optimize(rv)
|
return optimizer.optimize(rv)
|
||||||
|
|
||||||
|
def parse_command(self, line):
|
||||||
|
ls = line.split(' ')
|
||||||
|
cmd = ls[0]
|
||||||
|
argstr = ' '.join(ls[1:])
|
||||||
|
vars = {
|
||||||
|
'cmdstr': line,
|
||||||
|
'cmd': cmd,
|
||||||
|
'argstr': argstr,
|
||||||
|
'args': [x.strip() for x in ls[1:] if x.strip() != '']
|
||||||
|
}
|
||||||
|
|
||||||
|
return [cmd, vars]
|
||||||
|
|
||||||
def test(self):
|
def test(self):
|
||||||
#print self.parse(u"if (1) #740.xyz + -hello.world; endif")
|
#print self.parse(u"if (1) #740.xyz + -hello.world; endif")
|
||||||
|
@ -187,6 +200,9 @@ class Parser(object):
|
||||||
data = unicode(open("test.moo", "r").read(), 'utf-8')
|
data = unicode(open("test.moo", "r").read(), 'utf-8')
|
||||||
print self.parse(data)
|
print self.parse(data)
|
||||||
|
|
||||||
|
|
||||||
|
static_parser = Parser()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
p = Parser()
|
p = Parser()
|
||||||
p.test()
|
p.test()
|
||||||
|
|
24
server.py
24
server.py
|
@ -1,7 +1,8 @@
|
||||||
import os, sys, time
|
import os, sys, time
|
||||||
from listener import Listener
|
from listener import Listener, Poller
|
||||||
from language import VirtualMachine
|
from language import VirtualMachine
|
||||||
from database_fake import Fake_Database as Database
|
from database_fake import Fake_Database as Database
|
||||||
|
from parse import static_parser
|
||||||
|
|
||||||
class Server(object):
|
class Server(object):
|
||||||
def __init__(self, dbname):
|
def __init__(self, dbname):
|
||||||
|
@ -14,16 +15,24 @@ class Server(object):
|
||||||
self.server_started = None
|
self.server_started = None
|
||||||
self.loop_started = None
|
self.loop_started = None
|
||||||
self.listeners = []
|
self.listeners = []
|
||||||
|
self.poller = Poller()
|
||||||
|
|
||||||
def listen(self, addr, port):
|
def listen(self, addr, port):
|
||||||
l = Listener()
|
l = Listener()
|
||||||
l.listen(addr, port)
|
l.listen(addr, port)
|
||||||
self.listeners.append(l)
|
self.listeners.append(l)
|
||||||
|
|
||||||
|
def unlisten(self, addr, port):
|
||||||
|
l = Listener()
|
||||||
|
l.listen(addr, port)
|
||||||
|
self.listeners.append(l)
|
||||||
|
|
||||||
def mainloop(self):
|
def mainloop(self):
|
||||||
self.server_started = time.time()
|
self.server_started = time.time()
|
||||||
while True:
|
while True:
|
||||||
self.loop_started = time.time()
|
self.loop_started = time.time()
|
||||||
|
|
||||||
|
"""
|
||||||
for l in self.listeners:
|
for l in self.listeners:
|
||||||
l.handle_incoming_connections()
|
l.handle_incoming_connections()
|
||||||
l.scan_for_input(self.read_input)
|
l.scan_for_input(self.read_input)
|
||||||
|
@ -31,6 +40,9 @@ class Server(object):
|
||||||
for l in self.listeners:
|
for l in self.listeners:
|
||||||
l.flush_output()
|
l.flush_output()
|
||||||
self.idlewait()
|
self.idlewait()
|
||||||
|
"""
|
||||||
|
self.poller.poll(self.get_sleepytime())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def read_input(self, conn, data):
|
def read_input(self, conn, data):
|
||||||
|
@ -39,6 +51,16 @@ class Server(object):
|
||||||
del ds[-1]
|
del ds[-1]
|
||||||
for line in ds:
|
for line in ds:
|
||||||
print "%s: %s" % (conn.id, line)
|
print "%s: %s" % (conn.id, line)
|
||||||
|
cmd, vars = static_parser.parse_command(line)
|
||||||
|
self.db.match_command(cmd, vars)
|
||||||
|
|
||||||
|
def get_sleepytime(self):
|
||||||
|
if self.vm.sleepytime == None:
|
||||||
|
"virtual machine is still busy, no sleeping on the job!"
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return self.vm.sleepytime
|
||||||
|
|
||||||
|
|
||||||
def idlewait(self):
|
def idlewait(self):
|
||||||
if self.vm.sleepytime == None:
|
if self.vm.sleepytime == None:
|
||||||
|
|
8
test.moo
Executable file
8
test.moo
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
serverlog("hello");
|
||||||
|
part = 1;
|
||||||
|
if (part)
|
||||||
|
vvv = 3;
|
||||||
|
vxx = "abc";
|
||||||
|
else
|
||||||
|
vvv = #-1; vvx = $nothing;
|
||||||
|
endif
|
9
tt.py
Executable file
9
tt.py
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
from virtualmachine import VirtualMachine
|
||||||
|
from parse import Parser
|
||||||
|
|
||||||
|
p = Parser()
|
||||||
|
vm = VirtualMachine(None)
|
||||||
|
bytecode = p.parse("""serverlog("hello"); var1 = var2;""")
|
||||||
|
vm.spawn_cmd_task(bytecode, {})
|
||||||
|
|
||||||
|
vm.run()
|
198
virtualmachine.py
Executable file
198
virtualmachine.py
Executable file
|
@ -0,0 +1,198 @@
|
||||||
|
import random, heapq
|
||||||
|
from parse import Parser
|
||||||
|
from language import *
|
||||||
|
|
||||||
|
|
||||||
|
class VMContext(object):
|
||||||
|
def __init__(self, vars):
|
||||||
|
self.variables = vars
|
||||||
|
|
||||||
|
class VMTask(object):
|
||||||
|
def __init__(self, id, code, vars):
|
||||||
|
self.task_id = id
|
||||||
|
self.code_stack = [x for x in reversed(code)]
|
||||||
|
self.exc_stack = []
|
||||||
|
self.stack = []
|
||||||
|
self.contexts = [VMContext(vars)]
|
||||||
|
|
||||||
|
def context(self):
|
||||||
|
return self.contexts[-1]
|
||||||
|
|
||||||
|
class VirtualMachine(object):
|
||||||
|
def __init__(self, db):
|
||||||
|
self.db = db
|
||||||
|
self.active_task_id = None
|
||||||
|
self.sleepytime = None
|
||||||
|
self.contexts = []
|
||||||
|
self.tasks = {}
|
||||||
|
self.task = None
|
||||||
|
self.active_task_heap = []
|
||||||
|
self.next_task_heap = []
|
||||||
|
self.ticks_used = 0
|
||||||
|
self.max_ticks = 300000
|
||||||
|
self.max_tasks = 2**16
|
||||||
|
|
||||||
|
|
||||||
|
def generate_task_id(self):
|
||||||
|
rv = random.randint(1,self.max_tasks)
|
||||||
|
if len(self.tasks) >= self.max_tasks:
|
||||||
|
raise RangeError, "Maximum number of tasks exceeded"
|
||||||
|
while rv in self.tasks:
|
||||||
|
rv += 1
|
||||||
|
if rv > self.max_tasks:
|
||||||
|
rv = 1
|
||||||
|
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
def spawn_cmd_task(self, bytecode, vars):
|
||||||
|
task = VMTask(self.generate_task_id(), bytecode, vars)
|
||||||
|
self.tasks[task.task_id] = task
|
||||||
|
heapq.heappush(self.active_task_heap, (time.time(), task.task_id, task))
|
||||||
|
|
||||||
|
def spawn_forked_task(self, bytecode, vars):
|
||||||
|
task = VMTask(self.generate_task_id(), bytecode, vars)
|
||||||
|
self.tasks[task.task_id] = task
|
||||||
|
heapq.heappush(self.next_task_heap, (time.time(), task.task_id, task))
|
||||||
|
|
||||||
|
def code_pop(self):
|
||||||
|
return self.task.code_stack.pop()
|
||||||
|
|
||||||
|
def code_push(self, code):
|
||||||
|
if isinstance(code, CodeOpSequence):
|
||||||
|
for op in reverse(code):
|
||||||
|
self.task.code_stack.append(op)
|
||||||
|
else:
|
||||||
|
self.task.code_stack.append(code)
|
||||||
|
|
||||||
|
def exc_pop(self):
|
||||||
|
return self.task.exc_stack.pop()
|
||||||
|
|
||||||
|
def exc_push(self, exc):
|
||||||
|
self.task.exc_stack.append(exc)
|
||||||
|
|
||||||
|
def pop(self, count=1):
|
||||||
|
stack = [uncoerce(self.task.stack.pop()) for x in xrange(count)]
|
||||||
|
return [x for x in reversed(stack)]
|
||||||
|
|
||||||
|
def pop_raw(self, count=1):
|
||||||
|
stack = [self.task.stack.pop() for x in xrange(count)]
|
||||||
|
return [x for x in reversed(stack)]
|
||||||
|
|
||||||
|
def push(self, value):
|
||||||
|
self.task.stack.append(coerce(value))
|
||||||
|
|
||||||
|
def setvar(self, varname, val):
|
||||||
|
self.task.context().variables[varname] = val
|
||||||
|
|
||||||
|
def getvar(self, varname):
|
||||||
|
return self.task.context().variables[varname]
|
||||||
|
|
||||||
|
def push_context(self):
|
||||||
|
self.task.contexts.append(VMContext())
|
||||||
|
|
||||||
|
def pop_context(self):
|
||||||
|
self.task.contexts.pop()
|
||||||
|
|
||||||
|
if not self.task.contexts:
|
||||||
|
del self.tasks[self.active_task_id]
|
||||||
|
self.active_task_id = None
|
||||||
|
self.task = None
|
||||||
|
self.finished_start_next()
|
||||||
|
|
||||||
|
def suspend_start_next(self, delay):
|
||||||
|
now = time.time()
|
||||||
|
newtask = heapq.heappop(self.active_task_heap)
|
||||||
|
heapq.heappush(self.next_task_heap, (now+max(0.0,delay), self.active_task_id, self.task))
|
||||||
|
return self.activate_task(newtask)
|
||||||
|
|
||||||
|
def finished_start_next(self):
|
||||||
|
if self.active_task_heap:
|
||||||
|
now = time.time()
|
||||||
|
newtask = heapq.heappop(self.active_task_heap)
|
||||||
|
return self.activate_task(newtask)
|
||||||
|
|
||||||
|
def activate_task(self, task):
|
||||||
|
now = time.time()
|
||||||
|
if now < task[0]:
|
||||||
|
"task isn't ready to execute yet"
|
||||||
|
self.sleepytime = task[0] - now
|
||||||
|
heapq.heappush(self.next_task_heap, task)
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.active_task_id = task[1]
|
||||||
|
self.task = task[2]
|
||||||
|
self.ticks_used = 0
|
||||||
|
|
||||||
|
def uncaught_exception(self):
|
||||||
|
for exc in self.task.exc_stack:
|
||||||
|
print "Unhandled exception: %s" % (exc,)
|
||||||
|
|
||||||
|
def run_active_task(self):
|
||||||
|
task_id = self.active_task_id
|
||||||
|
while task_id == self.active_task_id and self.task.code_stack:
|
||||||
|
nextop = self.code_pop()
|
||||||
|
self.execute(nextop)
|
||||||
|
|
||||||
|
if self.task.exc_stack:
|
||||||
|
self.uncaught_exception()
|
||||||
|
self.finished_start_next()
|
||||||
|
|
||||||
|
if task_id == self.active_task_id:
|
||||||
|
self.finished_start_next()
|
||||||
|
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.sleepytime = None
|
||||||
|
if self.active_task_id == None:
|
||||||
|
self.finished_start_next()
|
||||||
|
if self.active_task_id == None:
|
||||||
|
"vm is idle"
|
||||||
|
return
|
||||||
|
self.run_active_task()
|
||||||
|
|
||||||
|
|
||||||
|
def jump(self, target):
|
||||||
|
while self.code_stack:
|
||||||
|
nextop = self.code_pop()
|
||||||
|
if isinstance(nextop, EndBlock):
|
||||||
|
if nextop.label == target:
|
||||||
|
self.execute(nextop)
|
||||||
|
break
|
||||||
|
|
||||||
|
def jump_code(self, target):
|
||||||
|
while self.code_stack:
|
||||||
|
nextop = self.code_pop()
|
||||||
|
if type(nextop) == target:
|
||||||
|
if isinstance(nextop, target):
|
||||||
|
self.execute(nextop)
|
||||||
|
break
|
||||||
|
if isinstance(nextop, EndBlock):
|
||||||
|
if nextop.label == target:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def raise_exc(self, exc=None):
|
||||||
|
if exc != None:
|
||||||
|
self.exc_push(exc)
|
||||||
|
|
||||||
|
while self.code_stack:
|
||||||
|
nextop = self.code_pop()
|
||||||
|
if isinstance(nextop, ExcHandlerBlock):
|
||||||
|
break
|
||||||
|
elif isinstance(nextop, FinallyBlock):
|
||||||
|
break
|
||||||
|
|
||||||
|
self.execute(nextop)
|
||||||
|
|
||||||
|
def execute(self, op):
|
||||||
|
self.ticks_used += op.ticks()
|
||||||
|
if self.ticks_used > self.max_ticks:
|
||||||
|
"ran out of ticks"
|
||||||
|
self.exc_push("out of ticks exception")
|
||||||
|
self.uncaught_exception()
|
||||||
|
self.finished_start_next()
|
||||||
|
else:
|
||||||
|
print "executing %s with stack %s" % (op, self.task.stack)
|
||||||
|
#op.load_stack(self)
|
||||||
|
op.execute(self)
|
Loading…
Add table
Reference in a new issue