Improve parser
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
7
Note.py
7
Note.py
@@ -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))
|
||||
|
||||
25
Parser.py
25
Parser.py
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user