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*);
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
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
%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; }
| 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; }
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; }
| 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; }
| 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); }
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
| 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
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;
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;
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);
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);