Skip to content

Commit

Permalink
Fix #58 (a tick in variables will cause the SharpEngine to crash) AND
Browse files Browse the repository at this point in the history
Fix 56 (symbols for variables aren't saved properly)
  • Loading branch information
vincent-lg committed Nov 22, 2016
1 parent de087df commit c8dee3b
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 40 deletions.
51 changes: 35 additions & 16 deletions src/client.py
Expand Up @@ -84,22 +84,7 @@ def run(self):
break

if msg:
for line in msg.splitlines():
for trigger in self.world.triggers:
try:
trigger.feed(line)
except Exception:
log = logger("client")
log.exception("The trigger {} failed".format(
repr(trigger.readction)))


try:
self.handle_message(msg)
except Exception:
log = logger("client")
log.exception(
"An error occurred when handling a message")
self.handle_lines(msg)

# Consider the thread as stopped
self.running = False
Expand All @@ -108,6 +93,40 @@ def run(self):
if self.window:
self.window.handle_disconnection()

def handle_lines(self, msg):
"""Handle multiple lines of text."""
lines = []
triggers = []
for line in msg.splitlines():
display = True
for trigger in self.world.triggers:
try:
test = trigger.test(line)
except Exception:
log = logger("client")
log.exception("The trigger {} failed".format(
repr(trigger.readction)))
else:
if test:
triggers.append((trigger, line))
if trigger.mute:
display = False

if display:
lines.append(line)

# Handle the remaining text
try:
self.handle_message("\r\n".join(lines))
except Exception:
log = logger("client")
log.exception(
"An error occurred when handling a message")

# Execute the triggers
for trigger, line in triggers:
trigger.test(line, execute=True)

def handle_message(self, msg, force_TTS=False, screen=True,
speech=True, braille=True):
"""When the client receives a message.
Expand Down
21 changes: 18 additions & 3 deletions src/scripting/trigger.py
Expand Up @@ -48,6 +48,7 @@ def __init__(self, sharp, reaction, action):
self.reaction = reaction
self.re_reaction = self.find_regex(reaction)
self.action = action
self.mute = False
self.logger = logger("sharp")

# Set the trigger's level
Expand All @@ -60,13 +61,15 @@ def __repr__(self):
@property
def sharp_script(self):
"""Return the SharpScript code to create this trigger."""
mute = "+mute" if self.mute else ""
return self.sharp_engine.format((("#trigger", self.reaction,
self.action), ))
self.action, mute), ))

@property
def copied(self):
"""Return a copied version of the trigger."""
copy = Trigger(self.sharp_engine, self.reaction, self.action)
copy.mute = self.mute
copy.level = self.level
return copy

Expand Down Expand Up @@ -94,12 +97,21 @@ def find_regex(self, reaction):

return re.compile(reaction, re.IGNORECASE)

def feed(self, line):
"""Should the trigger be triggered by the text?"""
def test(self, line, execute=False):
"""Should the trigger be triggered by the text?
This function return either True or False. If the 'execute'
argument is set to True, and the trigger should be fired, then
call the 'execute' method.
"""
match = self.re_reaction.search(line)
if match:
world = self.world
world = world and world.name or "unknown"
if not execute:
return True

self.logger.debug("Trigger {}.{} fired.".format(
world, self.reaction))

Expand All @@ -121,6 +133,9 @@ def feed(self, line):

# Execute the trigger
self.execute()
return True

return False

def execute(self):
"""Execute the trigger."""
Expand Down
25 changes: 15 additions & 10 deletions src/sharp/engine.py
Expand Up @@ -68,10 +68,10 @@ def __init__(self, engine, client, world):
self.functions[name] = function
self.globals[name] = function.run

def execute(self, code, debug=False):
def execute(self, code, debug=False, variables=False):
"""Execute the SharpScript code given as an argument."""
if isinstance(code, basestring):
instructions = self.feed(code)
instructions = self.feed(code, variables=variables)
else:
instructions = [code]

Expand All @@ -83,7 +83,7 @@ def execute(self, code, debug=False):
for instruction in instructions:
exec(instruction, globals, locals)

def feed(self, content):
def feed(self, content, variables=False):
"""Feed the SharpScript engine with a string content.
The content is probably a file with several statements in
Expand All @@ -105,12 +105,12 @@ def feed(self, content):
# The remaining must be SharpScript, splits into statements
statements = self.split_statements(content)
for statement in statements:
pycode = self.convert_to_python(statement)
pycode = self.convert_to_python(statement, variables=variables)
codes.append(pycode)

return codes

def convert_to_python(self, statement):
def convert_to_python(self, statement, variables=False):
"""Convert the statement to Python and return the str code.
The statement given in argument should be a tuple: The first
Expand All @@ -128,16 +128,21 @@ def convert_to_python(self, statement):
argument = repr(dedent(argument)).replace("\\n", "\n")
argument = "compile(" + argument + ", 'SharpScript', 'exec')"
elif argument.startswith("{"):
argument = repr(argument[1:-1])
argument = argument[1:-1]
argument = self.replace_semicolons(argument)
argument = self.replace_variables(argument)
if variables:
argument = self.replace_variables(argument)

argument = repr(argument).replace("\\n", "\n")
elif argument[0] in "-+":
kwargs[argument[1:]] = True if argument[0] == "+" else False
continue
else:
argument = repr(argument)
argument = self.replace_semicolons(argument)
argument = self.replace_variables(argument)
if variables:
argument = self.replace_variables(argument)

argument = repr(argument).replace("\\n", "\n")

arguments.append(argument)

Expand Down Expand Up @@ -298,7 +303,7 @@ def spot(match):
line = RE_VAR.sub(spot, line)

# Escape the double $ sign
line = line.replace("\\\\$", "$")
line = line.replace("\\$", "$")

return line

Expand Down
3 changes: 2 additions & 1 deletion src/sharp/functions/trigger.py
Expand Up @@ -35,8 +35,9 @@ class Trigger(Function):

"""Function SharpScript 'trigger'."""

def run(self, reaction, action):
def run(self, reaction, action, mute=False):
"""Say the text."""
trigger = ObjTrigger(self.sharp_engine, reaction, action)
trigger.mute = mute
if self.world:
self.world.triggers.append(trigger)
26 changes: 17 additions & 9 deletions src/tests/sharp/test_syntax.py
Expand Up @@ -121,20 +121,24 @@ def test_simple_variables(self):
self.engine.locals["art"] = "magnificient"

# Try to display the variables
statements = self.engine.feed("#send {Display a: $a.}")
statements = self.engine.feed("#send {Display a: $a.}",
variables=True)
self.assertEqual(statements, ["send('Display a: 30.')"])
statements = self.engine.feed("#send {Display b: $b.}")
statements = self.engine.feed("#send {Display b: $b.}",
variables=True)
self.assertEqual(statements, ["send('Display b: -80.')"])
statements = self.engine.feed("#send {Display art: $art.}")
statements = self.engine.feed("#send {Display art: $art.}",
variables=True)
self.assertEqual(statements, ["send('Display art: magnificient.')"])
statements = self.engine.feed("#send {a=$a, b=$b, art=$art.}")
statements = self.engine.feed("#send {a=$a, b=$b, art=$art.}",
variables=True)
self.assertEqual(statements, ["send('a=30, b=-80, art=magnificient.')"])

def test_variables_args(self):
"""Test variables in arguments."""
args = {"1": 800}
self.engine.locals["args"] = args
statements = self.engine.feed("#send $1")
statements = self.engine.feed("#send $1", variables=True)
self.assertEqual(statements, ["send('800')"])

def test_escape_variables(self):
Expand All @@ -144,13 +148,17 @@ def test_escape_variables(self):
self.engine.locals["s"] = "calc"

# Try to display the variables
statements = self.engine.feed("#send {sum=$sum}")
statements = self.engine.feed("#send {sum=$sum}",
variables=True)
self.assertEqual(statements, ["send('sum=500')"])
statements = self.engine.feed("#send {You have \\$$sum.}")
statements = self.engine.feed("#send {You have \\$$sum.}",
variables=True)
self.assertEqual(statements, ["send('You have $500.')"])
statements = self.engine.feed("#send {You have ${HP}HP left.}")
statements = self.engine.feed("#send {You have ${HP}HP left.}",
variables=True)
self.assertEqual(statements, ["send('You have 20HP left.')"])
statements = self.engine.feed("#send {You have ${H}HP left.}")
statements = self.engine.feed("#send {You have ${H}HP left.}",
variables=True)
self.assertEqual(statements, ["send('You have HP left.')"])

def test_escape_sharp(self):
Expand Down
2 changes: 1 addition & 1 deletion src/world.py
Expand Up @@ -96,7 +96,7 @@ def load(self):
file.close()

# Execute the script
self.sharp_engine.execute(content)
self.sharp_engine.execute(content, variables=False)

# Put the engine level back
self.engine.level = level
Expand Down

0 comments on commit c8dee3b

Please sign in to comment.