[VBSCRIPT] Sync with Wine Staging 4.18. CORE-16441
[reactos.git] / dll / win32 / vbscript / parser.y
index 0201099..8ecdf47 100644 (file)
@@ -28,6 +28,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
 static int parser_error(parser_ctx_t *,const char*);
 
 static void parse_complete(parser_ctx_t*,BOOL);
+static void handle_isexpression_script(parser_ctx_t *ctx, expression_t *expr);
 
 static void source_add_statement(parser_ctx_t*,statement_t*);
 static void source_add_class(parser_ctx_t*,class_decl_t*);
@@ -71,8 +72,6 @@ static class_decl_t *add_dim_prop(parser_ctx_t*,class_decl_t*,dim_decl_t*,unsign
 
 static statement_t *link_statements(statement_t*,statement_t*);
 
-static const WCHAR propertyW[] = {'p','r','o','p','e','r','t','y',0};
-
 #define STORAGE_IS_PRIVATE    1
 #define STORAGE_IS_DEFAULT    2
 
@@ -99,31 +98,33 @@ static const WCHAR propertyW[] = {'p','r','o','p','e','r','t','y',0};
     const_decl_t *const_decl;
     case_clausule_t *case_clausule;
     unsigned uint;
-    LONG lng;
+    LONG integer;
     BOOL boolean;
     double dbl;
 }
 
-%token tEOF tNL tREM tEMPTYBRACKETS
-%token tTRUE tFALSE
-%token tNOT tAND tOR tXOR tEQV tIMP tNEQ
-%token tIS tLTEQ tGTEQ tMOD
-%token tCALL tDIM tSUB tFUNCTION tPROPERTY tGET tLET tCONST
-%token tIF tELSE tELSEIF tEND tTHEN tEXIT
-%token tWHILE tWEND tDO tLOOP tUNTIL tFOR tTO tSTEP tEACH tIN
-%token tSELECT tCASE
-%token tBYREF tBYVAL
-%token tOPTION tEXPLICIT
-%token tSTOP
-%token tNOTHING tEMPTY tNULL
-%token tCLASS tSET tNEW tPUBLIC tPRIVATE tDEFAULT tME
-%token tERROR tNEXT tON tRESUME tGOTO
+%token tEXPRESSION tEOF tNL tEMPTYBRACKETS
+%token tLTEQ tGTEQ tNEQ
+%token tSTOP tME tREM
+%token <string> tTRUE tFALSE
+%token <string> tNOT tAND tOR tXOR tEQV tIMP
+%token <string> tIS tMOD
+%token <string> tCALL tDIM tSUB tFUNCTION tGET tLET tCONST
+%token <string> tIF tELSE tELSEIF tEND tTHEN tEXIT
+%token <string> tWHILE tWEND tDO tLOOP tUNTIL tFOR tTO tEACH tIN
+%token <string> tSELECT tCASE
+%token <string> tBYREF tBYVAL
+%token <string> tOPTION
+%token <string> tNOTHING tEMPTY tNULL
+%token <string> tCLASS tSET tNEW tPUBLIC tPRIVATE
+%token <string> tNEXT tON tRESUME tGOTO
 %token <string> tIdentifier tString
-%token <lng> tLong tShort
+%token <string> tDEFAULT tERROR tEXPLICIT tPROPERTY tSTEP
+%token <integer> tInt
 %token <dbl> tDouble
 
-%type <statement> Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt IfStatement Else_opt
-%type <expression> Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression
+%type <statement> Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt BodyStatements IfStatement Else_opt
+%type <expression> Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression ExpressionNl_opt
 %type <expression> ConcatExpression AdditiveExpression ModExpression IntdivExpression MultiplicativeExpression ExpExpression
 %type <expression> NotExpression UnaryExpression AndExpression OrExpression XorExpression EqvExpression
 %type <expression> ConstExpression NumericLiteralExpression
@@ -138,13 +139,14 @@ static const WCHAR propertyW[] = {'p','r','o','p','e','r','t','y',0};
 %type <dim_decl> DimDeclList DimDecl
 %type <dim_list> DimList
 %type <const_decl> ConstDecl ConstDeclList
-%type <string> Identifier
+%type <string> Identifier DotIdentifier
 %type <case_clausule> CaseClausules
 
 %%
 
 Program
     : OptionExplicit_opt SourceElements tEOF    { parse_complete(ctx, $1); }
+    | tEXPRESSION ExpressionNl_opt tEOF         { handle_isexpression_script(ctx, $2); }
 
 OptionExplicit_opt
     : /* empty */                { $$ = FALSE; }
