Add new functionalities

This commit is contained in:
Bartłomiej Pluta
2019-06-29 12:54:47 +02:00
parent 9a3936a202
commit db3419af01
3 changed files with 72 additions and 36 deletions

View File

@@ -37,7 +37,7 @@ def evaluateString(string, environment):
value = string.value value = string.value
for scope in reversed(environment.scopes): for scope in reversed(environment.scopes):
for k, v in scope.items(): for k, v in scope.items():
value = value.replace('{' + k + '}', str(v)) value = value.replace('{' + k + '}', objectString(v)) #TODO: poprawic
return value return value
def evaluateNote(note, environment): def evaluateNote(note, environment):
@@ -46,7 +46,6 @@ def evaluateNote(note, environment):
def evaluateFunctionCall(functionCall, environment): def evaluateFunctionCall(functionCall, environment):
function = functionCall.identifier.identifier function = functionCall.identifier.identifier
arguments = evaluateList(functionCall.arguments, environment) arguments = evaluateList(functionCall.arguments, environment)
#TODO: example
for name, definition in environment.functions.items(): for name, definition in environment.functions.items():
if name == function: if name == function:
return definition(arguments) return definition(arguments)
@@ -72,17 +71,35 @@ def evaluateAssignment(assignment, environment):
def evaluateAsterisk(asterisk, environment): def evaluateAsterisk(asterisk, environment):
count = evaluate(asterisk.iterator, environment) count = evaluate(asterisk.iterator, environment)
if isinstance(count, int):
for i in range(count): for i in range(count):
if isinstance(asterisk.iterator, IdentifierNode): if isinstance(asterisk.iterator, IdentifierNode):
environment.scopes[-1][f"_{asterisk.iterator.identifier}"] = i+1 environment.scopes[-1][f"_{asterisk.iterator.identifier}"] = i+1
else:
environment.scopes[-1]["_"] = i+1
evaluate(asterisk.statement, environment) evaluate(asterisk.statement, environment)
if isinstance(asterisk.iterator, IdentifierNode):
del environment.scopes[-1][f"_{asterisk.iterator.identifier}"]
else:
environment.scopes[-1]["_"] = i+1
elif isinstance(count, list):
for i, v in enumerate(count):
if isinstance(asterisk.iterator, IdentifierNode):
environment.scopes[-1][f"_{asterisk.iterator.identifier}"] = i+1
environment.scopes[-1][f"{asterisk.iterator.identifier}_"] = v
else:
environment.scopes[-1]["_"] = i+1
environment.scopes[-1]["__"] = v
evaluate(asterisk.statement, environment)
if isinstance(asterisk.iterator, IdentifierNode):
del environment.scopes[-1][f"_{asterisk.iterator.identifier}"]
del environment.scopes[-1][f"{asterisk.iterator.identifier}_"]
else:
del environment.scopes[-1]["_"]
del environment.scopes[-1]["__"]
def evaluateColon(colon, environment): def evaluateColon(colon, environment):
if isinstance(colon.a, IntegerLiteralNode) and isinstance(colon.b, IntegerLiteralNode): return Note.range(colon.a.value, colon.b.value)
return list(range(evaluateInteger(colon.a, environment), evaluateInteger(colon.b, environment)+1))
if isinstance(colon.a, NoteLiteralNode) and isinstance(colon.b, NoteLiteralNode):
return NotePitch.range(colon.a.value.note, colon.b.value.note)
raise RuntimeException("Range can be created using only note or integer literals")
def evaluate(input, environment): def evaluate(input, environment):
if isinstance(input, Program): if isinstance(input, Program):
@@ -112,13 +129,32 @@ def evaluate(input, environment):
if isinstance(input, IdentifierNode): if isinstance(input, IdentifierNode):
return evaluateIdentifier(input, environment) return evaluateIdentifier(input, environment)
def rand(args):
if len(args) == 1 and isinstance(args[0], list):
return args[0][int(random.uniform(0, len(args[0])))]
def objectString(obj):
if isinstance(obj, str):
return obj
if isinstance(obj, int):
return str(obj)
if isinstance(obj, Note):
return obj.note.name
if isinstance(obj, list):
return "(" + ", ".join([objectString(v) for v in obj]) + ")"
raise RuntimeException(f"Don't know how to interpret {str(obj)}")
def prt(args):
print("".join([objectString(arg) for arg in args]))
if __name__ == "__main__": if __name__ == "__main__":
functions = { functions = {
'print': lambda args: print("".join([str(arg) for arg in args])), 'print': prt,
'midi': lambda args: print(":".join([str(type(arg)) for arg in args])), 'midi': lambda args: print(":".join([str(type(arg)) for arg in args])),
'random': lambda args: args[0][int(random.uniform(0, len(args[0])))][1] 'type': lambda args: print(type(args[0])),
'random': rand
} }
with open(sys.argv[1], 'r') as source: with open(sys.argv[1], 'r') as source:
@@ -127,7 +163,6 @@ if __name__ == "__main__":
tokens = [token for token in tokenize(lines) if token.type != TokenType.COMMENT] tokens = [token for token in tokenize(lines) if token.type != TokenType.COMMENT]
ast = parse(tokens) ast = parse(tokens)
environment = Environment([{}], functions) environment = Environment([{}], functions)
evaluate(ast, environment) evaluate(ast, environment)

