progress on mung server
--HG-- branch : mung
This commit is contained in:
parent
8a5b25e6b0
commit
d3f845144e
11 changed files with 826 additions and 18 deletions
|
@ -3,7 +3,7 @@
|
||||||
CALLBUILTIN eval argstr
|
CALLBUILTIN eval argstr
|
||||||
.
|
.
|
||||||
:"handle_connection" x *
|
:"handle_connection" x *
|
||||||
RETURN #0;
|
RETURN #0
|
||||||
.
|
.
|
||||||
|
|
||||||
|
|
||||||
|
|
104
builtins.py
Executable file
104
builtins.py
Executable file
|
@ -0,0 +1,104 @@
|
||||||
|
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
|
||||||
|
builtin_map.update({
|
||||||
|
'properties': bi_properties,
|
||||||
|
'add_property': bi_add_property,
|
||||||
|
'delete_property': bi_delete_property,
|
||||||
|
'clear_property': bi_clear_property,
|
||||||
|
'set_property_opts': bi_set_property_opts,
|
||||||
|
'get_property_opts': bi_get_property_opts,
|
||||||
|
'set_property_owner': bi_set_property_owner,
|
||||||
|
'get_property_owner': bi_get_property_owner,
|
||||||
|
})
|
||||||
|
|
||||||
|
# manage files
|
||||||
|
builtin_map.update({
|
||||||
|
'files': bi_files,
|
||||||
|
'add_file': bi_add_file,
|
||||||
|
'delete_file': bi_delete_file,
|
||||||
|
'set_file_opts': bi_set_file_opts,
|
||||||
|
'get_file_opts': bi_get_file_opts,
|
||||||
|
'set_file_owner': bi_set_file_owner,
|
||||||
|
'get_file_owner': bi_get_file_owner,
|
||||||
|
})
|
||||||
|
|
||||||
|
# manage functions
|
||||||
|
builtin_map.update({
|
||||||
|
'functions': bi_functions,
|
||||||
|
'add_function': bi_add_function,
|
||||||
|
'delete_function': bi_delete_function,
|
||||||
|
'set_function_code': bi_set_function_code,
|
||||||
|
'get_function_code': bi_get_function_code,
|
||||||
|
'set_function_opts': bi_set_function_opts,
|
||||||
|
'get_function_opts': bi_get_function_opts,
|
||||||
|
'set_function_args': bi_set_function_args,
|
||||||
|
'get_function_args': bi_get_function_args,
|
||||||
|
'set_function_owner': bi_set_function_owner,
|
||||||
|
'get_function_owner': bi_get_function_owner,
|
||||||
|
})
|
||||||
|
|
||||||
|
# server configuration
|
||||||
|
builtin_map.update({
|
||||||
|
'set_server_var': bi_set_server_var,
|
||||||
|
'get_server_var': bi_get_server_var,
|
||||||
|
'save_database': bi_save_database,
|
||||||
|
'shutdown': bi_shutdown,
|
||||||
|
'server_info': bi_server_info,
|
||||||
|
'time': bi_time,
|
||||||
|
'format_time': bi_format_time,
|
||||||
|
})
|
||||||
|
|
||||||
|
# manage running tasks
|
||||||
|
builtin_map.update({
|
||||||
|
'set_perms': bi_set_perms,
|
||||||
|
'get_perms': bi_get_perms,
|
||||||
|
'task_id': bi_task_id,
|
||||||
|
'kill_task': bi_kill_task,
|
||||||
|
'eval': bi_eval,
|
||||||
|
'fork': bi_fork,
|
||||||
|
'sleep': bi_sleep,
|
||||||
|
'resume': bi_resume,
|
||||||
|
'raise': bi_raise,
|
||||||
|
'stack': bi_stack,
|
||||||
|
})
|
||||||
|
|
||||||
|
# manage objects
|
||||||
|
builtin_map.update({
|
||||||
|
'create': bi_create,
|
||||||
|
'destroy': bi_destroy,
|
||||||
|
'set_parent': bi_set_parent,
|
||||||
|
'parent': bi_parent,
|
||||||
|
'children': bi_children,
|
||||||
|
'set_owner': bi_set_owner,
|
||||||
|
'owner': bi_owner,
|
||||||
|
'max_object': bi_max_object,
|
||||||
|
'renumber': bi_renumber,
|
||||||
|
})
|
||||||
|
|
||||||
|
# manage connections and ports
|
||||||
|
builtin_map.update({
|
||||||
|
'connect': bi_connect,
|
||||||
|
'disconnect': bi_disconnect,
|
||||||
|
'open_connection': bi_open_connection,
|
||||||
|
'close_connection': bi_close_connection,
|
||||||
|
'incoming_connections': bi_incoming_connections,
|
||||||
|
'outgoing_connections': bi_outgoing_connections,
|
||||||
|
'get_connection_info': bi_get_connection_info,
|
||||||
|
'set_connection_opts': bi_set_connection_opts,
|
||||||
|
'send': bi_send,
|
||||||
|
'recv': bi_recv,
|
||||||
|
'listen': bi_listen,
|
||||||
|
'unlisten': bi_unlisten,
|
||||||
|
'setuid': bi_setuid,
|
||||||
|
})
|
||||||
|
"""
|
|
@ -1,3 +1,11 @@
|
||||||
|
|
||||||
|
|
||||||
|
class DSDB_Database(object):
|
||||||
|
def __init__(self, dbname):
|
||||||
|
self.dbname = dbname
|
||||||
|
self.fn = "%s.dsdb" % (dbname,)
|
||||||
|
self.load_from_file()
|
||||||
|
|
||||||
|
def load_from_file(self):
|
||||||
|
fd = open(self.fn, 'rb')
|
||||||
|
fd
|
||||||
|
|
16
database_fake.py
Executable file
16
database_fake.py
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
class Fake_Database(object):
|
||||||
|
def __init__(self, dbname):
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
149
ebnf.py
Executable file
149
ebnf.py
Executable file
|
@ -0,0 +1,149 @@
|
||||||
|
# This module tries to implement ISO 14977 standard with pyparsing.
|
||||||
|
# pyparsing version 1.1 or greater is required.
|
||||||
|
|
||||||
|
# ISO 14977 standardize The Extended Backus-Naur Form(EBNF) syntax.
|
||||||
|
# You can read a final draft version here:
|
||||||
|
# http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html
|
||||||
|
|
||||||
|
|
||||||
|
from pyparsing import *
|
||||||
|
|
||||||
|
|
||||||
|
all_names = '''
|
||||||
|
integer
|
||||||
|
meta_identifier
|
||||||
|
terminal_string
|
||||||
|
optional_sequence
|
||||||
|
repeated_sequence
|
||||||
|
grouped_sequence
|
||||||
|
syntactic_primary
|
||||||
|
syntactic_factor
|
||||||
|
syntactic_term
|
||||||
|
single_definition
|
||||||
|
definitions_list
|
||||||
|
syntax_rule
|
||||||
|
syntax
|
||||||
|
'''.split()
|
||||||
|
|
||||||
|
|
||||||
|
integer = Word(nums)
|
||||||
|
meta_identifier = Word(alphas, alphanums + '_')
|
||||||
|
terminal_string = Suppress("'") + CharsNotIn("'") + Suppress("'") ^ \
|
||||||
|
Suppress('"') + CharsNotIn('"') + Suppress('"')
|
||||||
|
definitions_list = Forward()
|
||||||
|
optional_sequence = Suppress('[') + definitions_list + Suppress(']')
|
||||||
|
repeated_sequence = Suppress('{') + definitions_list + Suppress('}')
|
||||||
|
grouped_sequence = Suppress('(') + definitions_list + Suppress(')')
|
||||||
|
syntactic_primary = optional_sequence ^ repeated_sequence ^ \
|
||||||
|
grouped_sequence ^ meta_identifier ^ terminal_string
|
||||||
|
syntactic_factor = Optional(integer + Suppress('*')) + syntactic_primary
|
||||||
|
syntactic_term = syntactic_factor + Optional(Suppress('-') + syntactic_factor)
|
||||||
|
single_definition = delimitedList(syntactic_term, ',')
|
||||||
|
definitions_list << delimitedList(single_definition, '|')
|
||||||
|
syntax_rule = meta_identifier + Suppress('=') + definitions_list + \
|
||||||
|
Suppress(';')
|
||||||
|
|
||||||
|
ebnfComment = ( "(*" +
|
||||||
|
ZeroOrMore( CharsNotIn("*") | ( "*" + ~Literal(")") ) ) +
|
||||||
|
"*)" ).streamline().setName("ebnfComment")
|
||||||
|
|
||||||
|
syntax = OneOrMore(syntax_rule)
|
||||||
|
syntax.ignore(ebnfComment)
|
||||||
|
|
||||||
|
|
||||||
|
def do_integer(str, loc, toks):
|
||||||
|
return int(toks[0])
|
||||||
|
|
||||||
|
def do_meta_identifier(str, loc, toks):
|
||||||
|
if toks[0] in symbol_table:
|
||||||
|
return symbol_table[toks[0]]
|
||||||
|
else:
|
||||||
|
forward_count.value += 1
|
||||||
|
symbol_table[toks[0]] = Forward()
|
||||||
|
return symbol_table[toks[0]]
|
||||||
|
|
||||||
|
def do_terminal_string(str, loc, toks):
|
||||||
|
return Literal(toks[0])
|
||||||
|
|
||||||
|
def do_optional_sequence(str, loc, toks):
|
||||||
|
return Optional(toks[0])
|
||||||
|
|
||||||
|
def do_repeated_sequence(str, loc, toks):
|
||||||
|
return ZeroOrMore(toks[0])
|
||||||
|
|
||||||
|
def do_grouped_sequence(str, loc, toks):
|
||||||
|
return Group(toks[0])
|
||||||
|
|
||||||
|
def do_syntactic_primary(str, loc, toks):
|
||||||
|
return toks[0]
|
||||||
|
|
||||||
|
def do_syntactic_factor(str, loc, toks):
|
||||||
|
if len(toks) == 2:
|
||||||
|
# integer * syntactic_primary
|
||||||
|
return And([toks[1]] * toks[0])
|
||||||
|
else:
|
||||||
|
# syntactic_primary
|
||||||
|
return [ toks[0] ]
|
||||||
|
|
||||||
|
def do_syntactic_term(str, loc, toks):
|
||||||
|
if len(toks) == 2:
|
||||||
|
# syntactic_factor - syntactic_factor
|
||||||
|
return NotAny(toks[1]) + toks[0]
|
||||||
|
else:
|
||||||
|
# syntactic_factor
|
||||||
|
return [ toks[0] ]
|
||||||
|
|
||||||
|
def do_single_definition(str, loc, toks):
|
||||||
|
toks = toks.asList()
|
||||||
|
if len(toks) > 1:
|
||||||
|
# syntactic_term , syntactic_term , ...
|
||||||
|
return And(toks)
|
||||||
|
else:
|
||||||
|
# syntactic_term
|
||||||
|
return [ toks[0] ]
|
||||||
|
|
||||||
|
def do_definitions_list(str, loc, toks):
|
||||||
|
toks = toks.asList()
|
||||||
|
if len(toks) > 1:
|
||||||
|
# single_definition | single_definition | ...
|
||||||
|
return Or(toks)
|
||||||
|
else:
|
||||||
|
# single_definition
|
||||||
|
return [ toks[0] ]
|
||||||
|
|
||||||
|
def do_syntax_rule(str, loc, toks):
|
||||||
|
# meta_identifier = definitions_list ;
|
||||||
|
assert toks[0].expr is None, "Duplicate definition"
|
||||||
|
forward_count.value -= 1
|
||||||
|
toks[0] << toks[1]
|
||||||
|
return [ toks[0] ]
|
||||||
|
|
||||||
|
def do_syntax(str, loc, toks):
|
||||||
|
# syntax_rule syntax_rule ...
|
||||||
|
return symbol_table
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
symbol_table = {}
|
||||||
|
class forward_count:
|
||||||
|
pass
|
||||||
|
forward_count.value = 0
|
||||||
|
for name in all_names:
|
||||||
|
expr = vars()[name]
|
||||||
|
action = vars()['do_' + name]
|
||||||
|
expr.setName(name)
|
||||||
|
expr.setParseAction(action)
|
||||||
|
#~ expr.setDebug()
|
||||||
|
|
||||||
|
|
||||||
|
def parse(ebnf, given_table={}):
|
||||||
|
symbol_table.clear()
|
||||||
|
symbol_table.update(given_table)
|
||||||
|
forward_count.value = 0
|
||||||
|
table = syntax.parseString(ebnf)[0]
|
||||||
|
assert forward_count.value == 0, "Missing definition"
|
||||||
|
for name in table:
|
||||||
|
expr = table[name]
|
||||||
|
expr.setName(name)
|
||||||
|
#~ expr.setDebug()
|
||||||
|
return table
|
129
language.py
129
language.py
|
@ -1,20 +1,121 @@
|
||||||
|
import time
|
||||||
|
from builtins import builtin_map
|
||||||
|
from language_types import coerce, uncoerce
|
||||||
|
|
||||||
from ply import lex
|
class VirtualMachine(object):
|
||||||
|
def __init__(self, db):
|
||||||
|
self.db = db
|
||||||
|
self.active_task_id = None
|
||||||
|
self.sleepytime = None
|
||||||
|
self.stack = []
|
||||||
|
self.contexts = []
|
||||||
|
self.tasks = {}
|
||||||
|
self.task_sequence = []
|
||||||
|
self.ticks_used = 0
|
||||||
|
|
||||||
|
def pop(self, count=1):
|
||||||
|
return [uncoerce(self.stack.pop()) for x in range(count)]
|
||||||
|
|
||||||
|
def push(self, value):
|
||||||
|
self.stack.append(coerce(value))
|
||||||
|
|
||||||
|
def setvar(self, varname, val):
|
||||||
|
self.contexts[-1][varname] = val
|
||||||
|
|
||||||
|
def getvar(self, varname):
|
||||||
|
return self.contexts[-1][varname]
|
||||||
|
|
||||||
|
def push_context(self):
|
||||||
|
self.contexts.append({})
|
||||||
|
|
||||||
|
def pop_context(self):
|
||||||
|
self.contexts.pop()
|
||||||
|
|
||||||
|
def suspend_start_next(self, delay):
|
||||||
|
now = time.time()
|
||||||
|
newtask = heapq.heappushpop(self.task_sequence, (now+max(0.0,delay), self.stack, self.contexts, self.ticks_used))
|
||||||
|
return activate_task(newtask)
|
||||||
|
|
||||||
|
def finished_start_next(self):
|
||||||
|
now = time.time()
|
||||||
|
newtask = heapq.heappop(self.task_sequence)
|
||||||
|
return activate_task(newtask)
|
||||||
|
|
||||||
|
def activate_task(self, task):
|
||||||
|
if now < task[0]:
|
||||||
|
"task isn't ready to execute yet"
|
||||||
|
self.sleepytime = task[0] - now
|
||||||
|
heapq.heappush(self.task_sequence, task[0])
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.active_task_id = task[0]
|
||||||
|
self.stack = task[1]
|
||||||
|
self.contexts = task[2]
|
||||||
|
self.ticks_used = task[3]
|
||||||
|
|
||||||
|
def get_next_task(self):
|
||||||
|
heapq.heappop(self.task_sequence)
|
||||||
|
|
||||||
|
def run_active_task
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.sleepytime = None
|
||||||
|
if self.active_task_id == None:
|
||||||
|
finished_start_next()
|
||||||
|
if self.active_task_id == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tokens = (
|
class CodeOp(object):
|
||||||
"OPERATION",
|
def __init__(self):
|
||||||
"LITERAL",
|
pass
|
||||||
"VARIABLE"
|
|
||||||
)
|
class GetProperty(CodeOp):
|
||||||
|
def execute(self, vm):
|
||||||
|
prop, obj = vm.pop(2)
|
||||||
|
vm.stack.append(vm.db.get_property(obj, prop))
|
||||||
|
|
||||||
t_OPERATION = (
|
class SetProperty(CodeOp):
|
||||||
r"CALLBUILTIN|CALLFUNC|SETVAR|RETURN"
|
def execute(self, vm):
|
||||||
)
|
val, prop, obj = vm.pop(3)
|
||||||
|
vm.db.set_property(obj, prop, val)
|
||||||
|
|
||||||
t_LITERAL = (
|
class GetFile(CodeOp):
|
||||||
r'"i"'
|
def execute(self, vm):
|
||||||
)
|
prop, obj = vm.pop(2)
|
||||||
|
vm.stack.append(vm.db.get_file(obj, prop))
|
||||||
|
|
||||||
lex.lex()
|
class SetFile(CodeOp):
|
||||||
print lex
|
def execute(self, vm):
|
||||||
|
val, prop, obj = vm.pop(3)
|
||||||
|
vm.db.set_file(obj, prop, val)
|
||||||
|
|
||||||
|
class SetVariable(CodeOp):
|
||||||
|
def execute(self, vm):
|
||||||
|
val, varname = vm.pop(2)
|
||||||
|
vm.setvar(varname, val)
|
||||||
|
|
||||||
|
class GetVariable(CodeOp):
|
||||||
|
def execute(self, vm):
|
||||||
|
varname, = vm.pop(1)
|
||||||
|
vm.push(vm.getvar(varname))
|
||||||
|
|
||||||
|
class CallBuiltin(CodeOp):
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def execute(self, vm):
|
||||||
|
funcname, = vm.pop(1)
|
||||||
|
builtin_map[funcname](vm)
|
||||||
|
|
||||||
|
class StartContext(CodeOp):
|
||||||
|
def execute(self, vm):
|
||||||
|
vm.push_context()
|
||||||
|
|
||||||
|
class EndContext(CodeOp):
|
||||||
|
def execute(self, vm):
|
||||||
|
vm.pop_context()
|
54
language_types.py
Executable file
54
language_types.py
Executable file
|
@ -0,0 +1,54 @@
|
||||||
|
|
||||||
|
|
||||||
|
class VMType(object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class VMInteger(VMType):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = int(value)
|
||||||
|
class VMFloat(VMType):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = float(value)
|
||||||
|
class VMTable(VMType):
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = dict(value)
|
||||||
|
|
||||||
|
class VMString(VMType):
|
||||||
|
def __init__(self, value):
|
||||||
|
if isinstance(value, unicode):
|
||||||
|
self.value = value
|
||||||
|
else:
|
||||||
|
self.value = unicode(str(value), 'ascii', 'ignore')
|
||||||
|
|
||||||
|
class VMObjRef(VMType):
|
||||||
|
def __init__(self, value):
|
||||||
|
if isinstance(value, ObjRef):
|
||||||
|
self.value = value
|
||||||
|
elif isinstance(value, (float, int)):
|
||||||
|
self.value = ObjRef(int(value))
|
||||||
|
else:
|
||||||
|
raise TypeError, "Attempted to create VMObjRef with invalid object reference: %r" % (value,)
|
||||||
|
|
||||||
|
|
||||||
|
def coerce(value):
|
||||||
|
if isinstance(value, int):
|
||||||
|
return VMInteger(value)
|
||||||
|
elif isinstance(value, (tuple, list)):
|
||||||
|
return VMList(list(value))
|
||||||
|
elif isinstance(value, unicode):
|
||||||
|
return VMString(value)
|
||||||
|
elif isinstance(value, dict):
|
||||||
|
return VMTable(value)
|
||||||
|
elif isinstance(value, ObjRef):
|
||||||
|
return VMObjRef(value)
|
||||||
|
elif isinstance(value, float):
|
||||||
|
return VMFloat(value)
|
||||||
|
elif value == None:
|
||||||
|
return VMInteger(0)
|
||||||
|
else:
|
||||||
|
raise TypeError("Unknown type %s cannot be coerced to VMType" % (type(value),))
|
||||||
|
|
||||||
|
|
||||||
|
def uncoerce(value):
|
||||||
|
assert isinstance(value, VMType)
|
||||||
|
return value.value
|
41
listener.py
41
listener.py
|
@ -2,6 +2,7 @@ import os, sys, time
|
||||||
import socket
|
import socket
|
||||||
import select
|
import select
|
||||||
import random
|
import random
|
||||||
|
from ringbuffer import RingBuffer
|
||||||
|
|
||||||
class Connection(object):
|
class Connection(object):
|
||||||
def __init__(self, id, conn, addr):
|
def __init__(self, id, conn, addr):
|
||||||
|
@ -11,6 +12,7 @@ class Connection(object):
|
||||||
self.input_encoding = 'raw'
|
self.input_encoding = 'raw'
|
||||||
self.output_encoding = 'ascii'
|
self.output_encoding = 'ascii'
|
||||||
self.linebuffer = True
|
self.linebuffer = True
|
||||||
|
self.output_buffer = RingBuffer(65536, True)
|
||||||
|
|
||||||
def fileno(self):
|
def fileno(self):
|
||||||
return self.conn.fileno()
|
return self.conn.fileno()
|
||||||
|
@ -34,6 +36,35 @@ class Connection(object):
|
||||||
return unicode(self.escape(data), 'ascii')
|
return unicode(self.escape(data), 'ascii')
|
||||||
else:
|
else:
|
||||||
return unicode(data, self.input_encoding, 'ignore')
|
return unicode(data, self.input_encoding, 'ignore')
|
||||||
|
|
||||||
|
def send(self, data):
|
||||||
|
assert isinstance(data, unicode)
|
||||||
|
try:
|
||||||
|
encoded = data.encode(self.output_encoding, 'replace')
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
try:
|
||||||
|
encoded = data.encode(self.output_encoding, 'ignore')
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
encoded = data.encode('ascii', 'ignore')
|
||||||
|
|
||||||
|
if len(encoded) > self.output_buffer.sizeleft():
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.output_buffer.write(encoded)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def output_waiting(self):
|
||||||
|
return self.output_buffer.bytes_waiting() > 0
|
||||||
|
|
||||||
|
def flush_buffer(self):
|
||||||
|
if not self.output_waiting():
|
||||||
|
return
|
||||||
|
|
||||||
|
data = self.output_buffer.read()
|
||||||
|
count = self.conn.send(data)
|
||||||
|
if count < len(data):
|
||||||
|
self.output_buffer.rewind(len(data) - count)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Listener(object):
|
class Listener(object):
|
||||||
|
@ -102,7 +133,10 @@ class Listener(object):
|
||||||
else:
|
else:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
def send(connid, data):
|
||||||
|
conn = self.connections[connid]
|
||||||
|
conn.send(data)
|
||||||
|
|
||||||
|
|
||||||
def scan_for_input(self, callback):
|
def scan_for_input(self, callback):
|
||||||
r, w, x = select.select(self.all_connections(), [], [], 0)
|
r, w, x = select.select(self.all_connections(), [], [], 0)
|
||||||
|
@ -112,6 +146,11 @@ class Listener(object):
|
||||||
self.delete_connection(conn)
|
self.delete_connection(conn)
|
||||||
else:
|
else:
|
||||||
callback(conn, input)
|
callback(conn, input)
|
||||||
|
|
||||||
|
def flush_output(self):
|
||||||
|
for conn in self.all_connections():
|
||||||
|
if conn.output_waiting():
|
||||||
|
conn.flush_output()
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
for x in self.connection_list:
|
for x in self.connection_list:
|
||||||
|
|
103
parse.py
Executable file
103
parse.py
Executable file
|
@ -0,0 +1,103 @@
|
||||||
|
from pyparsing import *
|
||||||
|
|
||||||
|
def enum_parse():
|
||||||
|
fd = open('test.enum', 'r')
|
||||||
|
|
||||||
|
# syntax we don't want to see in the final parse tree
|
||||||
|
_lcurl = Suppress('{')
|
||||||
|
_rcurl = Suppress('}')
|
||||||
|
_equal = Suppress('=')
|
||||||
|
_comma = Suppress(',')
|
||||||
|
_semi = Suppress(';')
|
||||||
|
_enum = Suppress('enum')
|
||||||
|
|
||||||
|
identifier = Word(alphas,alphanums+'_')
|
||||||
|
integer = Word(nums)
|
||||||
|
enumValue = Group(identifier('name') + Optional(_equal + integer('value')))
|
||||||
|
enumList = Group(enumValue + ZeroOrMore(_comma + enumValue))
|
||||||
|
enum = _enum + identifier('enum') + _lcurl + enumList('list') + _rcurl + Optional(_semi)
|
||||||
|
|
||||||
|
enumlist = ZeroOrMore(enum)
|
||||||
|
|
||||||
|
#print enumlist.parseString(fd.read(), parseAll=True)
|
||||||
|
# find instances of enums ignoring other syntax
|
||||||
|
for item in enumlist.parseString(fd.read(), parseAll=True):
|
||||||
|
id = 0
|
||||||
|
for entry in item:
|
||||||
|
if entry.value != '':
|
||||||
|
id = int(entry.value)
|
||||||
|
print '%s_%s = %d' % (item.enum.upper(),entry.name.upper(),id)
|
||||||
|
id += 1
|
||||||
|
|
||||||
|
fd.close()
|
||||||
|
|
||||||
|
def parse_fourfn():
|
||||||
|
global bnf
|
||||||
|
if not bnf:
|
||||||
|
point = Literal( "." )
|
||||||
|
e = CaselessLiteral( "E" )
|
||||||
|
fnumber = Combine( Word( "+-"+nums, nums ) +
|
||||||
|
Optional( point + Optional( Word( nums ) ) ) +
|
||||||
|
Optional( e + Word( "+-"+nums, nums ) ) )
|
||||||
|
ident = Word(alphas, alphas+nums+"_$")
|
||||||
|
|
||||||
|
plus = Literal( "+" )
|
||||||
|
minus = Literal( "-" )
|
||||||
|
mult = Literal( "*" )
|
||||||
|
div = Literal( "/" )
|
||||||
|
lpar = Literal( "(" ).suppress()
|
||||||
|
rpar = Literal( ")" ).suppress()
|
||||||
|
addop = plus | minus
|
||||||
|
multop = mult | div
|
||||||
|
expop = Literal( "^" )
|
||||||
|
pi = CaselessLiteral( "PI" )
|
||||||
|
|
||||||
|
expr = Forward()
|
||||||
|
atom = (Optional("-") + ( pi | e | fnumber | ident + lpar + expr + rpar ).setParseAction( pushFirst ) | ( lpar + expr.suppress() + rpar )).setParseAction(pushUMinus)
|
||||||
|
|
||||||
|
# by defining exponentiation as "atom [ ^ factor ]..." instead of "atom [ ^ atom ]...", we get right-to-left exponents, instead of left-to-righ
|
||||||
|
# that is, 2^3^2 = 2^(3^2), not (2^3)^2.
|
||||||
|
factor = Forward()
|
||||||
|
factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) )
|
||||||
|
|
||||||
|
term = factor + ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) )
|
||||||
|
expr << term + ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) )
|
||||||
|
bnf = expr
|
||||||
|
return bnf
|
||||||
|
|
||||||
|
|
||||||
|
def moo_parse():
|
||||||
|
fd = open('test.moo', 'r')
|
||||||
|
data = fd.read()
|
||||||
|
fd.close()
|
||||||
|
|
||||||
|
point = Literal( "." )
|
||||||
|
|
||||||
|
integer = Word( "+-"+nums, nums )
|
||||||
|
fnumber = Combine( integer +
|
||||||
|
Optional( point + Optional( Word( nums ) ) ) +
|
||||||
|
Optional( CaselessLiteral('e') + Word( "+-"+nums, nums ) ) )
|
||||||
|
ident = Word(alphas, alphas+nums+"_")
|
||||||
|
|
||||||
|
plus = Literal( "+" )
|
||||||
|
minus = Literal( "-" )
|
||||||
|
mult = Literal( "*" )
|
||||||
|
div = Literal( "/" )
|
||||||
|
lpar = Literal( "(" ).suppress()
|
||||||
|
rpar = Literal( ")" ).suppress()
|
||||||
|
addop = plus | minus
|
||||||
|
multop = mult | div
|
||||||
|
expop = Literal( "^" )
|
||||||
|
|
||||||
|
expr = Forward()
|
||||||
|
atom = (Optional("-") + ( fnumber | ident + lpar + expr + rpar ).setParseAction( pushFirst ) | ( lpar + expr.suppress() + rpar )).setParseAction(pushUMinus)
|
||||||
|
|
||||||
|
# by defining exponentiation as "atom [ ^ factor ]..." instead of "atom [ ^ atom ]...", we get right-to-left exponents, instead of left-to-righ
|
||||||
|
# that is, 2^3^2 = 2^(3^2), not (2^3)^2.
|
||||||
|
factor = Forward()
|
||||||
|
factor << atom + ZeroOrMore( ( expop + factor ).setParseAction( pushFirst ) )
|
||||||
|
|
||||||
|
term = factor + ZeroOrMore( ( multop + factor ).setParseAction( pushFirst ) )
|
||||||
|
expr << term + ZeroOrMore( ( addop + term ).setParseAction( pushFirst ) )
|
||||||
|
|
||||||
|
|
203
ringbuffer.py
Executable file
203
ringbuffer.py
Executable file
|
@ -0,0 +1,203 @@
|
||||||
|
try:
|
||||||
|
from cStringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from StringIO import StringIO
|
||||||
|
|
||||||
|
|
||||||
|
class FullBufferError(Exception):
|
||||||
|
|
||||||
|
class RingBuffer(object):
|
||||||
|
def __init__(self, size, overflow=True):
|
||||||
|
self.size = size
|
||||||
|
self.buffer = StringIO()
|
||||||
|
self.buffer_pos = 0
|
||||||
|
self.read_pos = 0
|
||||||
|
self.bytes_written = 0
|
||||||
|
self.first_read = True
|
||||||
|
self.allow_overflow = overflow
|
||||||
|
self.emptyclass = RingBuffer
|
||||||
|
self.fullclass = RingBufferFull
|
||||||
|
self.empty = True
|
||||||
|
|
||||||
|
def sizeleft(self):
|
||||||
|
return self.size - self.buffer_pos + self.read_pos
|
||||||
|
|
||||||
|
def bytes_waiting(self):
|
||||||
|
return self.size - self.sizeleft()
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
if data:
|
||||||
|
self.empty = False
|
||||||
|
ld = len(data)
|
||||||
|
if ld > self.sizeleft() and not self.allow_overflow:
|
||||||
|
raise FullBufferError("Data would overflow the buffer")
|
||||||
|
if self.buffer_pos + ld >= self.size:
|
||||||
|
self.__class__ = self.fullclass
|
||||||
|
split = self.size - self.buffer_pos
|
||||||
|
self.buffer.write(data[:split])
|
||||||
|
self.buffer.seek(0, 0)
|
||||||
|
self.buffer_pos = 0
|
||||||
|
self.bytes_written += split
|
||||||
|
self.write(data[split:])
|
||||||
|
else:
|
||||||
|
self.buffer.write(data)
|
||||||
|
self.buffer_pos += len(data)
|
||||||
|
self.bytes_written += len(data)
|
||||||
|
|
||||||
|
def read(self, bytes=0):
|
||||||
|
self.buffer.seek(self.read_pos, 0)
|
||||||
|
maxbytes = self.bytes_waiting()
|
||||||
|
if bytes > 0 and bytes < maxbytes:
|
||||||
|
maxbytes = bytes
|
||||||
|
|
||||||
|
rb = self.buffer.read(maxbytes)
|
||||||
|
self.read_pos = self.buffer.tell()
|
||||||
|
self.buffer.seek(self.buffer_pos, 0)
|
||||||
|
|
||||||
|
if self.read_pos == self.buffer_pos:
|
||||||
|
self.empty = True
|
||||||
|
return rb
|
||||||
|
|
||||||
|
def rewind(self, bytes):
|
||||||
|
if bytes > self.read_pos:
|
||||||
|
raise ValueError, "Buffer is not big enough to rewind that far"
|
||||||
|
|
||||||
|
self.read_pos -= bytes
|
||||||
|
if bytes > 0:
|
||||||
|
self.empty = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SplitRingBuffer(RingBuffer):
|
||||||
|
def __init__(self, size, split, overflow=True):
|
||||||
|
RingBuffer.__init__(self, size, overflow)
|
||||||
|
self.emptyclass = SplitRingBuffer
|
||||||
|
self.fullclass = SplitRingBufferFull
|
||||||
|
self.splitpos = split
|
||||||
|
self.read_pos = split
|
||||||
|
|
||||||
|
def read_head():
|
||||||
|
self.buffer.seek(0, 0)
|
||||||
|
rb = self.buffer.read()
|
||||||
|
self.buffer.seek(self.buffer_pos, 0)
|
||||||
|
return (True, rb)
|
||||||
|
|
||||||
|
|
||||||
|
class RingBufferFull(object):
|
||||||
|
def __init__(self, size):
|
||||||
|
raise NotImplementedError, "You should not create this class manually, use RingBuffer() instead"
|
||||||
|
|
||||||
|
def overflow_buffer():
|
||||||
|
self.buffer_pos = 0
|
||||||
|
self.seek_to_start()
|
||||||
|
|
||||||
|
def seek_to_start():
|
||||||
|
self.buffer.seek(0, 0)
|
||||||
|
|
||||||
|
def sizeleft(self):
|
||||||
|
if self.read_pos == None:
|
||||||
|
return self.size
|
||||||
|
elif self.read_pos == self.buffer_pos and self.empty:
|
||||||
|
return self.size
|
||||||
|
elif self.read_pos == self.buffer_pos:
|
||||||
|
return 0
|
||||||
|
elif self.read_pos < self.buffer_pos:
|
||||||
|
return self.size - self.buffer_pos + self.read_pos
|
||||||
|
else:
|
||||||
|
return self.read_pos - self.buffer_pos
|
||||||
|
|
||||||
|
def write(self, data):
|
||||||
|
if data:
|
||||||
|
self.empty = False
|
||||||
|
|
||||||
|
di = 0
|
||||||
|
ld = len(data)
|
||||||
|
|
||||||
|
# check for overflow before we start
|
||||||
|
if ld > self.sizeleft() and not self.allow_overflow:
|
||||||
|
# overflow will happen, raise an exception
|
||||||
|
raise FullBufferError("Data would overflow the buffer")
|
||||||
|
|
||||||
|
while (ld - di) + self.buffer_pos >= self.size:
|
||||||
|
# write data from the current buffer_pos all the way to the end of the ringbuffer
|
||||||
|
self.buffer.write(data[di:di + (self.size - self.buffer_pos)])
|
||||||
|
|
||||||
|
if self.read_pos != None and self.read_pos > self.buffer_pos:
|
||||||
|
# our read pos was between the buffer_pos and the end. since we just overwrote
|
||||||
|
# all that, it has been overwritten and we've lost our place, doh!
|
||||||
|
self.read_pos = None
|
||||||
|
self.overflow_buffer()
|
||||||
|
di += (self.size - self.buffer_pos)
|
||||||
|
|
||||||
|
# no more writing past the end of the buffer, now we can just do a simple write
|
||||||
|
self.buffer.write(data[di:])
|
||||||
|
if self.read_pos != None and self.buffer_pos <= self.read_pos and (self.buffer_pos + ld - di) > self.read_pos:
|
||||||
|
self.read_pos = None
|
||||||
|
self.buffer_pos += ld - di
|
||||||
|
self.bytes_written += ld
|
||||||
|
|
||||||
|
def read(self, bytes=0):
|
||||||
|
pos = self.read_pos
|
||||||
|
fullread = False
|
||||||
|
if pos == None:
|
||||||
|
pos = self.buffer_pos
|
||||||
|
|
||||||
|
maxlen = self.bytes_waiting()
|
||||||
|
self.buffer.seek(pos, 0)
|
||||||
|
if bytes > 0 and maxlen > bytes:
|
||||||
|
maxlen = bytes
|
||||||
|
|
||||||
|
if maxlen == 0:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
split = self.size - pos
|
||||||
|
if split >= maxlen:
|
||||||
|
self.buffer.seek(pos, 0)
|
||||||
|
rb = self.buffer.read(maxlen)
|
||||||
|
self.read_pos = self.buffer.tell()
|
||||||
|
self.buffer.seek(self.buffer_pos, 0)
|
||||||
|
else:
|
||||||
|
self.buffer.seek(pos, 0)
|
||||||
|
rb = self.buffer.read(split)
|
||||||
|
self.seek_to_start()
|
||||||
|
rb += self.buffer.read(maxlen - split)
|
||||||
|
self.read_pos = self.buffer.tell()
|
||||||
|
self.buffer.seek(self.buffer_pos, 0)
|
||||||
|
|
||||||
|
if self.read_pos == self.buffer_pos and bytes > 0:
|
||||||
|
"we've read everything out of the buffer"
|
||||||
|
self.empty = True
|
||||||
|
|
||||||
|
return rb
|
||||||
|
|
||||||
|
def rewind(self, bytes):
|
||||||
|
if bytes > self.sizeleft():
|
||||||
|
raise ValueError, "Buffer is not big enough to rewind that far"
|
||||||
|
|
||||||
|
self.read_pos -= bytes
|
||||||
|
if self.read_pos < 0:
|
||||||
|
self.read_pos += self.size
|
||||||
|
|
||||||
|
if bytes > 0:
|
||||||
|
self.empty = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SplitRingBufferFull(RingBufferFull):
|
||||||
|
def read(self, bytes=0):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def overflow_buffer():
|
||||||
|
self.buffer_pos = self.split_pos
|
||||||
|
|
||||||
|
def seek_to_start():
|
||||||
|
self.buffer.seek(self.split_pos, 0)
|
||||||
|
|
||||||
|
def read_head():
|
||||||
|
self.buffer.seek(0, 0)
|
||||||
|
rb = self.buffer.read(self.split_pos)
|
||||||
|
self.buffer.seek(self.buffer_pos, 0)
|
||||||
|
return (False, rb)
|
||||||
|
|
||||||
|
|
33
server.py
33
server.py
|
@ -1,9 +1,18 @@
|
||||||
import os, sys, time
|
import os, sys, time
|
||||||
from listener import Listener
|
from listener import Listener
|
||||||
|
from language import VirtualMachine
|
||||||
|
from database_fake import Fake_Database as Database
|
||||||
|
|
||||||
class Server(object):
|
class Server(object):
|
||||||
def __init__(self, dbname):
|
def __init__(self, dbname):
|
||||||
self.dbname = dbname
|
self.dbname = dbname
|
||||||
|
self.db = Database(dbname)
|
||||||
|
self.vm = VirtualMachine(self.db)
|
||||||
|
self.max_sleep = 0.1
|
||||||
|
self.min_sleep = 0.005
|
||||||
|
self.vm_sleep_fudge = 0.85
|
||||||
|
self.server_started = None
|
||||||
|
self.loop_started = None
|
||||||
self.listeners = []
|
self.listeners = []
|
||||||
|
|
||||||
def listen(self, addr, port):
|
def listen(self, addr, port):
|
||||||
|
@ -12,11 +21,16 @@ class Server(object):
|
||||||
self.listeners.append(l)
|
self.listeners.append(l)
|
||||||
|
|
||||||
def mainloop(self):
|
def mainloop(self):
|
||||||
|
self.server_started = time.time()
|
||||||
while True:
|
while True:
|
||||||
|
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)
|
||||||
time.sleep(2)
|
self.vm.run()
|
||||||
|
for l in self.listeners:
|
||||||
|
l.flush_output()
|
||||||
|
self.idlewait()
|
||||||
|
|
||||||
|
|
||||||
def read_input(self, conn, data):
|
def read_input(self, conn, data):
|
||||||
|
@ -25,6 +39,23 @@ 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)
|
||||||
|
|
||||||
|
def idlewait(self):
|
||||||
|
if self.vm.sleepytime == None:
|
||||||
|
"virtual machine is still busy anyway, no sleeping on the job!"
|
||||||
|
return
|
||||||
|
|
||||||
|
"also check how much time we have spent already. if it's already been our polling"
|
||||||
|
"time (or longer!), there's no sense waiting even more!"
|
||||||
|
time_already_spent = time.time() - self.loop_started
|
||||||
|
|
||||||
|
sleepytime = min(self.max_sleep - time_already_spent, self.vm.sleepytime * self.vm_sleep_fudge)
|
||||||
|
if sleepytime < self.min_sleep or sleepytime < 0.0:
|
||||||
|
return
|
||||||
|
|
||||||
|
time.sleep(sleepytime)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
srv = Server("Test")
|
srv = Server("Test")
|
||||||
|
|
Loading…
Add table
Reference in a new issue