@@ -155,6 +157,15 @@ SourceElements
     | SourceElements StatementNl            { source_add_statement(ctx, $2); }
     | SourceElements ClassDeclaration       { source_add_class(ctx, $2); }
 
+ExpressionNl_opt
+    : /* empty */                           { $$ = NULL; }
+    | Expression tNL                        { $$ = $1; }
+
+BodyStatements
+    : /* empty */                           { $$ = NULL; }
+    | Statement                             { $$ = $1; }
+    | StatementNl BodyStatements            { $$ = link_statements($1, $2); }
+
 StatementsNl_opt
     : /* empty */                           { $$ = NULL; }
     | StatementsNl                          { $$ = $1; }
@@ -210,7 +221,7 @@ SimpleStatement
 
 MemberExpression
     : Identifier                            { $$ = new_member_expression(ctx, NULL, $1); CHECK_ERROR; }
-    | CallExpression '.' Identifier         { $$ = new_member_expression(ctx, $1, $3); CHECK_ERROR; }
+    | CallExpression '.' DotIdentifier      { $$ = new_member_expression(ctx, $1, $3); CHECK_ERROR; }
 
 DimDeclList
     : DimDecl                               { $$ = $1; }
@@ -366,6 +377,7 @@ UnaryExpression
     | CallExpression                { $$ = $1; }
     | tNEW Identifier               { $$ = new_new_expression(ctx, $2); CHECK_ERROR; }
     | '-' UnaryExpression           { $$ = new_unary_expression(ctx, EXPR_NEG, $2); CHECK_ERROR; }
+    | '+' UnaryExpression           { $$ = $2; }
 
 CallExpression
     : PrimaryExpression                 { $$ = $1; }
@@ -381,15 +393,13 @@ LiteralExpression
     | tNOTHING                      { $$ = new_expression(ctx, EXPR_NOTHING, 0); CHECK_ERROR; }
 
 NumericLiteralExpression
-    : tShort                        { $$ = new_long_expression(ctx, EXPR_USHORT, $1); CHECK_ERROR; }
-    | '0'                           { $$ = new_long_expression(ctx, EXPR_USHORT, 0); CHECK_ERROR; }
-    | tLong                         { $$ = new_long_expression(ctx, EXPR_ULONG, $1); CHECK_ERROR; }
+    : '0'                           { $$ = new_long_expression(ctx, EXPR_INT, 0); CHECK_ERROR; }
+    | tInt                          { $$ = new_long_expression(ctx, EXPR_INT, $1); CHECK_ERROR; }
     | tDouble                       { $$ = new_double_expression(ctx, $1); CHECK_ERROR; }
 
 IntegerValue
-    : tShort                        { $$ = $1; }
-    | '0'                           { $$ = 0; }
-    | tLong                         { $$ = $1; }
+    : '0'                           { $$ = 0; }
+    | tInt                          { $$ = $1; }
 
 PrimaryExpression
     : '(' Expression ')'            { $$ = new_unary_expression(ctx, EXPR_BRACKETS, $2); }
@@ -400,25 +410,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
@@ -443,10 +458,67 @@ ArgumentDecl
     | tBYREF Identifier EmptyBrackets_opt       { $$ = new_argument_decl(ctx, $2, TRUE); }
     | tBYVAL Identifier EmptyBrackets_opt       { $$ = new_argument_decl(ctx, $2, FALSE); }
 
-/* 'property' may be both keyword and identifier, depending on context */
+/* these keywords may also be an identifier, depending on context */
 Identifier
     : tIdentifier    { $$ = $1; }
