Final Project: FAQ
Answers to your commonly asked questions.
General Code Questions
- What code can I change?
- Any and all of it. Make sure you understand the code/its purpose, why you are changing it, and what impacts the change will have. And, use branching and commits judiciously so you can roll back if needed.
- These variable names/method names/... don't make sense to me,
- After you understand their purpose, rename them (using Eclipse's refactoring tool) with a descriptive name that would be more helpful.
- There are code smells in this code!
- Indeed. You need to understand well-designed code as well as poorly designed code (and why it is poorly designed/what problems it causes). You should be able to address the code smells
- How does a switch statement work?
- Switch statement tutorial
- How can I "connect" these two things/have them interact?
- Consider the different ways that we can connect things. You
need to consider the context/scenario to figure out which is the
best way for your code.
- We can make a (non-private) static method that can be called by other classes.
- If we have an object of the class, then we can call methods on that object.
- If we need an object in another class, we can pass it as a parameter to a method or a constructor.
For example, in the Goblin game, the
GamePieceobjects had atakeTurnmethod that took as a parameter aGameobject so that theGamePiececould call methods on theGameobject.As another example, in the
Canvasclass, the constructors take aFrameas a parameter and then store the Frame as a private instance variable. Then, theCanvascan call methods on itsFrameobject.
- Eclipse is having trouble/I can't run Main/
-
- Confirm there aren't any compiler errors in required code.
- Look at the
Problemsview (often in Eclipse's bottom panel) - In Eclipse's
Projectmenu, selectClean...to delete all the .class files and recompile. - If it still doesn't run, delete the Run configuration
(under the Run menu, click on
Run Configurationsand then delete the Java ApplicationMainconfiguration and then try running again.
- Something very weird is happening, e.g., something that seems fundamental or that I copied from other Picasso code or from class slides isn't working.
- Check your assumptions. Common sources are
- You're importing the wrong class. Remember multiple classes can have the same name; make sure you import the class from the appropriate package.
java.langclasses are imported by default, but if you name a class with the same name as one of those, you may not know which one is being used. (Eclipse can show you, though.) It's easiest just to avoid naming classes, e.g.,StringorError.
- I'm overwhelmed. Where should I start?
- Check out the test classes. They make it clearer what the
various components are supposed to do (what are their inputs, what
is their output).
Then, try implementing a unary function: first, write the test cases, then implement the unary function.
- Something isn't working, and I'm not sure what the problem is
- You know what my response is going to be: have you isolated where the problem is? Have you written test cases to test each part so you know where the problem is?
Tokenization
- I know I need to handle quoted strings for the images, but when I try to get the string, I only get the quote.
- This requires understanding a bit about
the StreamTokenizer
class, which is used by the
Tokenizerclass and other associated classes. Look what it says in thenextTokenaboutttypeand in thettypedocumentation about quoted strings. If you make sure you understand the existing tokenization code first (at least at a high level, e.g., where is thenextTokenmethod called? How does its result get used?), then this step becomes fairly straightforward. - What
does
TokenFactory'stokenNameToTokenrepresent? - First, see where it is updated/used. Right click on the name,
then go to References and select Project. One place
it's being updated in is
the
initBuiltinFunctionTokenMappings. That name is probably more descriptive than the map's name. It maps the name of the function to the Token class that represents the function. It is used to distinguish between a known function name and an identifier (a variable).Check out where else it is being updated/used.
- In the Tokenizer class, why is a space added before minus signs?
- Otherwise, the minus sign is included in the variable name when you try to
evaluate the expression
x-y. This isn't a problem with the other operators.I implemented a terrible hack to solve this. I think this should usually work (and not break something else). In
Tokenizer'sparseTokensmethod, this statement (and its comment) is the first line:
// - is seen as a numeric character. If we try to parse, e.g., x-y, // it is seen as one string "x-y". See StreamTokenizer documentation about // handling words. So, our imperfect solution is to always add // a space before a minus sign. Negative numbers will still be // seen as numbers, and the space will mark the end of a word. s = s.replace("-", " -");Here's what is happening: the
StreamTokenizerlooks at characters and tries to figure out what to do with them. According to the documentation, "A word token consists of a word constituent followed by zero or more word constituents or number constituents." So, when theStreamTokenizersees thexinx-y, it grabs every word or numeric constituent that follows. We need the minus character to be a number constituent because we want to be able to parse numbers, e.g., -1. If we try to make the minus sign an "ordinary" character, we can no longer parse negative numbers. So, since this really isn't the focus of the assignment, we'll go with the imperfect solution provided above. (Although I am open to hearing proposals of better solutions.)
Parsing
- The order of operations constants don't make sense. GROUPING should have high precedence.
- You're learning to try to read someone else's code. Note that
GROUPING is not yet used, and this is partial code. I am not sure
if it would be used. It seems like it's placed for the parentheses
of a function, but I don't know what the original goals of this
code were. You can and should change this code to be whatever
makes the most sense to you--well, and has good design.
Note that, if you have your automated JUnit tests, you should be able to make changes to this code and confirm that you are getting correct results fairly easily.
- How should parsing an assignment statement work?
-
Consider each part separately for some sample expressions, e.g.,
a=xandfloor_of_x=floor(x). Then consider, what should happen when the user entersaorfloor_of_x/x?Write JUnit tests for each step in the interpreting of the language for these expressions.
- Tokenizing: What should the tokens be for each example?
- Parsing: What should the result of infix to postfix be? What analyzers need to be involved? What should the expression tree look like?
- Evaluating: What is the result of evaluating an assignment statement?
Note that you should not handle assignments specially, separately. You have all of this parsing infrastructure, so add to the parser to handle assignments.
Consider what functionality/classes you can use/leverage. You may need to do some refactoring to make it all work together well.
Finally, what erroneous assignment statements should you handle, i.e., display an error message?
Semantic Analyzer
- I am getting an error about not being able to find "=AssignmentToken".
- Go to the code where the error occurs by clicking on the stack trace. What is happening in that code? The answer to the next question may be good to reference.
- I made my code for the negate/inversion (!) operator and updated all the right files, but my code isn't finding its semantic analyzer.
- This one is tricky.
!is a comment for the properties file. You'll need to escape the character (using the escape character:\) in the properties file.
Evaluating
- How do I implement
evaluatefor something? - As we discussed in class, make sure you check
ReferenceForExpressionEvaluationsto see if there is anything helpful there. - How should the String expression's evaluate work?
- The description says, "an image of the given file name is read.
This should return the nearest color from the image at the
current (x, y) values. If the image cannot be read, an error is
thrown."
Recall how
Evaluatorworks: it converts the image coordinates (which is an int between 0 and the dimension) to the domain space (-1,1). For the String expression, you'll want to do the opposite: convert from the domain space to image space. - How should
imageWrapandimageClipwork? -
First, refer to the examples for
imageWrapandimageClipon the intrinsics page and compare with the original vortex image.Then, consider this:
Check out
Pixmapfor its code related to images. (You don't need to use a Pixmap object itself, necessarily, because that's more than what you need; just copy and adapt the relevant parts in your code.)Similar to what you've been doing (hopefully), write test cases for each part (tokenizing, parsing, evaluation) before you implement much code. Make a simple test image that will be easy to test.
imageClipis similar, but how the coordinates are kept within the domain is different. (Refer back to the example image.) - I keep getting errors about not being able to find the image file, but the image file is there.
- One trick to help with your debugging is to construct a
Fileobject using the filename and check what its path is (getAbsolutePath()). Does that path match what you expected?You can either change the String that you pass in to make it be the appropriate path or add an image directory in your image code to say where to look for images. Make sure that directory works for all of your teammates and me, i.e., not hardcoded for your computer.
Error Handling
- Errors can happen throughout the code. Do I need error handling statements everywhere?
-
First, let's distinguish error handling (which should be
everywhere) vs reporting errors to the user via the GUI. Errors
should be handled, i.e., the code doesn't crash and is in a stable
state. Exceptions (e.g.,
ParseException) represent the error and can be propagated up to whoever called the method.Reporting errors to the user, however, should not be throughout the code and it shouldn't happen in non-GUI code. Remember the single responsibility principle, and consider that the interpreter code should be independent of the GUI. For example, consider if we wanted to have another GUI for the interpreter, e.g., one that is designed for children or is web-based. As a project-focused example, when you run the JUnit tests, which are focused on the interpreter and should test error cases, those error test cases shouldn't pop up GUI windows and also shouldn't fail because the GUI hasn't been created. Since the tests are automated, you don't want to have to click the OK button (or similar) whenever there is an expected error.
Consider where the central points or bridges are between the GUI and where the errors occurred: that's where the error reporting code should go. There should only be a few places where the error reporting code is called.
- If there is an error when evaluating an expression, the next [valid] expression evaluated doesn't work either. But, if you press the button again, it works.
- Add some print statements to try to figure out what's happening. Is there something leftover from the erroroneous expression?
Testing
- I wrote my JUnit test, but the test is failing, and the output is a little strange.
- Two things that will make testing better and debugging easier:
overriding the
toStringandequalsmethods in the relevant classes that are being compared. - I can't test method X because it's private
- If it's private, is there a method that calls that method that you can test instead? Alternatively, is the method private for a good reason? Or, could the access modifier be changed (for a good reason)?
- How can I test evaluating the ExpressionTreeNodes?
- This should look similar to what we did in class, where we
computed what the resulting RGBColor would be at a specific (x,y)
coordinate. For example:
@Test public void testFloorEvaluation() { Floor myTree = new Floor(new X()); // some straightforward tests assertEquals(new RGBColor(0, 0, 0), myTree.evaluate(.4, -1)); assertEquals(new RGBColor(0, 0, 0), myTree.evaluate(.999, -1)); assertEquals(new RGBColor(-1, -1, -1), myTree.evaluate(-.7, -1)); // test the ints; remember that y's value doesn't matter for (int i = -1; i <= 1; i++) { assertEquals(new RGBColor(i, i, i), myTree.evaluate(i, -i)); assertEquals(new RGBColor(i, i, i), myTree.evaluate(i, i)); } double[] tests = {-.7, -.00001, .000001, .5}; for( double testVal : tests) { double floorOfTestVal = Math.floor(testVal); assertEquals(new RGBColor(floorOfTestVal, floorOfTestVal, floorOfTestVal), myTree.evaluate(testVal, -1)); assertEquals(new RGBColor(floorOfTestVal, floorOfTestVal, floorOfTestVal), myTree.evaluate(testVal, testVal)); } }
GitHub
- Eclipse is saying that there are conflicts in our main branch, and I'm unable to merge my branch.
- Yeah, that happens. Try to resolve the conflicts. You'll need to decide if you want to use that version or your version or maybe do a merge. After resolving the conflicts, stage them for commitment and then commit. Eclipse's User Guide
GUI
- Wouldn't it be cool if I could press enter on the text box, and evaluation would happen? How do I do that?
- Yes, in fact, that is required functionality for the preliminary
implementation. You'll want to look into adding
an
ActionListenerto the text field.
Navigating Code
As discussed in class, there are several ways you can navigate the code to find what you are looking for in Eclipse.
- Use the Search capabilities, probably use the File Search or Java Search, if you want to look for something more specifically.
- Right click on a class/object/method and go to
Referencesand then selectThis Projectto see where that is referenced in your code. - Use
F3to jump to an object's or method's declaration. - Click on a variable in a Java class, and you'll see gray marks in the sidebar that show where the variable is used.
Configuring Eclipse
- Whenever I try to open a
.expfile in Eclipse, some other editor opens. -
This should have been resolved in the set up of your project in
Eclipse.
Go back to the set up
and configure Eclipse.
Alternatively, every time you open a .exp file, you can right-click on the file and choose "Open With" and then "Text Editor".
Or, when the pop up about the editors comes up, click to set the "Preferences for File Associations". Add
.expas a file type, and then add the associated editor for the.expfiles. Search for "text" and select "Text Editor". Apply the changes and then close the window.