Improve parser

This commit is contained in:
Bartłomiej Pluta
2019-06-30 19:58:37 +02:00
parent 607e9f9214
commit 65353a80f2
5 changed files with 44 additions and 53 deletions

View File

@@ -93,13 +93,13 @@ def transposeTo(args, env):
result.append([note.transpose(semitones) for note in notes if isinstance(note, Note)])
else:
result.append([])
return returnElementOrList(result)
return returnElementOrList(result)
else:
pass # not valid signature
def transpose(args, env):
if len(args) > 1 and isinstance(args[0], int):
def transpose(args, env):
if len(args) > 1 and isinstance(args[0], int) and all(isinstance(arg, list) for i, arg in enumerate(args) if i != 0):
value = args[0]
transposed = []
for i, arg in enumerate(args):
@@ -108,7 +108,11 @@ def transpose(args, env):
if not isinstance(arg, list):
return # is not list
transposed.append([note.transpose(value) for note in arg if isinstance(note, Note)])
return transposed
return returnElementOrList(transposed)
if len(args) > 1 and all(isinstance(arg, Note) for i, arg in enumerate(args) if i != 0):
value = args[0]
transposed = [note.transpose(value) for i, note in enumerate(args) if i != 0]
return returnElementOrList(transposed)
else:
return # not valid signature
@@ -124,42 +128,6 @@ def exit(args, env):
else:
pass # not valid signature
def upper(args, env):
value = []
for arg in args:
if isinstance(arg, Note):
value.append(arg.getUpperNeighbour())
elif isinstance(arg, list):
value.append(upperList(arg))
else:
pass # invalid argument
return returnElementOrList(value)
def upperList(list):
if all(isinstance(x, Note) for x in list):
value = [note.getUpperNeighbour() for note in list]
return returnElementOrList(value)
else:
pass #not valid signature
def lower(args, env):
value = []
for arg in args:
if isinstance(arg, Note):
value.append(arg.getLowerNeighbour())
elif isinstance(arg, list):
value.append(lowerList(arg))
else:
pass # invalid argument
return returnElementOrList(value)
def lowerList(list):
if all(isinstance(x, Note) for x in list):
value = [note.getLowerNeighbour() for note in list]
return returnElementOrList(value)
else:
pass #not valid signature
def sleep(args, env):
if len(args) == 1 and isinstance(args[0], int):
time.sleep(args[0])
@@ -189,8 +157,6 @@ def createEnvironment():
'interval': interval,
'transpose': transpose,
'transposeTo': transposeTo,
'upper': upper,
'lower': lower,
'sleep': sleep,
'random': rand,
'exit': exit

View File

@@ -104,8 +104,12 @@ def evaluateAsterisk(asterisk, environment):
del environment.scopes[-1]["_"]
del environment.scopes[-1]["__"]
def evaluateColon(colon, environment):
return Note.range(colon.a.value, colon.b.value)
def evaluateColon(colon, environment):
if isinstance(colon.a, NoteLiteralNode) and isinstance(colon.b, NoteLiteralNode):
return Note.range(colon.a.value, colon.b.value)
elif isinstance(colon.a, IntegerLiteralNode) and isinstance(colon.b, IntegerLiteralNode):
return list(range(colon.a.value, colon.b.value+1))
raise RuntimeException("Invalid colon arguments")
def evaluate(input, environment):
if isinstance(input, Program):

View File

@@ -83,13 +83,6 @@ class Note:
def __repr__(self):
return self.__str__()
def getLowerNeighbour(self):
return Note._fromIntRepr(max((self._intRepr()-1), 0))
def getUpperNeighbour(self):
maxIntRepr = Note(NotePitch.H, 9)._intRepr() # max value for one-digit octave number
return Note._fromIntRepr(min((self._intRepr()+1), maxIntRepr))
@staticmethod
def _fromIntRepr(intRepr, duration=4):
note = NotePitch(intRepr % len(NotePitch))

View File

@@ -83,13 +83,24 @@ def parseNoteOrColon(input, parent):
note = parseNote(input, parent)
if len(input) > 1 and input[0].type == TokenType.COLON:
input.pop(0)
b = parseExpression(input, parent) #TODO: only expressions!
b = parseNote(input, parent) #TODO: only expressions!
if b is None:
raise ParseError(f"Line {input[0].pos[0]+1}, col {input[0].pos[1]+1}: Invalid colon argument '{input[0].value}'")
return ColonNode(note, b)
return note
def parseIntegerOrColon(input, parent):
integer = parseInteger(input, parent)
if len(input) > 1 and input[0].type == TokenType.COLON:
input.pop(0)
b = parseInteger(input, parent) #TODO: only expressions!
if b is None:
raise ParseError(f"Line {input[0].pos[0]+1}, col {input[0].pos[1]+1}: Invalid colon argument '{input[0].value}'")
return ColonNode(integer, b)
return integer
def parseFunctionCallOrAssignOrIdentifier(input, parent):
identifier = IdentifierNode(input.pop(0).value)
# Function call
@@ -111,10 +122,19 @@ def parsePercent(input, parent):
return PercentNode(value)
def parseMinus(input, parent):
input.pop(0)
value = parseInteger(input, parent)
return IntegerLiteralNode(-value.value)
def parseExpression(input, parent):
type = input[0].type
if type == TokenType.MINUS:
return parseMinus(input, parent)
if type == TokenType.INTEGER:
return parseInteger(input, parent)
return parseIntegerOrColon(input, parent)
if type == TokenType.STRING:
return parseString(input, parent)
if type == TokenType.NOTE:
@@ -125,6 +145,7 @@ def parseExpression(input, parent):
return parsePercent(input, parent)
if type == TokenType.OPEN_PAREN:
return parseList(input, parent)
raise ParseError(f"Line {input[0].pos[0]+1}, col {input[0].pos[1]+1}: Unexpected character '{input[0].value}'")
def parseArrayElement(input, parent):
type = input[0].type

View File

@@ -18,6 +18,7 @@ class TokenType(Enum):
NOTE = 12
COMMENT = 13
PERCENT = 14
MINUS = 15
class TokenizerError(Exception):
pass
@@ -148,6 +149,11 @@ def tokenizePercent(input, current, line):
return (1, Token(TokenType.PERCENT, input[current], (line, current)))
return (0, None)
def tokenizeMinus(input, current, line):
if input[current] == '-':
return (1, Token(TokenType.MINUS, input[current], (line, current)))
return (0, None)
tokenizers = (
tokenizeOpenParen,
tokenizeCloseParen,
@@ -162,6 +168,7 @@ tokenizers = (
tokenizeAssign,
tokenizeColon,
tokenizePercent,
tokenizeMinus,
tokenizeComment,
tokenizeWhitespaces
)