WheretIB / nullc

Fast C-like programming language with advanced features
MIT License
162 stars 12 forks source link

How are scopes chained in `nullc` ? #30

Open mingodad opened 2 years ago

mingodad commented 2 years ago

I'm trying to add a compiler warning for shadowed variables but I'm having trouble understand scopes in nullc, I started by copying and changing Report(ExpressionContext &ctx, SynBase *source, const char *msg, ...) then changed bool CheckVariableConflict(ExpressionContext &ctx, SynBase *source, InplaceStr name) to issue the warning then I'm getting this warnings when running nullc:

WARNING: name 'x' is already taken for a variable in outer scope
WARNING: name 'y' is already taken for a variable in outer scope
WARNING: name 'x' is already taken for a variable in outer scope
WARNING: name 'y' is already taken for a variable in outer scope
WARNING: name 'z' is already taken for a variable in outer scope
WARNING: name 'x' is already taken for a variable in outer scope
WARNING: name 'y' is already taken for a variable in outer scope
WARNING: name 'z' is already taken for a variable in outer scope
WARNING: name 'w' is already taken for a variable in outer scope
WARNING: name 'node' is already taken for a variable in outer scope
WARNING: name 'node' is already taken for a variable in outer scope
WARNING: name 'node' is already taken for a variable in outer scope
WARNING: name 'node' is already taken for a variable in outer scope
WARNING: name 'node' is already taken for a variable in outer scope
WARNING: name 'node' is already taken for a variable in outer scope

I understand that I need to search for the symbol name in outer scopes to decide to show the warning.

How are scopes chained in nullc ?

    NULLC_PRINT_FORMAT_CHECK(3, 4) void Warning(ExpressionContext &ctx, SynBase *source, const char *msg, ...)
    {
        va_list args;
        va_start(args, msg);

                vprintf(msg, args);
                //ReportAt(ctx, source, source->pos.begin, msg, args);

        va_end(args);
    }
    bool CheckVariableConflict(ExpressionContext &ctx, SynBase *source, InplaceStr name)
    {
        if(LookupTypeByName(ctx, name.hash()))
        {
            Report(ctx, source, "ERROR: name '%.*s' is already taken for a type", FMT_ISTR(name));
            return true;
        }

        if(IdentifierLookupResult *lookup = LookupObjectByName(ctx, name.hash()))
        {
            if(lookup->variable)
            {
                            if(lookup->variable->scope == ctx.scope) {
                Report(ctx, source, "ERROR: name '%.*s' is already taken for a variable in current scope", FMT_ISTR(name));
                return true;
                            }
                            else {
                Warning(ctx, source, "WARNING: name '%.*s' is already taken for a variable in outer scope\n", FMT_ISTR(name));
                            }
            }

            if(lookup->function && lookup->function->scope == ctx.scope)
            {
                Report(ctx, source, "ERROR: name '%.*s' is already taken for a function", FMT_ISTR(name));
            }
        }

        if(FindNamespaceInCurrentScope(ctx, name))
        {
            Report(ctx, source, "ERROR: name '%.*s' is already taken for a namespace", FMT_ISTR(name));
            return true;
        }

        return false;
    }