View File

@@ -38,7 +38,7 @@ class NotePitch(Enum):
aValue = a.value aValue = a.value
bValue = b.value bValue = b.value
return [note for note in NotePitch.__members__.items() if note[1].value >= aValue and note[1].value <= bValue] return [note[1] for note in NotePitch.__members__.items() if note[1].value >= aValue and note[1].value <= bValue]
class Note: class Note:
def __init__(self, note, octave, duration): def __init__(self, note, octave, duration):
@@ -49,5 +49,6 @@ class Note:
self.octave = octave self.octave = octave
self.duration = duration self.duration = duration
def __str__(self): @staticmethod
return self.note.name def range(a, b):
return [Note(note, 1, 1) for note in NotePitch.range(a.note, b.note)]

View File

@@ -79,16 +79,18 @@ def parseAsterisk(input, parent):
return AsteriskStatementNode(iterator, value) return AsteriskStatementNode(iterator, value)
def parseColon(input, parent): def parseNoteOrColon(input, parent):
note = parseNote(input, parent)
if len(input) > 1 and input[0].type == TokenType.COLON:
input.pop(0) input.pop(0)
a = parent.pop(-1)
b = parseExpression(input, parent) #TODO: only expressions! b = parseExpression(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 ColonNode(a, b) return note
def parseFunctionCallOrAssignOrIdentifier(input, parent): def parseFunctionCallOrAssignOrIdentifier(input, parent):
#import pdb; pdb.set_trace()
identifier = IdentifierNode(input.pop(0).value) identifier = IdentifierNode(input.pop(0).value)
# Function call # Function call
if len(input) > 0 and input[0].type == TokenType.OPEN_PAREN: if len(input) > 0 and input[0].type == TokenType.OPEN_PAREN:
@@ -116,15 +118,13 @@ def parseExpression(input, parent):
if type == TokenType.STRING: if type == TokenType.STRING:
return parseString(input, parent) return parseString(input, parent)
if type == TokenType.NOTE: if type == TokenType.NOTE:
return parseNote(input, parent) return parseNoteOrColon(input, parent)
if type == TokenType.IDENTIFIER: if type == TokenType.IDENTIFIER:
return parseFunctionCallOrAssignOrIdentifier(input, parent) return parseFunctionCallOrAssignOrIdentifier(input, parent)
if type == TokenType.PERCENT: if type == TokenType.PERCENT:
return parsePercent(input, parent) return parsePercent(input, parent)
if type == TokenType.OPEN_PAREN: if type == TokenType.OPEN_PAREN:
return parseList(input, parent) return parseList(input, parent)
if type == TokenType.COLON:
return parseColon(input, parent)
def parseArrayElement(input, parent): def parseArrayElement(input, parent):
type = input[0].type type = input[0].type