This homework gives you the opportunity to review the earlier class activity and make sure you understand how to refactor a Program/Statement.
- Using recursion, complete the body of the following static
method.
/** * Refactors the given {@code Statement} by renaming every occurrence of * instruction {@code oldName} to {@code newName}. Every other statement is * left unmodified. * * @param s * the {@code Statement} * @param oldName * the name of the instruction to be renamed * @param newName * the new name of the renamed instruction * @updates s * @requires [newName is a valid IDENTIFIER] * @ensures <pre> * s = [#s refactored so that every occurrence of instruction oldName * is replaced by newName] * </pre> */ public static void renameInstruction(Statement s, String oldName, String newName) {...}
- Using the method above, complete the body of the following
static method.
/** * Refactors the given {@code Program} by renaming instruction * {@code oldName}, and every call to it, to {@code newName}. Everything * else is left unmodified. * * @param p * the {@code Program} * @param oldName * the name of the instruction to be renamed * @param newName * the new name of the renamed instruction * @updates p * @requires <pre> * oldName is in DOMAIN(p.context) and * [newName is a valid IDENTIFIER] and * newName is not in DOMAIN(p.context) * </pre> * @ensures <pre> * p = [#p refactored so that instruction oldName and every call * to it are replaced by newName] * </pre> */ public static void renameInstruction(Program p, String oldName, String newName) {...}
- You may hand-draw your answer to this question. Recalling
how much we care that you use correct punctuation when you write
objects' values, and using the notation of
Slides 9-12 in Program, but fully drawing each abstract syntax tree involved,
show the value of p at the end of the following code
snippet.
1 Program p = new Program1(); 2 Map<String, Statement> context = p.newContext(); 3 Statement block = p.newBody(); 4 Statement s = block.newInstance(); 5 p.setName("Get-to-Edge-and-Wait-for-Infection"); 6 s.assembleCall("walk"); 7 block.addToBlock(0, s); 8 s.assembleCall("run"); 9 block.addToBlock(block.lengthOfBlock(), s); 10 s.assembleWhile(Condition.NEXT_IS_NOT_WALL, block); 11 block.addToBlock(0, s); 12 p.swapBody(block); 13 s.assembleCall("move"); 14 block.addToBlock(0, s); 15 s.assembleCall("move"); 16 block.addToBlock(block.lengthOfBlock(), s); 17 context.add("run", block); 18 s.assembleCall("move"); 19 block = block.newInstance(); 20 block.addToBlock(0, s); 21 context.add("walk", block); 22 p.swapContext(context);
- Consider the occurrence on line 19 of the code snippet above of block = block.newInstance(). What would probably have happened if that statement had been replaced by block.clear()? In other words, what is the difference between the two statements? You may hand-draw a diagram to show the difference. (Hint: which are the only two lines in the code snippet in which the statement executed would introduce an alias to a mutable object? (Hint: all contracts in our components catalog advertise every introduction of an alias to a mutable object.))