-    | tPROPERTY      { $$ = propertyW; }
+    | tDEFAULT       { $$ = $1; }
+    | tERROR         { $$ = $1; }
+    | tEXPLICIT      { $$ = $1; }
+    | tPROPERTY      { $$ = $1; }
+    | tSTEP          { $$ = $1; }
+
+/* most keywords can be an identifier after a dot */
+DotIdentifier
+    : Identifier     { $$ = $1; }
+    | tTRUE          { $$ = $1; }
+    | tFALSE         { $$ = $1; }
+    | tNOT           { $$ = $1; }
+    | tAND           { $$ = $1; }
+    | tOR            { $$ = $1; }
+    | tXOR           { $$ = $1; }
+    | tEQV           { $$ = $1; }
+    | tIMP           { $$ = $1; }
+    | tIS            { $$ = $1; }
+    | tMOD           { $$ = $1; }
+    | tCALL          { $$ = $1; }
+    | tDIM           { $$ = $1; }
+    | tSUB           { $$ = $1; }
+    | tFUNCTION      { $$ = $1; }
+    | tGET           { $$ = $1; }
+    | tLET           { $$ = $1; }
+    | tCONST         { $$ = $1; }
+    | tIF            { $$ = $1; }
+    | tELSE          { $$ = $1; }
+    | tELSEIF        { $$ = $1; }
+    | tEND           { $$ = $1; }
+    | tTHEN          { $$ = $1; }
+    | tEXIT          { $$ = $1; }
+    | tWHILE         { $$ = $1; }
+    | tWEND          { $$ = $1; }
+    | tDO            { $$ = $1; }
+    | tLOOP          { $$ = $1; }
+    | tUNTIL         { $$ = $1; }
+    | tFOR           { $$ = $1; }
+    | tTO            { $$ = $1; }
+    | tEACH          { $$ = $1; }
+    | tIN            { $$ = $1; }
+    | tSELECT        { $$ = $1; }
+    | tCASE          { $$ = $1; }
+    | tBYREF         { $$ = $1; }
+    | tBYVAL         { $$ = $1; }
+    | tOPTION        { $$ = $1; }
+    | tNOTHING       { $$ = $1; }
+    | tEMPTY         { $$ = $1; }
+    | tNULL          { $$ = $1; }
+    | tCLASS         { $$ = $1; }
+    | tSET           { $$ = $1; }
+    | tNEW           { $$ = $1; }
+    | tPUBLIC        { $$ = $1; }
+    | tPRIVATE       { $$ = $1; }
+    | tNEXT          { $$ = $1; }
+    | tON            { $$ = $1; }
+    | tRESUME        { $$ = $1; }
+    | tGOTO          { $$ = $1; }
 
 /* Most statements accept both new line and ':' as separators */
 StSep
@@ -487,6 +559,22 @@ static void parse_complete(parser_ctx_t *ctx, BOOL option_explicit)
     ctx->option_explicit = option_explicit;
 }
 
+static void handle_isexpression_script(parser_ctx_t *ctx, expression_t *expr)
+{
+    retval_statement_t *stat;
+
+    ctx->parse_complete = TRUE;
+    if(!expr)
+        return;
+
+    stat = new_statement(ctx, STAT_RETVAL, sizeof(*stat));
+    if(!stat)
+        return;
+
+    stat->expr = expr;
+    ctx->stats = &stat->stat;
+}
+
 static void *new_expression(parser_ctx_t *ctx, expression_type_t type, size_t size)
 {
     expression_t *expr;
@@ -879,7 +967,7 @@ static class_decl_t *add_class_function(parser_ctx_t *ctx, class_decl_t *class_d
     function_decl_t *iter;
 
     for(iter = class_decl->funcs; iter; iter = iter->next) {
-        if(!strcmpiW(iter->name, decl->name)) {
+        if(!wcsicmp(iter->name, decl->name)) {
             if(decl->type == FUNC_SUB || decl->type == FUNC_FUNCTION) {
                 FIXME("Redefinition of %s::%s\n", debugstr_w(class_decl->name), debugstr_w(decl->name));
                 ctx->hres = E_FAIL;
@@ -967,12 +1055,12 @@ void *parser_alloc(parser_ctx_t *ctx, size_t size)
     return ret;
 }
 
-HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter)
+HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimiter, DWORD flags)
 {
     static const WCHAR html_delimiterW[] = {'<','/','s','c','r','i','p','t','>',0};
 
     ctx->code = ctx->ptr = code;
-    ctx->end = ctx->code + strlenW(ctx->code);
+    ctx->end = ctx->code + lstrlenW(ctx->code);
 
     heap_pool_init(&ctx->heap);
 
@@ -984,7 +1072,10 @@ HRESULT parse_script(parser_ctx_t *ctx, const WCHAR *code, const WCHAR *delimite
     ctx->stats = ctx->stats_tail = NULL;
     ctx->class_decls = NULL;
     ctx->option_explicit = FALSE;
-    ctx->is_html = delimiter && !strcmpiW(delimiter, html_delimiterW);
+    ctx->is_html = delimiter && !wcsicmp(delimiter, html_delimiterW);
+
+    if(flags & SCRIPTTEXT_ISEXPRESSION)
+        ctx->last_token = tEXPRESSION;
 
     parser_parse(ctx);