-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2ac1d6a
commit d906750
Showing
4 changed files
with
211 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
from parsimonious.grammar import Grammar | ||
from utils import Trace | ||
from instructions import get_instruction | ||
from InstructionSequence import InstructionSequence | ||
from EnvironmentChangeInstruction import EnvironmentChangeInstruction | ||
|
||
class Wave(object): | ||
def __init__(self): | ||
pass | ||
|
||
def parse(self, source, root=None): | ||
if root is None: | ||
root = 'wave' | ||
|
||
grammar = '\n'.join(v.__doc__ for k, v in vars(self.__class__).items() | ||
if '__' not in k and hasattr(v, '__doc__') and v.__doc__) | ||
|
||
return Grammar(grammar)[root].parse(source) | ||
|
||
def eval(self, source, root=None): | ||
node = self.parse(source, root) if isinstance(source, str) else source | ||
method = getattr(self, node.expr_name, lambda node, children: children) | ||
return method(node, [self.eval(n) for n in node]) | ||
|
||
def wave(self, node, children): | ||
'wave = sequence' | ||
return children | ||
|
||
def symbol(self, node, children): | ||
'symbol = ~"[a-zA-Z]"' | ||
return node.text | ||
|
||
def identifier(self, node, children): | ||
'identifier = ~"[a-zA-Z_]+"' | ||
return node.text | ||
|
||
def string(self, node, children): | ||
'string = ( ~"[a-zA-Z0-9]+" ) / ( "\\"" ~"[^\\"]*" "\\"" )' | ||
text = node.text if node.text[0] != '"' else node.text[1:-1] | ||
return text | ||
|
||
def sequence(self, node, children): | ||
'sequence = ( natural? "{" instruction + "}" ) / instruction+' | ||
instr = children[0] | ||
if len(instr) < 3 or node.children[0].children[1].text != '{': # just instruction+ | ||
return InstructionSequence(instr, 1) | ||
else: | ||
count, _, seq, _ = instr | ||
count = 1 if not count else count[0] | ||
return InstructionSequence(seq, count) | ||
|
||
def parameter(self, node, children): | ||
'parameter = string / ( sequence )' | ||
return children[0] | ||
|
||
def parameters(self, node, children): | ||
'parameters = parameter ( "," parameter )*' | ||
par = [children[0]] + ([x[1] for x in children[1]]) | ||
return par | ||
|
||
def ec_instruction(self, node, children): | ||
'ec_instruction = "[" ( identifier "=" )? string "]"' | ||
identifier = None if not children[1] else children[1][0][0] | ||
return EnvironmentChangeInstruction(identifier, children[2]) | ||
|
||
def rndr_instruction(self, node, children): | ||
'rndr_instruction = float? symbol ( "(" parameters ")" )?' | ||
|
||
width, sym, par = children | ||
|
||
width = None if not width else width[0] | ||
par = None if not par else par[0][1] | ||
|
||
return get_instruction(sym, width, par) | ||
|
||
def instruction(self, node, children): | ||
'instruction = rndr_instruction / ec_instruction' | ||
return children[0] | ||
|
||
def natural(self, node, children): | ||
'natural = ~"[0-9]+"' | ||
return int(node.text) | ||
|
||
def float(self, node, children): | ||
'float = ( natural ( "." natural )? ) / ( "." natural )' | ||
return float(node.text) | ||
|
||
def _(self, node, children): | ||
'_ = ~"\s*"' | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from RenderInstruction import RenderInstruction | ||
from BackgroundInstruction import BackgroundInstruction | ||
from utils import Trace | ||
|
||
def get_instruction(symbol, width = None, parameters = None): | ||
if width is None: | ||
width = 1 | ||
|
||
if symbol == 'B': | ||
return BackgroundInstruction(parameters[0]) | ||
else: | ||
param = None if not parameters else parameters[0] | ||
return RenderInstruction(symbol, width, param) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import unittest | ||
from Parser import Wave | ||
from RenderInstruction import RenderInstruction | ||
from BackgroundInstruction import BackgroundInstruction | ||
from InstructionSequence import InstructionSequence | ||
from EnvironmentChangeInstruction import EnvironmentChangeInstruction | ||
|
||
class tests(unittest.TestCase): | ||
def test_minimal(self): | ||
self.assertEqual( | ||
Wave().eval('L'), | ||
InstructionSequence([RenderInstruction('L', 1)], 1)) | ||
|
||
def test_width(self): | ||
self.assertEqual( | ||
Wave().eval('3L'), | ||
InstructionSequence([RenderInstruction('L', 3)], 1)) | ||
|
||
def test_param(self): | ||
self.assertEqual( | ||
Wave().eval('D(0xAA)'), | ||
InstructionSequence([RenderInstruction('D', 1, '0xAA')], 1)) | ||
|
||
def test_multiple_params(self): | ||
self.assertEqual( | ||
Wave().eval('3L(x,x,x)'), | ||
InstructionSequence([RenderInstruction('L', 3, 'x')], 1)) | ||
|
||
def test_multiple_instr(self): | ||
self.assertEqual( | ||
Wave().eval('LLL'), | ||
InstructionSequence(3*[RenderInstruction('L', 1)], 1)) | ||
|
||
def test_explicit_sequence(self): | ||
self.assertEqual( | ||
Wave().eval('{LLL}'), | ||
InstructionSequence(3*[RenderInstruction('L', 1)], 1)) | ||
|
||
def test_mutiple_sequence(self): | ||
self.assertEqual( | ||
Wave().eval('4{LLL}'), | ||
InstructionSequence(3*[RenderInstruction('L', 1)], 4)) | ||
|
||
def test_sequence_param(self): | ||
self.assertEqual( | ||
Wave().eval('B({LL})'), | ||
InstructionSequence([BackgroundInstruction(InstructionSequence(2*[RenderInstruction('L', 1)]))])) | ||
|
||
def test_ec_instruction(self): | ||
self.assertEqual( | ||
Wave().eval('[foo=bar]'), | ||
InstructionSequence([EnvironmentChangeInstruction('foo', 'bar')])) | ||
|
||
def test_ec_no_indentifier(self): | ||
self.assertEqual( | ||
Wave().eval('[bar]'), | ||
InstructionSequence([EnvironmentChangeInstruction('color', 'bar')])) | ||
|
||
def test_complete(self): | ||
self.assertEqual( | ||
Wave().eval('LH4LB({[grey]H0L})LL(0)'), | ||
InstructionSequence([ | ||
RenderInstruction('L', 1), | ||
RenderInstruction('H', 1), | ||
RenderInstruction('L', 4), | ||
BackgroundInstruction( | ||
InstructionSequence([ | ||
EnvironmentChangeInstruction('color', 'grey'), | ||
RenderInstruction('H', 1), | ||
RenderInstruction('L', 0)])), | ||
RenderInstruction('L', 1), | ||
RenderInstruction('L', 1, '0') ])) | ||
|
||
def test_identifier(self): | ||
self.assertEqual( | ||
Wave().eval('_asdf', 'identifier'), | ||
'_asdf') | ||
|
||
def test_natural(self): | ||
self.assertEqual( | ||
Wave().eval('123', 'natural'), | ||
123) | ||
|
||
def test_float(self): | ||
self.assertEqual( | ||
Wave().eval('123', 'float'), | ||
123) | ||
|
||
self.assertEqual( | ||
Wave().eval('1.2', 'float'), | ||
1.2) | ||
|
||
self.assertEqual( | ||
Wave().eval('.4', 'float'), | ||
0.4) | ||
|
||
def test_string(self): | ||
self.assertEqual( | ||
Wave().eval('asdf', 'string'), | ||
'asdf') | ||
|
||
self.assertEqual( | ||
Wave().eval('"asdf,xy"', 'string'), | ||
'asdf,xy') |