In the Windows vbscript parser, some End statements don't require a newline preceeding them. The game Ymir actually depends on this.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/parser.y | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y index 11a8f9d..d4f5eb3 100644 --- a/dlls/vbscript/parser.y +++ b/dlls/vbscript/parser.y @@ -122,7 +122,7 @@ static statement_t *link_statements(statement_t*,statement_t*); %token <integer> tInt %token <dbl> tDouble
-%type <statement> Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt IfStatement Else_opt +%type <statement> Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt BodyStatements IfStatement Else_opt %type <expression> Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression %type <expression> ConcatExpression AdditiveExpression ModExpression IntdivExpression MultiplicativeExpression ExpExpression %type <expression> NotExpression UnaryExpression AndExpression OrExpression XorExpression EqvExpression @@ -155,6 +155,11 @@ SourceElements | SourceElements StatementNl { source_add_statement(ctx, $2); } | SourceElements ClassDeclaration { source_add_class(ctx, $2); }
+BodyStatements + : /* empty */ { $$ = NULL; } + | Statement { $$ = $1; } + | StatementNl BodyStatements { $$ = link_statements($1, $2); } + StatementsNl_opt : /* empty */ { $$ = NULL; } | StatementsNl { $$ = $1; } @@ -399,25 +404,30 @@ ClassDeclaration
ClassBody : /* empty */ { $$ = new_class_decl(ctx); } + | FunctionDecl { $$ = add_class_function(ctx, new_class_decl(ctx), $1); CHECK_ERROR; } | FunctionDecl StSep ClassBody { $$ = add_class_function(ctx, $3, $1); CHECK_ERROR; } /* FIXME: We should use DimDecl here to support arrays, but that conflicts with PropertyDecl. */ + | Storage tIdentifier { dim_decl_t *dim_decl = new_dim_decl(ctx, $2, FALSE, NULL); CHECK_ERROR; + $$ = add_dim_prop(ctx, new_class_decl(ctx), dim_decl, $1); CHECK_ERROR; } | Storage tIdentifier StSep ClassBody { dim_decl_t *dim_decl = new_dim_decl(ctx, $2, FALSE, NULL); CHECK_ERROR; $$ = add_dim_prop(ctx, $4, dim_decl, $1); CHECK_ERROR; } + | tDIM DimDecl { $$ = add_dim_prop(ctx, new_class_decl(ctx), $2, 0); CHECK_ERROR; } | tDIM DimDecl StSep ClassBody { $$ = add_dim_prop(ctx, $4, $2, 0); CHECK_ERROR; } + | PropertyDecl { $$ = add_class_function(ctx, new_class_decl(ctx), $1); CHECK_ERROR; } | PropertyDecl StSep ClassBody { $$ = add_class_function(ctx, $3, $1); CHECK_ERROR; }
PropertyDecl - : Storage_opt tPROPERTY tGET tIdentifier ArgumentsDecl_opt StSep StatementsNl_opt tEND tPROPERTY + : Storage_opt tPROPERTY tGET tIdentifier ArgumentsDecl_opt StSep BodyStatements tEND tPROPERTY { $$ = new_function_decl(ctx, $4, FUNC_PROPGET, $1, $5, $7); CHECK_ERROR; } - | Storage_opt tPROPERTY tLET tIdentifier '(' ArgumentDecl ')' StSep StatementsNl_opt tEND tPROPERTY + | Storage_opt tPROPERTY tLET tIdentifier '(' ArgumentDecl ')' StSep BodyStatements tEND tPROPERTY { $$ = new_function_decl(ctx, $4, FUNC_PROPLET, $1, $6, $9); CHECK_ERROR; } - | Storage_opt tPROPERTY tSET tIdentifier '(' ArgumentDecl ')' StSep StatementsNl_opt tEND tPROPERTY + | Storage_opt tPROPERTY tSET tIdentifier '(' ArgumentDecl ')' StSep BodyStatements tEND tPROPERTY { $$ = new_function_decl(ctx, $4, FUNC_PROPSET, $1, $6, $9); CHECK_ERROR; }
FunctionDecl - : Storage_opt tSUB Identifier ArgumentsDecl_opt StSep StatementsNl_opt tEND tSUB + : Storage_opt tSUB Identifier ArgumentsDecl_opt StSep BodyStatements tEND tSUB { $$ = new_function_decl(ctx, $3, FUNC_SUB, $1, $4, $6); CHECK_ERROR; } - | Storage_opt tFUNCTION Identifier ArgumentsDecl_opt StSep StatementsNl_opt tEND tFUNCTION + | Storage_opt tFUNCTION Identifier ArgumentsDecl_opt StSep BodyStatements tEND tFUNCTION { $$ = new_function_decl(ctx, $3, FUNC_FUNCTION, $1, $4, $6); CHECK_ERROR; }
Storage_opt
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/vbscript/tests/run.c | 99 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+)
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 15a8f10..87540a3 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -2077,6 +2077,104 @@ static void test_gc(void) IActiveScriptParse_Release(parser); }
+static void test_end_parse_without_nl(void) +{ + static const char *invalid[] = + { + /* If...End If */ + "If 0 > 1 Then\n" + " x = 0 End If\n", + + /* While...End While */ + "While False\n" + " x = 0 End While\n", + + /* While...Wend */ + "While False\n" + " x = 0 Wend\n", + + /* Do While...Loop */ + "Do While False\n" + " x = 0 Loop\n", + + /* Do Until...Loop */ + "Do Until True\n" + " x = 0 Loop\n", + + /* Do...Loop While */ + "Do\n" + " x = 0 Loop While False\n", + + /* Do...Loop Until */ + "Do\n" + " x = 0 Loop Until True\n", + + /* Select...End Select */ + "x = False\n" + "Select Case 42\n" + " Case 0\n" + " Call ok(False, "unexpected case")\n" + " Case 42\n" + " x = True End Select\n" + "Call ok(x, "wrong case")\n", + + /* Class...End Class (empty) */ + "Class C End Class" + }; + static const char *valid[] = + { + /* Sub...End Sub */ + "Sub test\n" + " x = 42 End Sub\n", + + /* Sub...End Sub (with a Call) */ + "Sub test\n" + " x = 42\n" + " Call ok(x = 42, "x = " & x)End Sub\n" + "Call test()", + + /* Function...End Function (with a Call) */ + "Function test(x)\n" + " Call ok(x > 0, "x = " & x)End Function\n" + "test(1)", + + /* Class...End Class (with storage identifier) */ + "Class C\n" + " Public x End Class\n", + + /* Class...End Class (with Dim decl) */ + "Class C\n" + " Dim x End Class\n", + + /* Class...End Class (with Function decl) */ + "Class C\n" + " Function test(ByVal x)\n" + " x = 0 End Function End Class\n", + + /* Property...End Property */ + "Class C\n" + " Public x\n" + " Public default Property Get defprop\n" + " defprop = x End Property End Class\n" + }; + HRESULT hres; + UINT i; + + for (i = 0; i < ARRAY_SIZE(invalid); i++) + { + SET_EXPECT(OnScriptError); + hres = parse_script_ar(invalid[i]); + ok(FAILED(hres), "[%u] script did not fail\n", i); + todo_wine CHECK_CALLED(OnScriptError); + } + + for (i = 0; i < ARRAY_SIZE(valid); i++) + { + hres = parse_script_ar(valid[i]); + ok(SUCCEEDED(hres), "[%u] script failed\n", i); + } +} + static void test_msgbox(void) { HRESULT hres; @@ -2499,6 +2597,7 @@ static void run_tests(void)
test_procedures(); test_gc(); + test_end_parse_without_nl(); test_msgbox(); test_parse_context(); }
Hi Gabriel,
On 9/5/19 2:48 PM, Gabriel Ivăncescu wrote:
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
dlls/vbscript/tests/run.c | 99 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+)
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 15a8f10..87540a3 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -2077,6 +2077,104 @@ static void test_gc(void) IActiveScriptParse_Release(parser); }
+static void test_end_parse_without_nl(void) +{
How calling it test_parse_errors() with an intention of adding more parser errors to the array in the future?
- static const char *invalid[] =
- {
/* If...End If */
"If 0 > 1 Then\n"
" x = 0 End If\n",
/* While...End While */
"While False\n"
" x = 0 End While\n",
/* While...Wend */
"While False\n"
" x = 0 Wend\n",
/* Do While...Loop */
"Do While False\n"
" x = 0 Loop\n",
/* Do Until...Loop */
"Do Until True\n"
" x = 0 Loop\n",
/* Do...Loop While */
"Do\n"
" x = 0 Loop While False\n",
/* Do...Loop Until */
"Do\n"
" x = 0 Loop Until True\n",
/* Select...End Select */
"x = False\n"
"Select Case 42\n"
" Case 0\n"
" Call ok(False, \"unexpected case\")\n"
" Case 42\n"
" x = True End Select\n"
"Call ok(x, \"wrong case\")\n",
/* Class...End Class (empty) */
"Class C End Class"
- };
- static const char *valid[] =
- {
Please add tests that are expected to parse correctly to lang.vbs instead.
Thanks,
Jacek
On 9/6/19 4:30 PM, Jacek Caban wrote:
Hi Gabriel,
On 9/5/19 2:48 PM, Gabriel Ivăncescu wrote:
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
dlls/vbscript/tests/run.c | 99 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+)
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c index 15a8f10..87540a3 100644 --- a/dlls/vbscript/tests/run.c +++ b/dlls/vbscript/tests/run.c @@ -2077,6 +2077,104 @@ static void test_gc(void) IActiveScriptParse_Release(parser); } +static void test_end_parse_without_nl(void) +{
How calling it test_parse_errors() with an intention of adding more parser errors to the array in the future?
+ static const char *invalid[] = + { + /* If...End If */ + "If 0 > 1 Then\n" + " x = 0 End If\n",
+ /* While...End While */ + "While False\n" + " x = 0 End While\n",
+ /* While...Wend */ + "While False\n" + " x = 0 Wend\n",
+ /* Do While...Loop */ + "Do While False\n" + " x = 0 Loop\n",
+ /* Do Until...Loop */ + "Do Until True\n" + " x = 0 Loop\n",
+ /* Do...Loop While */ + "Do\n" + " x = 0 Loop While False\n",
+ /* Do...Loop Until */ + "Do\n" + " x = 0 Loop Until True\n",
+ /* Select...End Select */ + "x = False\n" + "Select Case 42\n" + " Case 0\n" + " Call ok(False, "unexpected case")\n" + " Case 42\n" + " x = True End Select\n" + "Call ok(x, "wrong case")\n",
+ /* Class...End Class (empty) */ + "Class C End Class" + }; + static const char *valid[] = + {
Please add tests that are expected to parse correctly to lang.vbs instead.
Thanks,
Jacek
Hi Jacek,
Sure I'll do those changes in a moment, thanks for the review.
Signed-off-by: Jacek Caban jacek@codeweavers.com
On 9/5/19 2:48 PM, Gabriel Ivăncescu wrote:
ClassBody : /* empty */ { $$ = new_class_decl(ctx); }
- | FunctionDecl { $$ = add_class_function(ctx, new_class_decl(ctx), $1); CHECK_ERROR; } | FunctionDecl StSep ClassBody { $$ = add_class_function(ctx, $3, $1); CHECK_ERROR; } /* FIXME: We should use DimDecl here to support arrays, but that conflicts with PropertyDecl. */
- | Storage tIdentifier { dim_decl_t *dim_decl = new_dim_decl(ctx, $2, FALSE, NULL); CHECK_ERROR;
$$ = add_dim_prop(ctx, new_class_decl(ctx), dim_decl, $1); CHECK_ERROR; } | Storage tIdentifier StSep ClassBody { dim_decl_t *dim_decl = new_dim_decl(ctx, $2, FALSE, NULL); CHECK_ERROR; $$ = add_dim_prop(ctx, $4, dim_decl, $1); CHECK_ERROR; }
- | tDIM DimDecl { $$ = add_dim_prop(ctx, new_class_decl(ctx), $2, 0); CHECK_ERROR; } | tDIM DimDecl StSep ClassBody { $$ = add_dim_prop(ctx, $4, $2, 0); CHECK_ERROR; }
- | PropertyDecl { $$ = add_class_function(ctx, new_class_decl(ctx), $1); CHECK_ERROR; } | PropertyDecl StSep ClassBody { $$ = add_class_function(ctx, $3, $1); CHECK_ERROR; }
I'm fine with it for now, but it would be nice to get rid of those duplications at some point.
Thanks,
Jacek