Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

List Variables

in General Posts: 20

Does anyone know a way of listing all the variables used in a program by tab or class, I thought I had seen something on the forum previously but I cannot find. I try and use variable names that are memorable, but when you come back to complete a project after a few weeks, I tend to lose track of what variable names I have used.

Tagged:

Comments

  • dave1707dave1707 Mod
    edited October 26 Posts: 9,725

    @timber This might be close enough to what you’re after. Key in the project name and press go. You can include comments using the slider.

    Project updated below
    
  • dave1707dave1707 Mod
    edited October 26 Posts: 9,725

    Here’s an updated version. It shows a list of all projects. You can tap on a project name and that will fill in the parameter project name. Then press Process for a list of names in that project. To view another, tap List of projects and select another name.

    Updated code below
    
  • dave1707dave1707 Mod
    edited October 26 Posts: 9,725

    Updated version. Tap a project name and it will list the names. Tap again for another project.

    -- code viewer
    
    viewer.mode=STANDARD
    
    function setup()
        pasteboard.copy("")
        project=""
        textMode(CORNER)
        font("Courier")
        parameter.boolean("Include_Comments",false,setup1)
        list()
    end
    
    function setup1()
        tab,tab1={},{}
        dy,per=0,0
        comment=false
        longComment=false
        process()
    end
    
    function draw()
        background(40,40,50)
        fill(255)
        if pasteboard.text~="" then
            project=pasteboard.text
            pasteboard.copy("")
            setup1()
        end
        if lp==nil then
            return
        end
        if #lp==0 then
            text("Project not found...  "..project,50,HEIGHT/2)
            return
        end
        if dy==0 then
            text(project,30,HEIGHT-30)
            text("Nbr    Count    Name            Entries  "..#tab1,30,HEIGHT-70)
            text("Scroll up/down",WIDTH/2+80,HEIGHT-30)
        end
        for a,b in pairs(tab1) do
            text(string.format("%5d   %5d      %-s",a,tab[b],b),2,HEIGHT-80-a*20+dy)
        end
    end
    
    function touched(t)
        if t.state==CHANGED then
            dy=dy+t.deltaY
            if dy<0 then
                dy=0
            end
        end
    end
    
    function list()
        output.clear()
        temp=listProjects()
        for a,b in pairs(temp) do
            print(b)
        end
        pasteboard.copy("")
    end
    
    function process()
        str=""
        project=string.gsub(project,"\n","")
        lp=listProjectTabs(project)
        if #lp==0 then        
            return
        end
        for a,b in pairs(lp) do
            local rp=readProjectTab(project..":"..b)
            str=str..rp
        end
        str1=""
        proc()
    end
    
    function get4bytes(z)
        v=string.sub(str,z,z)
        v1=string.sub(str,z+1,z+1)
        v2=string.sub(str,z+2,z+2)
        v3=string.sub(str,z+3,z+3)
    end
    
    function checkComments()
        if v=="\n" then
            comment=false
        end
        if v=="-" and v1=="-" and v2=="[" and v3=="[" then
            longComment=true
        elseif longComment and v=="-" and v1=="-" and v2=="]" and v3=="]" then
            longComment=false
        elseif v=="-" and v1=="-" then
            comment=true
        end
        if Include_Comments then
            comment,longComment=false,false
        end
    end
    
    function proc()
        for z=1,string.len(str) do
            get4bytes(z)
            checkComments()
            if comment or longComment then
                -- ignore until end of comment 
            else
                proc1()
            end
        end
        proc2()
    end
    
    function proc1()
        if v>="a" and v<="z" or v>="A" and v<="Z" then
            per=0
            str1=str1..v
        elseif v>="0" and v<="9" then
            per=0
            str1=str1..v
        elseif str1~="" and v=="_" then
            per=0
            str1=str1..v
        elseif str1~="" and v=="'" then
            per=0
            str1=str1..v
        elseif str1~="" and v=="." then
            per=per+1
            if per==2 then
                per=0
                str1=string.sub(str1,1,string.len(str1)-1)
                if tab[str1]==nil then
                    tab[str1]=1
                else
                    tab[str1]=tab[str1]+1
                end
                str1=""
            else
                str1=str1..v
            end
        elseif str1~="" then
            per=0
            local len=string.len(str1)
            if string.sub(str1,len,len)=="." then
                str1=string.sub(str1,1,len-1)
            end
            if string.sub(str1,len,len)=="'" then
                str1=string.sub(str1,1,len-1) 
            end 
            if tab[str1]==nil then
                tab[str1]=1
            else
                tab[str1]=tab[str1]+1
            end
            str1=""
        else
            str1=""
        end
    end
    
    function proc2()
        for a,b in pairs(tab) do
            table.insert(tab1,a)
        end
        table.sort(tab1)
    end
    
  • Posts: 20

    @dave1707 thank you, this will be a good starting point. I’ve not studied the code closely, but it looks like you create a list of tabs that make up the selected project and iterate through them. If that is the case, I could theoretically add another parameter to select only the tab I wanted to interrogate. I.e Select project -> Select tab -> Process. The reason for this would be to differentiate between variables with the same name but in different classes.

  • Posts: 1,275

    I think this might be better done with string patterns, but "if it works do it".

  • dave1707dave1707 Mod
    Posts: 9,725

    @RonJeffries Just curious, how would string patterns work.

  • dave1707dave1707 Mod
    Posts: 9,725

    Here’s a version that gives the counts by tab name.

    -- code viewer, breakdown by tabs
    
    viewer.mode=STANDARD
    
    function setup()
        pasteboard.copy("")
        project=""
        textMode(CORNER)
        font("Courier")
        parameter.boolean("Include_Comments",false,setup1)
        list()
    end
    
    function setup1()
        tab,tab1,tab2={},{},{}
        dy,per=0,0
        comment=false
        longComment=false
        process()
    end
    
    function draw()
        background(40,40,50)
        fill(255)
        if pasteboard.text~="" then
            project=pasteboard.text
            pasteboard.copy("")
            setup1()
        end
        if lp==nil then
            return
        end
        if #lp==0 then
            text("Project not found...  "..project,50,HEIGHT/2)
            return
        end
        if dy==0 then
            text(project,30,HEIGHT-30)
            text("Nbr    Count    Name    < tab >",30,HEIGHT-70)
            text("Entries  "..#tab1,WIDTH-200,HEIGHT-70)
            text("Scroll up/down",WIDTH-200,HEIGHT-30)
        end
        for a,b in pairs(tab2) do
            st,en=string.find(b,"#*",1,true)
            str=string.sub(b,en+1)
            text(string.format("%5d   %-s",a,str),2,HEIGHT-80-a*20+dy)
        end
    end
    
    function touched(t)
        if t.state==CHANGED then
            dy=dy+t.deltaY
            if dy<0 then
                dy=0
            end
        end
    end
    
    function list()
        output.clear()
        temp=listProjects()
        for a,b in pairs(temp) do
            print(b)
        end
        pasteboard.copy("")
    end
    
    function process()
        str=""
        project=string.gsub(project,"\n","")
        lp=listProjectTabs(project)
        if #lp==0 then        
            return
        end
        for a,b in pairs(lp) do
            str=""
            tabName=b
            local rp=readProjectTab(project..":"..b)
            str=str..rp
            str1=""
            proc()
        end
        table.sort(tab2)
    end
    
    function get4bytes(z)
        v=string.sub(str,z,z)
        v1=string.sub(str,z+1,z+1)
        v2=string.sub(str,z+2,z+2)
        v3=string.sub(str,z+3,z+3)
    end
    
    function checkComments()
        if v=="\n" then
            comment=false
        end
        if v=="-" and v1=="-" and v2=="[" and v3=="[" then
            longComment=true
        elseif longComment and v=="-" and v1=="-" and v2=="]" and v3=="]" then
            longComment=false
        elseif v=="-" and v1=="-" then
            comment=true
        end
        if Include_Comments then
            comment,longComment=false,false
        end
    end
    
    function proc()
        for z=1,string.len(str) do
            get4bytes(z)
            checkComments()
            if comment or longComment then
                -- ignore until end of comment 
            else
                proc1()
            end
        end
        proc2()
    end
    
    function proc1()
        if v>="a" and v<="z" or v>="A" and v<="Z" then
            per=0
            str1=str1..v
        elseif v>="0" and v<="9" then
            per=0
            str1=str1..v
        elseif str1~="" and v=="_" then
            per=0
            str1=str1..v
        elseif str1~="" and v=="'" then
            per=0
            str1=str1..v
        elseif str1~="" and v=="." then
            per=per+1
            if per==2 then
                per=0
                str1=string.sub(str1,1,string.len(str1)-1)
                if tab[str1]==nil then
                    tab[str1]=1
                else
                    tab[str1]=tab[str1]+1
                end
                str1=""
            else
                str1=str1..v
            end
        elseif str1~="" then
            per=0
            local len=string.len(str1)
            if string.sub(str1,len,len)=="." then
                str1=string.sub(str1,1,len-1)
            end
            if string.sub(str1,len,len)=="'" then
                str1=string.sub(str1,1,len-1)
            end 
            str1=str1.."     < "..tabName.." >"
            if tab[str1]==nil then
                tab[str1]=1
            else
                tab[str1]=tab[str1]+1
            end
            str1=""
        else
            str1=""
        end
    end
    
    function proc2()
        for a,b in pairs(tab) do
            table.insert(tab1,a)
        end
        createTab2()
        tab={}
    end
    
    function createTab2()
        for a,b in pairs(tab) do
            ss=string.format("%s#*%4d       %-s",a,b,a)
            table.insert(tab2,ss)
        end
    end
    
  • Posts: 1,275

    if i understand what your program does, it basically looks for a pattern of _, alpha and numbers in between punctuation and white space. so we'd express that as a pattern, something like

    [%s\+\-\*\/]*([_%a][_%w]*)[%s\+\-\*\/]
    -- not name  name             not name
    

    hideous, yes, but once we get the pattern right, tabContents:gmatch(pattern) would return all the matches.

    See my recent Codea Stats articles for examples of finding class and method definitions.

    Trouble with patters is they are hard to write and read. but when the are applicable, they are mighty.

    I might try to do this problem in an upcoming stats article. it'll be a bear!

  • dave1707dave1707 Mod
    Posts: 9,725

    @RonJeffries i do patterns sometimes, but it seems to take forever to get it right. Probably the more you use it, the easier it becomes.

  • Posts: 1,275

    if it ever gets easy, I've not done it enough. :)

  • Posts: 1,275

    here's a thing:

    -- find
    
    function setup()
        s = readProjectTab("Main")
        t = {}
        for w in string.gmatch(s, "[_%a][_%w]*") do
            table.insert(t,w)
        end
        table.sort(t)
        w = ""
        for _,word in ipairs(t) do
            if word~= w then print(word) end
            w = word
        end
    end
    
  • dave1707dave1707 Mod
    Posts: 9,725

    @RonJeffries That’s a start. If I add a=1234, it doesn’t find the 1234. Also, it splits up the commands that have a . in them (ie table.sort). There would probably have to be multiple gmatch commands to find each type of word, number, whatever.

  • Posts: 1,275

    why should it find 1234, that's not a variable?
    is table.sort one word? i'd think not ...
    i think i'd winnow out dups, then remove all the keywords.
    and of course remove comments, which is hard but doable i think.

  • dave1707dave1707 Mod
    Posts: 9,725

    @RonJeffries Here’s a modification. It finds the number and counts everything. My original code doesn’t look for just variables, but everything that makes up the code. I’m not sure if patterns could do everything the way I’m doing it.

    function setup()
        s = readProjectTab("Main")
        t = {}
        for w in string.gmatch(s, "[%a%d]*") do
            if t[w]==nil then
                t[w]=1
            else
                t[w]=t[w]+1
            end
        end
        a=1234
        table.sort(t)
        print("============")
        for a,b in pairs(t) do
            print(t[a].." = "..a)
        end
    end
    
  • Posts: 1,275

    misses _i, but easily fixed.

    i prefer t[w] = (t[w] or 0) + 1

    i'm not sure if patterns could do what yours does, not least because i don't know what it does. it'd have to study it to know.

    horses for courses, certainly.

  • Posts: 1,275

    i didn't know that pasteboard trick. very cool.

  • dave1707dave1707 Mod
    Posts: 9,725

    @RonJeffries My code doesn’t catch the _i, but it does catch the i . Don’t know if that’s really important or not, but probably should for clarity. I’d like to redo the way I check things and separate them so I can have a comment showing what I’m trying to catch with each if .

    The pasteboard code makes it easy to select projects from a list.

    As for the t[w]= code, for me that’s not easily understandable. It saves code, but if I looked at it some time from now, I wouldn’t know what it was really doing.

  • edited October 28 Posts: 1,275

    ah. i'm used to it. old C programmer or something. :smile:

  • Posts: 20

    @dave1707 Thanks, the added tab reference is very useful.

  • Posts: 1,275

    This code strips all --[[ comments from the input text, including things like --[===[ and such.

                local pat = "%-%-%[(=*)%[.-%]%1%]"
                local ans = text:gsub(pat,"")
    
  • dave1707dave1707 Mod
    Posts: 9,725

    @RonJeffries I’ve been trying to use patterns to replace all my if statements, but I’m having trouble with some of the combinations.

    The things I’m having trouble with are

    d=qwe..asd
    The qwe..asd should split to
    d
    qwe
    asd

    e=123..456..qwe
    Should split to
    e
    123
    456
    qwe

    f=s:get.func_qwert
    Should split to
    f
    s:get.func_qwert

    function setup()
        str="111 table.insert _q34=123.45 _73ab='asd' f:search b=51*52 c=qwert_asdfg d=qwe..asd e=123..456..qwe f=s:get.func_qwert"
        print(str)
    
        for a in string.gmatch(str,"[%d%.%d]*[%_%w]*[%a%.%a]*[%a%:%a]*") do
            if a~="" then
                print(a)
            end
        end
    end
    
  • Posts: 1,275

    you have pattern elements like [%d%.%d ]*

    what are you trying to match with those?

    i'm not sure you can go all that in one match, but i'm not clear what you want yet. reading further...

  • dave1707dave1707 Mod
    edited October 29 Posts: 9,725

    @RonJeffries The %d%.%d captures numbers that have a decimal point in them, ie 123.45 . All of those patterns work, I just can’t get the right patterns to capture everything the way I want. If you run the little program I included, it separates everything, but not quite the way I want for everything.

    My if statements in the original program does everything the way I want. I just thought I’d try using patterns. It gives me practice trying to use them.

  • edited October 29 Posts: 1,275

    Here's something that may be a bit like what you are looking for.

    note there is no pattern that will parse arbitrary lua code, so we will always have to segment somehow.

    function setup()
        str="111 table.insert _q34=123.45 _73ab='asd' f:search b=51*52 c=qwert_asdfg d=qwe..asd e=123..456..qwe f=s:get.func_qwert "
        print(str)
        --pat = "[%d%.%d]*[%_%w]*[%a%.%a]*[%a%:%a]*"
        pat = "([^%s]-)%s" -- split on space
        for a in string.gmatch(str,pat) do
            if a~="" and a:find("=") then
                pat2 = "(.*)=(.*)" -- split and capture around =
                for b,c in a:gmatch(pat2) do
                    print(b, " gets ",c)
                end
            else
                print(a, " has no =")
            end
        end
    end
    
  • Posts: 1,275

    yes, i'm not saying patterns are better ... just that i'd use them if i could. I'm sure one pattern can't do what your original code does.

  • dave1707dave1707 Mod
    Posts: 9,725

    @RonJeffries That’s kind of interesting. I ran it against an actual project and it didn’t turn out to be that beneficial. Majority was has no = .

    One pattern won’t do what I’m after, that’s why I have several different [patterns] in the “ “. But the more I add, the more they conflict with the other ones. At least I’m getting practice using them.

  • Posts: 1,275

    yes. the scheme i'm using at home is multiple specialized patterns, run sequentially. one finds class devs, another finds method devs, etc.

  • dave1707dave1707 Mod
    Posts: 9,725

    @RonJeffries Using patterns is an simple and powerful way to find things. The only problem is they’re not that easy to learn. For me it’s more of trial and error before I get what I want.

  • Posts: 1,275

    me too, though i'm getting better at guessing. often i build up the pattern bit by bit.

Sign In or Register to comment.