def doCall2(phrase, args): ''' "Calls" a phrase. This uses the language construct we have to specify the key, scale, instrument, etc to be used in the Phrases. ''' new_env = {} new_env['__up__'] = phrase.outer_env new_env["_notes"] = [{}] for arg in args: if arg[0] == "key": new_env["_scale"] = key_engine(arg[1], arg[2]) elif arg[0] == "instr": new_env[arg[1]] = arg[2] else: new_env["_" + arg[0]] = arg[1] return self.evalStmt(phrase.body, new_env)
def evalStmt(self, stmts, env): ''' Evaluates a list of statements in a given environment. ''' def doCall(phrase, args): ''' "Calls" a phrase. Essentially evaluates the phrase and returns its environment, typically to retreive the notelist. ''' new_env = {} new_env['__up__'] = phrase.outer_env new_env["_notes"] = [{}] for i in range(len(args)): new_env[phrase.args[i]] = args[i] return self.evalStmt(phrase.body, new_env) def doCall2(phrase, args): ''' "Calls" a phrase. This uses the language construct we have to specify the key, scale, instrument, etc to be used in the Phrases. ''' new_env = {} new_env['__up__'] = phrase.outer_env new_env["_notes"] = [{}] for arg in args: if arg[0] == "key": new_env["_scale"] = key_engine(arg[1], arg[2]) elif arg[0] == "instr": new_env[arg[1]] = arg[2] else: new_env["_" + arg[0]] = arg[1] return self.evalStmt(phrase.body, new_env) def update(name,env,val): ''' Updates a binding in the environment to a given value. ''' if not env: sys.exit(1) elif name in env: env[name] = val else: update(name,env['__up__'],val) # Evaluate the statements for s in stmts: if s[0] == 'phrase-def': # Phrase definition, binds a phrase to a name in # the environment env[s[1]] = Phrase(s[1], s[3], s[2], env) elif s[0] == "play": # Play each phrase sequentially for p in s[1]: phrase = self.lookup(p, env) val = doCall(phrase, phrase.args) if self.recording == True: env["_notes"] = val["_notes"] else: if env["_notes"][0] == {}: env["_notes"] = val["_notes"] else: env["_notes"].extend(val["_notes"]) elif s[0] == 'play-with': # only one phrase can follow after phrase = self.lookup(s[1], env) val = doCall2(phrase, s[2]) if self.recording == True: env["_notes"] = val["_notes"] else: if env["_notes"][0] == {}: env["_notes"] = val["_notes"] else: env["_notes"].extend(val["_notes"]) elif s[0] == 'loop': # Loops a set of phrases self.evalStmt(s[1], env) elif s[0] == "asgn": # Assign a binding in the environment env[s[1]] = s[2] elif s[0] == "playing": # Sets the current instrument to be played if s[1] in env.keys(): env["_currInstr"] = env[s[1]] else: env["_currInstr"] = s[1] elif s[0] == "playing-in": # Sets the current instrument to be played and the # octave it will be played in if s[1] in env.keys(): env["_currInstr"] = env[s[1]] else: env["_currInstr"] = s[1] if "_octave"in env.keys() and env["__up__"] is not None: pass else: env["_octave"] = s[2] elif s[0] == "key": # Declare the key to be played if "_scale" in env.keys() and env["__up__"] is not None: print "passing" pass else: # Calls the key engine to dynamically generate the # notes in the scale env["_scale"] = key_engine(s[1], s[2]) elif s[0] == "meter": # Declare the meter if "_meter" in env.keys() and env["__up__"] is not None: pass else: env["_meter"] = s[1] elif s[0] == "tempo": # Declare the tempo if "_tempo" in env.keys() and env["__up__"] is not None: env["_tempo"] = s[1] elif s[0] == "duration": # Declare the default duration to be played if "_duration" in env.keys() and env["__up__"] is not None: pass else: env["_duration"] = s[1] elif s[0] == 'import-instr': # Imports an instrument that can be used in writing songs filename = s[1] ot.importInstrument(filename) elif s[0] == 'include': # Include phrases from another file filename = s[1] try: # Parse and interpret the phrase to get the notelist and environment fil = open(filename, "r") text = fil.read() fil.close() grammar_file = ReadFile("fortissimo/fortissimo.grm") parser = parser_generator.makeParser(grammar_parser.parse(cs164_grammar_file)) input_ast = parser.parse(text) interpr = Intepreter(False) new_env = interpr.evalStmt(input_ast, interpr.global_env) self.global_env.update(new_env) except: print "Could not include file '" + filename + "'." elif s[0] == "notes": # Adds notes to the environments notelist self.addNotesToQueue(s[1], env) else: raise SyntaxError("Illegal or Unimplemented AST node: " + str(s)) return env