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 why you are changing it 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). 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
GamePiece
objects had atakeTurn
method that took as a parameter aGame
object so that theGamePiece
could call methods on theGame
object.As another example, in the
Canvas
class, the constructors take aFrame
as a parameter and then store the Frame as a private instance variable. Then, theCanvas
can call methods on itsFrame
object.
- Eclipse is having trouble/I can't run Main/
-
- Confirm there aren't any compiler errors in required code.
- Look at the
Problems
view (often in Eclipse's bottom panel) - In Eclipse's
Project
menu, 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 Configurations
and then delete the Java ApplicationMain
configuration 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.lang
classes 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.,String
orError
.
- 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.
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
Tokenizer
class and other associated classes. Look what it says in thenextToken
aboutttype
and in thettype
documentation about quoted strings. If you make sure you understand the existing tokenization code first (at least at a high level, e.g., where is thenextToken
method called? How does its result get used?), then this step becomes fairly straightforward. - What does
tokenNameToToken
represent? - 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
'sparseTokens
method, 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
StreamTokenizer
looks 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 theStreamTokenizer
sees thex
inx-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=x
andfloor_of_x=floor(x)
. Then consider, what should happen when the user entersa
orfloor_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 about 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 evaluate something?
- As we discussed in class, make sure you check
ReferenceForExpressionEvaluations
to see if there is anything helpful there. - How should String'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
Evaluator
works: it converts the image coordinates (which is an int between 0 and the dimension) to the domain space (-1,1). For String, you'll want to do the opposite: convert from the domain space to image space. - How should
imageWrap
andimageClip
work? -
First, refer to the examples for
imageWrap
andimageClip
on the intrinsics page and compare with the original vortex image.Then, consider this:
Check out
Pixmap
for its code related to images. (You don't need to use a Pixmap object itself -- 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.
imageClip
is 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
File
object 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
toString
andequals
methods 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?
- 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. This links to a simple example of how to make the text field respond to the user pressing enter.
Configuring Eclipse
- Whenever I try to open a
.exp
file in Eclipse, some other editor opens. -
There are a few options:
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
.exp
as a file type, and then add the associated editor for the.exp
files. Search for "text" and select "Text Editor". Apply the changes and then close the window.