S2 Guide: Troubleshooting

From Dreamwidth Notes
Jump to: navigation, search

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";