Difference between revisions of "S2 Guide: Troubleshooting"
(2 intermediate revisions by the same user not shown) | |||
Line 175: | Line 175: | ||
The compiler tells us it was expecting a ";" character instead of what it found. Notice that this time, the line the compiler has trouble with is the line <em>after</em> the line we forgot the semicolon on. | The compiler tells us it was expecting a ";" character instead of what it found. Notice that this time, the line the compiler has trouble with is the line <em>after</em> the line we forgot the semicolon on. | ||
− | That's because the compiler doesn't look at line breaks to figure out where statements end, it looks at | + | That's because the compiler doesn't look at line breaks to figure out where statements end, it looks at semicolons for that. This means that you can split a single statement over two lines, if you wanted to. Here's an example of that statement (properly ended) across two lines: : |
<syntaxhighlight lang="s2"> | <syntaxhighlight lang="s2"> | ||
Line 183: | Line 183: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | A line that doesn't end in a | + | A line that doesn't end in a semicolon is not automatically a problem for the compiler -- but when the next line doesn't make sense as a continuation of the statement, it will trigger an error. To fix this problem, we need to put a semicolon at the end of the appropriate line: |
<syntaxhighlight lang="s2"> | <syntaxhighlight lang="s2"> | ||
Line 247: | Line 247: | ||
I'm going to put a bracket set (<tt>[]</tt>) around the exact position the compile error is complaining about expecting an open parenthesis(<tt>(</tt>) there: | I'm going to put a bracket set (<tt>[]</tt>) around the exact position the compile error is complaining about expecting an open parenthesis(<tt>(</tt>) there: | ||
− | var int length = test<strong>[-]</strong>>length(); | + | var int length = test<strong>[-]</strong>>length(); |
Why was the compiler expecting an open parenthesis there? Without <tt>$</tt> in front of test, the compiler doesn't know to treat it as a variable. It instead treats test as a global function, and function calls require parentheses, e.g. <tt>test()</tt>. | Why was the compiler expecting an open parenthesis there? Without <tt>$</tt> in front of test, the compiler doesn't know to treat it as a variable. It instead treats test as a global function, and function calls require parentheses, e.g. <tt>test()</tt>. |
Latest revision as of 05:26, 20 June 2010
Contents
- 1 Syntax checklist
- 2 Deciphering compile errors
- 2.1 Compiler background
- 2.2 Forgetting to declare a variable
- 2.3 Mixing up variable types
- 2.4 Forgetting the semicolon (;) at the end of a statement
- 2.5 Not putting $ in front of a variable being accessed
- 2.6 Forgetting to use parentheses on a function call
- 2.7 Forgetting the end parentheses on a function call
- 2.8 Forgetting code block brackets
- 2.9 Accidentally using a $ when declaring a variable
Syntax checklist
- Are you ending all statements with a semicolon (;)?
- Have you declared all variables you are using?
- Are you using $ when you're accessing variables?
- Do your function calls have matching parentheses?
- Do your code blocks have matching brackets?
- If the error is on a line you are trying to use a variable in a string, have you tried using the ${variable} format?
Deciphering compile errors
The layer editor won't let you save a layer that contains compiler errors. Let's say that in the S2 Cookbook: A Testbed Layout, I test some code that has syntax errors where it says "# Code you want to test goes here". Here are some example situations of the kinds of compile errors I can encounter, and their solution.
Compiler background
The compiler is a program that:
- Breaks up the S2 code into little chunks called "tokens" or "nodes"
- Assembles all those tokens into a working program in Perl
If we break the rules of the S2 programming language, the compiler can give errors.
Forgetting to declare a variable
Let's make a really easy error first, to get through the basics. Here's an example where I forget to declare the $test variable before I use it:
var int length = $test->length();
(This kind of a situation could also happen if I meant to use an existing variable but misspelled its name!)
When I try to save and compile, this is the compiler error I get:
S2 Compiler Output at Thu Jun 17 10:23:17 2010 Error compiling layer: Compile error: line 15, column 22: Unknown local variable $test S2::NodeVarRef, S2/NodeVarRef.pm, 180 S2::NodeVarRef, S2/NodeVarRef.pm, 151 S2::NodeTerm, S2/NodeTerm.pm, 182 S2::NodeTerm, S2/NodeTerm.pm, 66 S2::NodeExpr, S2/NodeExpr.pm, 46 S2::NodeVarDeclStmt, S2/NodeVarDeclStmt.pm, 54 S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 108 S2::NodeFunction, S2/NodeFunction.pm, 230 S2::Checker, S2/Checker.pm, 374 S2::Compiler, S2/Compiler.pm, 34 Context 11: """</head>"""; 12: """<body>"""; 13: 14: 15: var int length = $test->length(); 16: 17: """</body>"""; 18: """</html>"""; 19: }
You'll notice that the compiler gives us the line and column (how many characters from the start of the line) the error starts on. The message in this instance is pretty obvious--it's telling us that that the variable $test is unknown. The lines after that are called a traceback, and they indicate what steps the parser was taking to make the tokens--this is usually not very useful to most people.
After the error message and traceback, the compiler helpfully gives us some context consisting of the line it had trouble with, emphasized, along with the some surrounding lines. This helps us find the troublesome place in the code, or see if we can see what the problem is.
To fix this problem, we just need to declare the variable before we use it:
var string test = "test"; var int length = $test->length();
Mixing up variable types
What happens if we try to assign the value from one type of variable to a variable with a different type?
var string test = "test"; var int length = $test;
Resulting compile error:
S2 Compiler Output at Thu Jun 17 16:06:44 2010 Error compiling layer: Compile error: line 15, column 5: Can't initialize variable 'length' of type int with expression of type string S2::NodeVarDeclStmt, S2/NodeVarDeclStmt.pm, 55 S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 108 S2::NodeFunction, S2/NodeFunction.pm, 230 S2::Checker, S2/Checker.pm, 374 S2::Compiler, S2/Compiler.pm, 34 Context 11: """</head>"""; 12: """<body>"""; 13: 14: var string test = "test"; 15: var int length = $test; 16: 17: """</body>"""; 18: """</html>"""; 19: }
If we're assigning to a variable that's not being declared at the same time:
var string test = "test"; var int length; $length = $test;
The error is slightly different:
S2 Compiler Output at Thu Jun 17 16:12:35 2010 Error compiling layer: Compile error: line 16, column 5: Can't assign type string to int S2::NodeAssignExpr, S2/NodeAssignExpr.pm, 73 S2::NodeExpr, S2/NodeExpr.pm, 46 S2::NodeExprStmt, S2/NodeExprStmt.pm, 35 S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 108 S2::NodeFunction, S2/NodeFunction.pm, 230 S2::Checker, S2/Checker.pm, 374 S2::Compiler, S2/Compiler.pm, 34 Context 12: """<body>"""; 13: 14: var string test = "test"; 15: var int length; 16: $length = $test; 17: 18: """</body>"""; 19: """</html>"""; 20: }
Fixing this problem depends on what you were trying to achieve, but you need to make sure you're not trying to match up two values of a different type.
Forgetting the semicolon (;) at the end of a statement
var string test = "test" var int length = $test->length();
Compile error: line 15, column 5: Unexpected token found. Expecting: [TokenPunct] = ; Got: [TokenKeyword] = var S2::Node, S2/Node.pm, 144 S2::NodeVarDeclStmt, S2/NodeVarDeclStmt.pm, 35 S2::NodeStmt, S2/NodeStmt.pm, 62 S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 43 S2::NodeFunction, S2/NodeFunction.pm, 104 S2::Layer, S2/Layer.pm, 59 S2::Compiler, S2/Compiler.pm, 27 Context 11: """</head>"""; 12: """<body>"""; 13: 14: var string test = "test" 15: var int length = $test->length(); 16: 17: """</body>"""; 18: """</html>"""; 19: }
The compiler tells us it was expecting a ";" character instead of what it found. Notice that this time, the line the compiler has trouble with is the line after the line we forgot the semicolon on.
That's because the compiler doesn't look at line breaks to figure out where statements end, it looks at semicolons for that. This means that you can split a single statement over two lines, if you wanted to. Here's an example of that statement (properly ended) across two lines: :
var string test = "test"; var int length = $test->length();
A line that doesn't end in a semicolon is not automatically a problem for the compiler -- but when the next line doesn't make sense as a continuation of the statement, it will trigger an error. To fix this problem, we need to put a semicolon at the end of the appropriate line:
var string test = "test"; var int length = $test->length();
Not putting $ in front of a variable being accessed
Here's some code where I forgot to put a $ in front of a variable I am using:
var string test = "test"; var int length = test->length();
This is the compiler error I get:
S2 Compiler Output at Thu Jun 17 10:13:02 2010 Error compiling layer: Compile error: line 15, column 26: Unexpected token found. Expecting [TokenPunct] = ( Got: [TokenPunct] = -> S2::Node, S2/Node.pm, 144 S2::NodeArguments, S2/NodeArguments.pm, 25 S2::NodeTerm, S2/NodeTerm.pm, 471 S2::NodeIncExpr, S2/NodeIncExpr.pm, 41 S2::NodeTypeCastOp, S2/NodeTypeCastOp.pm, 29 S2::NodeInstanceOf, S2/NodeInstanceOf.pm, 29 S2::NodeUnaryExpr, S2/NodeUnaryExpr.pm, 40 S2::NodeProduct, S2/NodeProduct.pm, 28 S2::NodeSum, S2/NodeSum.pm, 31 S2::NodeRelExpr, S2/NodeRelExpr.pm, 29 S2::NodeEqExpr, S2/NodeEqExpr.pm, 29 S2::NodeLogAndExpr, S2/NodeLogAndExpr.pm, 29 S2::NodeLogOrExpr, S2/NodeLogOrExpr.pm, 29 S2::NodeRange, S2/NodeRange.pm, 29 S2::NodeCondExpr, S2/NodeCondExpr.pm, 29 S2::NodeAssignExpr, S2/NodeAssignExpr.pm, 29 S2::NodeExpr, S2/NodeExpr.pm, 29 S2::NodeVarDeclStmt, S2/NodeVarDeclStmt.pm, 33 S2::NodeStmt, S2/NodeStmt.pm, 62 S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 43 S2::NodeFunction, S2/NodeFunction.pm, 104 S2::Layer, S2/Layer.pm, 59 S2::Compiler, S2/Compiler.pm, 27 Context 11: """</head>"""; 12: """<body>"""; 13: 14: var string test = "test"; 15: var int length = test->length(); 16: 17: """</body>"""; 18: """</html>"""; 19: }
You'll note that the compiler error doesn't tell us exactly what the problem is. It tells us what "token" (part of the programming language) it was expecting, and what it got.
I'm going to put a bracket set ([]) around the exact position the compile error is complaining about expecting an open parenthesis(() there:
var int length = test[-]>length();
Why was the compiler expecting an open parenthesis there? Without $ in front of test, the compiler doesn't know to treat it as a variable. It instead treats test as a global function, and function calls require parentheses, e.g. test().
Since that error message is pretty confusing, the best way to figure out the problem is to examine the line and run through the Syntax Checklist listed above. We'll find that we've broken the rule about using $ when we're accessing variables.
To fix the error, we put the $ character in front of the variable we're trying to access.
var string test = "test"; var int length = $test->length();
Forgetting to use parentheses on a function call
var string test = "test"; var int length = $test->length;
S2 Compiler Output at Thu Jun 17 16:30:31 2010 Error compiling layer: Compile error: line 15, column 35: Unexpected token found. Expecting: [TokenPunct] = ( Got: [TokenPunct] = ; S2::Node, S2/Node.pm, 144 S2::NodeArguments, S2/NodeArguments.pm, 25 S2::NodeTerm, S2/NodeTerm.pm, 471 S2::NodeIncExpr, S2/NodeIncExpr.pm, 41 S2::NodeTypeCastOp, S2/NodeTypeCastOp.pm, 29 S2::NodeInstanceOf, S2/NodeInstanceOf.pm, 29 S2::NodeUnaryExpr, S2/NodeUnaryExpr.pm, 40 S2::NodeProduct, S2/NodeProduct.pm, 28 S2::NodeSum, S2/NodeSum.pm, 31 S2::NodeRelExpr, S2/NodeRelExpr.pm, 29 S2::NodeEqExpr, S2/NodeEqExpr.pm, 29 S2::NodeLogAndExpr, S2/NodeLogAndExpr.pm, 29 S2::NodeLogOrExpr, S2/NodeLogOrExpr.pm, 29 S2::NodeRange, S2/NodeRange.pm, 29 S2::NodeCondExpr, S2/NodeCondExpr.pm, 29 S2::NodeAssignExpr, S2/NodeAssignExpr.pm, 29 S2::NodeExpr, S2/NodeExpr.pm, 29 S2::NodeVarDeclStmt, S2/NodeVarDeclStmt.pm, 33 S2::NodeStmt, S2/NodeStmt.pm, 62 S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 43 S2::NodeFunction, S2/NodeFunction.pm, 104 S2::Layer, S2/Layer.pm, 59 S2::Compiler, S2/Compiler.pm, 27 Context 11: """</head>"""; 12: """<body>"""; 13: 14: var string test = "test"; 15: var int length = $test->length; 16: 17: """</body>"""; 18: """</html>"""; 19: }
Here's a bracket set ([]) in the position the compiler has trouble with:
var int length = $test->length[;]
Since the compiler is complaining that it didn't expect the token it got, ";", and was expecting a "(" instead, and what we're trying to do is call a function, we put in the brackets and can fix the error:
var string test = "test"; var int length = $test->length();
Forgetting the end parentheses on a function call
var string test = "test"; var int length = $test->length(;
S2 Compiler Output at Thu Jun 17 16:37:46 2010 Error compiling layer: Compile error: line 15, column 36: Can't finish parsing NodeTerm S2::NodeTerm, S2/NodeTerm.pm, 484 S2::NodeIncExpr, S2/NodeIncExpr.pm, 41 S2::NodeTypeCastOp, S2/NodeTypeCastOp.pm, 29 S2::NodeInstanceOf, S2/NodeInstanceOf.pm, 29 S2::NodeUnaryExpr, S2/NodeUnaryExpr.pm, 40 S2::NodeProduct, S2/NodeProduct.pm, 28 S2::NodeSum, S2/NodeSum.pm, 31 S2::NodeRelExpr, S2/NodeRelExpr.pm, 29 S2::NodeEqExpr, S2/NodeEqExpr.pm, 29 S2::NodeLogAndExpr, S2/NodeLogAndExpr.pm, 29 S2::NodeLogOrExpr, S2/NodeLogOrExpr.pm, 29 S2::NodeRange, S2/NodeRange.pm, 29 S2::NodeCondExpr, S2/NodeCondExpr.pm, 29 S2::NodeAssignExpr, S2/NodeAssignExpr.pm, 29 S2::NodeExpr, S2/NodeExpr.pm, 29 S2::NodeArguments, S2/NodeArguments.pm, 33 S2::NodeTerm, S2/NodeTerm.pm, 471 S2::NodeIncExpr, S2/NodeIncExpr.pm, 41 S2::NodeTypeCastOp, S2/NodeTypeCastOp.pm, 29 S2::NodeInstanceOf, S2/NodeInstanceOf.pm, 29 S2::NodeUnaryExpr, S2/NodeUnaryExpr.pm, 40 S2::NodeProduct, S2/NodeProduct.pm, 28 S2::NodeSum, S2/NodeSum.pm, 31 S2::NodeRelExpr, S2/NodeRelExpr.pm, 29 S2::NodeEqExpr, S2/NodeEqExpr.pm, 29 S2::NodeLogAndExpr, S2/NodeLogAndExpr.pm, 29 S2::NodeLogOrExpr, S2/NodeLogOrExpr.pm, 29 S2::NodeRange, S2/NodeRange.pm, 29 S2::NodeCondExpr, S2/NodeCondExpr.pm, 29 S2::NodeAssignExpr, S2/NodeAssignExpr.pm, 29 S2::NodeExpr, S2/NodeExpr.pm, 29 S2::NodeVarDeclStmt, S2/NodeVarDeclStmt.pm, 33 S2::NodeStmt, S2/NodeStmt.pm, 62 S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 43 S2::NodeFunction, S2/NodeFunction.pm, 104 S2::Layer, S2/Layer.pm, 59 S2::Compiler, S2/Compiler.pm, 27 Context 11: """</head>"""; 12: """<body>"""; 13: 14: var string test = "test"; 15: var int length = $test->length(; 16: 17: """</body>"""; 18: """</html>"""; 19: }
This isn't a very clear error! The character it's having trouble with in a bracket set ([]) is:
var int length = $test->length([;]
We can see that there's a parentheses before it that doesn't get closed, and that's probably why it's telling us it can't parse this particular "node".
Close the parenthesis and things will be fine:
var string test = "test"; var int length = $test->length();
Forgetting code block brackets
Starting
var int length = 5; if ( $length > 4 ) print """This is too big!"""; }
S2 Compiler Output at Thu Jun 17 16:37:46 2010 Error compiling layer: Compile error: line 17, column 9: Unexpected token found. Expecting: [TokenPunct] = { Got: [TokenKeyword] = print S2::Node, S2/Node.pm, 144 S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 27 S2::NodeIfStmt, S2/NodeIfStmt.pm, 35 S2::NodeStmt, S2/NodeStmt.pm, 41 S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 43 S2::NodeFunction, S2/NodeFunction.pm, 104 S2::Layer, S2/Layer.pm, 59 S2::Compiler, S2/Compiler.pm, 27 Context 13: 14: var int length = 5; 15: 16: if ( $length > 4 ) 17: print """This is too big!"""; } 18: 19: """</body>"""; 20: """</html>"""; 21: }
This instance is a lot like the missing semicolon ending a statement--the compiler is saying it's expecting a "{" instead of the token it ends up getting.
To fix, add the starting bracket:
var int length = 5; if ( $length > 4 ) { print """This is too big!"""; }
Closing
var int length = 5; if ( $length > 4 ) { print """This is too big!""";
S2 Compiler Output at Thu Jun 17 16:37:46 2010 Error compiling layer: Compile error: line 6, column 1: Didn't find closing brace in statement block S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 52 S2::NodeFunction, S2/NodeFunction.pm, 104 S2::Layer, S2/Layer.pm, 59 S2::Compiler, S2/Compiler.pm, 27 Context 2: layerinfo "name" = "S2 Testbed Layout"; 3: 4: function Page::print() 5: "This is a skeleton page function, for testing." 6: { 7: """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" """; 8: """"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n"""; 9: """<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n"""; 10: """<title>S2 Testbed Layout</title>\n""";
This error is much trickier than the other errors! Instead of giving us an error anywhere around the code we made the mistake in, it's giving us the line with the previous open bracket, way up at the start of the function we're working in. However, from the error we know that the compiler wasn't able to match up a set of braces. It can be hard to figure out where the problem is, but if you go through your program checking to make sure all of your starting braces have closing braces, you'll manage to fix the problem:
var int length = 5; if ( $length > 4 ) { print """This is too big!"""; }
Accidentally using a $ when declaring a variable
Even though you need to use a $ sign to access variables and get into the habit of putting them in front of variable names, you can't use one while declaring them like this:
var string $test = "test";
The error you'll get is:
S2 Compiler Output at Sat Jun 19 23:09:30 2010 Error compiling layer: Compile error: line 15, column 12: Expected identifier. S2::Node, S2/Node.pm, 171 S2::NodeNamedType, S2/NodeNamedType.pm, 36 S2::NodeVarDecl, S2/NodeVarDecl.pm, 30 S2::NodeVarDeclStmt, S2/NodeVarDeclStmt.pm, 30 S2::NodeStmt, S2/NodeStmt.pm, 62 S2::NodeStmtBlock, S2/NodeStmtBlock.pm, 43 S2::NodeFunction, S2/NodeFunction.pm, 104 S2::Layer, S2/Layer.pm, 59 S2::Compiler, S2/Compiler.pm, 27 Context 11: """<title>S2 Testbed Layout</title>\n"""; 12: """</head>\n"""; 13: """<body>\n"""; 14: 15: var string $test = "test"; 16: 17: """</body>\n"""; 18: """</html>\n"""; 19: }
The character it bails on is:
var string [$]test = "test";
When the compiler tells you it expecting an identifier, it's trying to tell you that it wants a valid variable name without the $. Take away the $ and it will work:
var string test = "test";