X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=3698ee57fea8dbf53e653ff85630512542f17353;hb=e7112d5579fc5ddf14b4f2d8236cf7efa339449a;hp=06b5a4fe2ba56aca9e00a8248aba22716fe79e16;hpb=c1b77b2459e0b8687428e6f4932797b869caace1;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index 06b5a4f..3698ee5 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -243,7 +243,7 @@ extern int a3_lex(); %left new2 %left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@' -%nonassoc T_IDENTIFIER +%left T_IDENTIFIER %left above_identifier %left below_else %nonassoc "else" @@ -319,7 +319,10 @@ struct _methodstate { char is_global; int variable_count; + dict_t*unresolved_variables; + char inner; + char uses_parent_function; abc_method_t*abc; int var_index; // for inner methods @@ -470,7 +473,7 @@ static void old_state() static code_t* method_header(methodstate_t*m); static code_t* wrap_function(code_t*c,code_t*header, code_t*body); -static void function_initvars(methodstate_t*m, params_t*params, int flags); +static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0); static char* internal_filename_package = 0; @@ -495,7 +498,7 @@ void initialize_file(char*filename) dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method); } else { state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount); - function_initvars(state->method, 0, 0); + function_initvars(state->method, 0, 0, 1); global->init = abc_initscript(global->file); state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope } @@ -566,16 +569,15 @@ static void xx_scopetest() c = abc_iftrue(c,xx);*/ } - typedef struct _variable { int index; classinfo_t*type; char init; + methodstate_t*method; } variable_t; -static variable_t* find_variable(char*name) +static variable_t* find_variable(state_t*s, char*name) { - state_t* s = state; while(s) { variable_t*v = 0; if(s->method) @@ -589,16 +591,16 @@ static variable_t* find_variable(char*name) } return 0; } -static variable_t* find_variable_safe(char*name) +static variable_t* find_variable_safe(state_t*s, char*name) { - variable_t* v = find_variable(name); + variable_t* v = find_variable(s, name); if(!v) syntaxerror("undefined variable: %s", name); return v; } static char variable_exists(char*name) { - return dict_lookup(state->vars, name)!=0; + return dict_contains(state->vars, name); } code_t*defaultvalue(code_t*c, classinfo_t*type); static int new_variable(const char*name, classinfo_t*type, char init) @@ -607,6 +609,7 @@ static int new_variable(const char*name, classinfo_t*type, char init) v->index = state->method->variable_count; v->type = type; v->init = init; + v->method = state->method; dict_put(state->vars, name, v); @@ -615,7 +618,7 @@ static int new_variable(const char*name, classinfo_t*type, char init) #define TEMPVARNAME "__as3_temp__" static int gettempvar() { - variable_t*v = find_variable(TEMPVARNAME); + variable_t*v = find_variable(state, TEMPVARNAME); if(v) return v->index; return new_variable(TEMPVARNAME, 0, 0); @@ -665,6 +668,14 @@ code_t* var_block(code_t*body) return c; } +void unknown_variable(char*name) +{ + if(!state->method->unresolved_variables) + state->method->unresolved_variables = dict_new(); + if(!dict_contains(state->method->unresolved_variables, name)) + dict_put(state->method->unresolved_variables, name, 0); +} + #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);} static void parsererror(const char*file, int line, const char*f) @@ -763,14 +774,20 @@ static int flags2access(int flags) return access; } -static void function_initvars(methodstate_t*m, params_t*params, int flags) +static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0) { - if(m->inner) - new_variable("this", 0, 0); - else if(!m->is_global) - new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0); - else - new_variable("globalscope", 0, 0); + if(var0) { + int index = -1; + if(m->inner) + index = new_variable("this", 0, 0); + else if(!m->is_global) + index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0); + else + index = new_variable("globalscope", 0, 0); + if(index) + *(int*)0=0; + parserassert(!index); + } if(params) { param_list_t*p=0; @@ -846,9 +863,9 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo state->method = state->cls->init; parserassert(state->cls && state->cls->info); - - function_initvars(state->cls->init, 0, 0); - function_initvars(state->cls->static_init, 0, 0); + + function_initvars(state->cls->init, 0, 0, 1); + function_initvars(state->cls->static_init, 0, 0, 0); if(extends && (extends->flags & FLAG_FINAL)) syntaxerror("Can't extend final class '%s'", extends->name); @@ -1011,7 +1028,7 @@ static void check_constant_against_type(classinfo_t*t, constant_t*c) || c->type == CONSTANT_UINT); } else if(TYPE_IS_UINT(t)) { xassert(c->type == CONSTANT_UINT || - (c->type == CONSTANT_INT && c->i>0)); + (c->type == CONSTANT_INT && c->i>=0)); } else if(TYPE_IS_INT(t)) { xassert(c->type == CONSTANT_INT); } else if(TYPE_IS_BOOLEAN(t)) { @@ -1113,9 +1130,7 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type) methodstate_t*parent_method = state->method; if(as3_pass==1) { - // not valid yet - params = 0; - return_type = 0; + return_type = 0; // not valid in pass 1 } new_state(); @@ -1137,14 +1152,17 @@ static void innerfunction(char*name, params_t*params, classinfo_t*return_type) list_append(parent_method->innerfunctions, state->method); dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method); + + function_initvars(state->method, params, 0, 1); } if(as3_pass == 2) { state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount); + state->method->variable_count = 0; parserassert(state->method); state->method->info->return_type = return_type; - function_initvars(state->method, params, 0); + function_initvars(state->method, params, 0, 1); } } @@ -1171,14 +1189,17 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n return_type = 0; state->method->info = registerfunction(getset, flags, name, params, return_type, 0); + + function_initvars(state->method, params, flags, 1); dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method); } if(as3_pass == 2) { state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount); + state->method->variable_count = 0; parserassert(state->method); - + if(state->cls) { memberinfo_t*m = registry_findmember(state->cls->info, name, 2); check_override(m, flags); @@ -1189,7 +1210,7 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n } state->method->info->return_type = return_type; - function_initvars(state->method, params, flags); + function_initvars(state->method, params, flags, 1); } } @@ -1197,71 +1218,107 @@ static abc_method_t* endfunction(token_t*ns, int flags, enum yytokentype getset, params_t*params, classinfo_t*return_type, code_t*body) { if(as3_pass==1) { + // store inner methods in variables + function_initvars(state->method, 0, 0, 0); + + methodstate_list_t*ml = state->method->innerfunctions; + while(ml) { + methodstate_t*m = ml->methodstate; + parserassert(m->inner); + if(m->unresolved_variables) { + dict_t*d = m->unresolved_variables; + int t; + for(t=0;thashsize;t++) { + dictentry_t*l = d->slots[t]; + while(l) { + /* check parent method's variables */ + if(find_variable(state, l->key)) { + m->uses_parent_function = 1; + break; + } + l = l->next; + } + if(l) break; + } + + dict_destroy(m->unresolved_variables); + m->unresolved_variables = 0; + } + ml = ml->next; + } old_state(); return 0; } - abc_method_t*f = 0; + if(as3_pass==2) { + if(state->method->uses_parent_function){ + syntaxerror("accessing variables of parent function from inner functions not supported yet"); + } - multiname_t*type2 = sig2mname(return_type); - int slot = 0; - if(state->method->inner) { - f = state->method->abc; - abc_method_init(f, global->file, type2, 1); - } else if(state->method->is_constructor) { - f = abc_class_getconstructor(state->cls->abc, type2); - } else if(!state->method->is_global) { - namespace_t mname_ns = {state->method->info->access, ""}; - multiname_t mname = {QNAME, &mname_ns, 0, name}; + abc_method_t*f = 0; + + multiname_t*type2 = sig2mname(return_type); + int slot = 0; + if(state->method->inner) { + f = state->method->abc; + abc_method_init(f, global->file, type2, 1); + } else if(state->method->is_constructor) { + f = abc_class_getconstructor(state->cls->abc, type2); + } else if(!state->method->is_global) { + namespace_t mname_ns = {state->method->info->access, ""}; + multiname_t mname = {QNAME, &mname_ns, 0, name}; + + if(flags&FLAG_STATIC) + f = abc_class_staticmethod(state->cls->abc, type2, &mname); + else + f = abc_class_method(state->cls->abc, type2, &mname); + slot = f->trait->slot_id; + } else { + namespace_t mname_ns = {state->method->info->access, state->package}; + multiname_t mname = {QNAME, &mname_ns, 0, name}; - if(flags&FLAG_STATIC) - f = abc_class_staticmethod(state->cls->abc, type2, &mname); - else - f = abc_class_method(state->cls->abc, type2, &mname); - slot = f->trait->slot_id; - } else { - namespace_t mname_ns = {state->method->info->access, state->package}; - multiname_t mname = {QNAME, &mname_ns, 0, name}; - - f = abc_method_new(global->file, type2, 1); - trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f); - //abc_code_t*c = global->init->method->body->code; - } - //flash doesn't seem to allow us to access function slots - //state->method->info->slot = slot; - - if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE; - if(getset == KW_GET) f->trait->kind = TRAIT_GETTER; - if(getset == KW_SET) f->trait->kind = TRAIT_SETTER; - if(params->varargs) f->flags |= METHOD_NEED_REST; - - char opt=0; - param_list_t*p=0; - for(p=params->list;p;p=p->next) { - if(params->varargs && !p->next) { - break; //varargs: omit last parameter in function signature + f = abc_method_new(global->file, type2, 1); + trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f); + //abc_code_t*c = global->init->method->body->code; } - multiname_t*m = sig2mname(p->param->type); - list_append(f->parameters, m); - if(p->param->value) { - check_constant_against_type(p->param->type, p->param->value); - opt=1;list_append(f->optional_parameters, p->param->value); - } else if(opt) { - syntaxerror("non-optional parameter not allowed after optional parameters"); + //flash doesn't seem to allow us to access function slots + //state->method->info->slot = slot; + + if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE; + if(getset == KW_GET) f->trait->kind = TRAIT_GETTER; + if(getset == KW_SET) f->trait->kind = TRAIT_SETTER; + if(params->varargs) f->flags |= METHOD_NEED_REST; + + char opt=0; + param_list_t*p=0; + for(p=params->list;p;p=p->next) { + if(params->varargs && !p->next) { + break; //varargs: omit last parameter in function signature + } + multiname_t*m = sig2mname(p->param->type); + list_append(f->parameters, m); + if(p->param->value) { + check_constant_against_type(p->param->type, p->param->value); + opt=1;list_append(f->optional_parameters, p->param->value); + } else if(opt) { + syntaxerror("non-optional parameter not allowed after optional parameters"); + } + } + check_code_for_break(body); + + if(f->body) { + f->body->code = body; + f->body->exceptions = state->method->exceptions; + } else { //interface + if(body) + syntaxerror("interface methods can't have a method body"); } - } - check_code_for_break(body); - if(f->body) { - f->body->code = body; - f->body->exceptions = state->method->exceptions; - } else { //interface - if(body) - syntaxerror("interface methods can't have a method body"); + old_state(); + return f; } - - old_state(); - return f; + + return 0; } char is_subtype_of(classinfo_t*type, classinfo_t*supertype) @@ -1363,8 +1420,11 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to) return c; if(TYPE_IS_NULL(from) && !IS_NUMBER_OR_INT(to)) return c; - syntaxerror("can't convert type %s to %s", from->name, to->name); - return 0; // make gcc happy + + as3_error("can't convert type %s%s%s to %s%s%s", + from->package, from->package?".":"", from->name, + to->package, to->package?".":"", to->name); + return c; } code_t*defaultvalue(code_t*c, classinfo_t*type) @@ -1830,14 +1890,17 @@ VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);} ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION { +PASS12 if(variable_exists($1)) syntaxerror("Variable %s already defined", $1); +PASS1 + new_variable($1, $2, 1); +PASS2 if(!is_subtype_of($3.t, $2)) { syntaxerror("Can't convert %s to %s", $3.t->name, $2->name); } - int index = new_variable($1, $2, 1); if($2) { @@ -1875,7 +1938,7 @@ MAYBEELSE: %prec below_else {$$ = code_new();} MAYBEELSE: "else" CODEBLOCK {$$=$2;} //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;} -IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE { +IF : "if" '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE { $$ = code_new(); $$ = code_append($$, $4.c); @@ -1891,7 +1954,7 @@ IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE { myjmp->branch = $$ = abc_nop($$); } $$ = var_block($$); - old_state(); + PASS12 old_state(); } FOR_INIT : {$$=code_new();} @@ -1899,15 +1962,19 @@ FOR_INIT : VARIABLE_DECLARATION FOR_INIT : VOIDEXPRESSION // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here? +// (I don't see any easy way to revolve this conflict otherwise, as we +// can't touch VAR_READ without upsetting the precedence about "return") FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE { + PASS12 $$=$2;new_variable($2,$3,1); } FOR_IN_INIT : T_IDENTIFIER { + PASS12 $$=$1; } -FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;} -FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;} +FOR_START : T_FOR '(' {PASS12 new_state();$$.name=$1;$$.each=0;} +FOR_START : T_FOR "each" '(' {PASS12 new_state();$$.name=$1;$$.each=1;} FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK { if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement"); @@ -1926,11 +1993,11 @@ FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK { myif->branch = out; $$ = var_block($$); - old_state(); + PASS12 old_state(); } FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK { - variable_t*var = find_variable($2); + variable_t*var = find_variable(state, $2); char*tmp1name = concat2($2, "__tmp1__"); int it = new_variable(tmp1name, TYPE_INT, 0); char*tmp2name = concat2($2, "__array__"); @@ -1966,13 +2033,14 @@ FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK { myif->branch = out; $$ = var_block($$); - old_state(); free(tmp1name); free(tmp2name); + + PASS12 old_state(); } -WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK { +WHILE : T_WHILE '(' {PASS12 new_state();} EXPRESSION ')' CODEBLOCK { $$ = code_new(); @@ -1988,10 +2056,10 @@ WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK { continuejumpsto($$, $1, cont); $$ = var_block($$); - old_state(); + PASS12 old_state(); } -DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' { +DO_WHILE : T_DO {PASS12 new_state();} CODEBLOCK "while" '(' EXPRESSION ')' { $$ = code_new(); code_t*loopstart = $$ = abc_label($$); $$ = code_append($$, $3); @@ -2003,7 +2071,7 @@ DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' { continuejumpsto($$, $1, cont); $$ = var_block($$); - old_state(); + PASS12 old_state(); } BREAK : "break" %prec prec_none { @@ -2040,7 +2108,7 @@ CASE: "case" E ':' MAYBECODE { DEFAULT: "default" ':' MAYBECODE { $$ = $3; } -SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' { +SWITCH : T_SWITCH '(' {PASS12 new_state();} E ')' '{' MAYBE_CASE_LIST '}' { $$=$4.c; $$ = code_append($$, $7); code_t*out = $$ = abc_pop($$); @@ -2064,12 +2132,12 @@ SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' { } $$ = var_block($$); - old_state(); + PASS12 old_state(); } /* ------------ try / catch /finally ---------------- */ -CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);} +CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {PASS12 new_state();state->exception_name=$3;new_variable($3, $4, 0);} '{' MAYBECODE '}' { namespace_t name_ns = {ACCESS_PACKAGE, ""}; multiname_t name = {QNAME, &name_ns, 0, $3}; @@ -2080,20 +2148,19 @@ CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name $$ = e; code_t*c = 0; - int i = find_variable_safe($3)->index; + int i = find_variable_safe(state, $3)->index; e->target = c = abc_nop(0); c = abc_setlocal(c, i); c = code_append(c, $8); c = abc_kill(c, i); c = var_block(c); - old_state(); + PASS12 old_state(); } -FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' { +FINALLY: "finally" '{' {PASS12 new_state();state->exception_name=0;} MAYBECODE '}' { $4 = var_block($4); if(!$4) { $$=0; - old_state(); } else { NEW(abc_exception_t, e) e->exc_type = 0; //all exceptions @@ -2101,9 +2168,9 @@ FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' { e->target = 0; e->to = abc_nop(0); e->to = code_append(e->to, $4); - old_state(); $$ = e; } + PASS12 old_state(); } CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);} @@ -2126,7 +2193,7 @@ CATCH_FINALLY_LIST: FINALLY { } } -TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST { +TRY : "try" '{' {PASS12 new_state();} MAYBECODE '}' CATCH_FINALLY_LIST { code_t*out = abc_nop(0); code_t*start = abc_nop(0); @@ -2166,7 +2233,7 @@ TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST { list_concat(state->method->exceptions, $6.l); $$ = var_block($$); - old_state(); + PASS12 old_state(); } /* ------------ throw ------------------------------- */ @@ -2178,7 +2245,7 @@ THROW : "throw" EXPRESSION { THROW : "throw" %prec prec_none { if(!state->exception_name) syntaxerror("re-throw only possible within a catch block"); - variable_t*v = find_variable(state->exception_name); + variable_t*v = find_variable(state, state->exception_name); $$=code_new(); $$=abc_getlocal($$, v->index); $$=abc_throw($$); @@ -2207,8 +2274,9 @@ PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");} MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;} IMPORT : "import" PACKAGEANDCLASS { - PASS1 - if(!registry_find($2->package, $2->name)) { + PASS12 + slotinfo_t*s = registry_find($2->package, $2->name); + if(!s) {// || !(s->flags&FLAG_BUILTIN)) { as3_schedule_class($2->package, $2->name); } @@ -2221,7 +2289,7 @@ IMPORT : "import" PACKAGEANDCLASS { $$=0; } IMPORT : "import" PACKAGE '.' '*' { - PASS1 + PASS12 if(strncmp("flash.", $2, 6)) { as3_schedule_package($2); } @@ -2443,19 +2511,19 @@ PARAM_LIST: PARAM { } PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT { - PASS1 $$=0; - PASS2 - $$ = malloc(sizeof(param_t)); + PASS12 + $$ = rfx_calloc(sizeof(param_t)); $$->name=$1; $$->type = $3; + PASS2 $$->value = $4; } PARAM: T_IDENTIFIER MAYBESTATICCONSTANT { - PASS1 $$=0; - PASS2 - $$ = malloc(sizeof(param_t)); + PASS12 + $$ = rfx_calloc(sizeof(param_t)); $$->name=$1; $$->type = TYPE_ANY; + PASS2 $$->value = $2; } GETSET : "get" {$$=$1;} @@ -2465,7 +2533,8 @@ GETSET : "get" {$$=$1;} FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}' { - PASS1 old_state();list_deep_free($6.list); + PASS1 + endfunction(0,$1,$3,$4,&$6,0,0); PASS2 if(!state->method->info) syntaxerror("internal error"); @@ -2473,6 +2542,7 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P c = wrap_function(c, 0, $11); endfunction(0,$1,$3,$4,&$6,$8,c); + PASS12 list_deep_free($6.list); $$=0; } @@ -2482,7 +2552,8 @@ MAYBE_IDENTIFIER: {PASS12 $$=0;} INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}' { - PASS1 old_state();list_deep_free($4.list); + PASS1 + endfunction(0,0,0,$2,&$4,0,0); PASS2 methodinfo_t*f = state->method->info; if(!f || !f->kind) syntaxerror("internal error"); @@ -2492,10 +2563,11 @@ INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE int index = state->method->var_index; endfunction(0,0,0,$2,&$4,$6,c); - list_deep_free($4.list); $$.c = abc_getlocal(0, index); $$.t = TYPE_FUNCTION(f); + + PASS12 list_deep_free($4.list); } @@ -2504,9 +2576,8 @@ INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE CLASS: T_IDENTIFIER { PASS1 $$=0; PASS2 - /* try current package */ slotinfo_t*s = find_class($1); - if(!s) syntaxerror("Could not find class/method %s\n", $1); + if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package); $$ = (classinfo_t*)s; } @@ -3255,6 +3326,19 @@ E : E '.' T_IDENTIFIER } VAR_READ : T_IDENTIFIER { + PASS1 + /* Queue unresolved identifiers for checking against the parent + function's variables. + We consider everything which is not a local variable "unresolved". + This encompasses class names, members of the surrounding class + etc. which *correct* because local variables of the parent function + would shadow those. + */ + if(state->method->inner && !find_variable(state, $1)) { + unknown_variable($1); + } + PASS2 + $$.t = 0; $$.c = 0; slotinfo_t*a = 0; @@ -3262,7 +3346,7 @@ VAR_READ : T_IDENTIFIER { variable_t*v; /* look at variables */ - if((v = find_variable($1))) { + if((v = find_variable(state, $1))) { // $1 is a local variable $$.c = abc_getlocal($$.c, v->index); $$.t = v->type;