is there a way to count classes?

i’m wanting some project stats, and getting a list of all classes would be of great value. offhand i don’t see how to do it. ideas? thanks!

@RonJeffries Would something like this help. If not I might have something else.

viewer.mode=FULLSCREEN

function setup()    
    project="Examples:Cargo-Bot"
    lst=listProjectTabs(project)
    for a,b in pairs(lst) do
        str=readProjectTab(project..":"..b)
    end 
    font("Courier")
    textMode(CORNER)
    dy=0
    tab={}   
    r=listProjectTabs(project)
    for a,b in pairs(r) do
        str=readProjectTab(project..":"..b)
        table.insert(tab,"\
")
        table.insert(tab,"\
")
        table.insert(tab,project.." : "..b)
        b1=1
        s=1
        comment=false
        startComment=false
        while true do
            s,e=string.find(str,"\
",s)
            if s==nil then
                break
            end
            s=e+1                        
            str1=string.sub(str,b1,e)   
                     
            sc1,ec1=string.find(str1,"%-%-%[%[")  
            if sc1 ~= nil then
                startComment=true
            end            
            --sc2,ec21=string.find(str1,"%-%-%]%]")  
            sc2,ec21=string.find(str1,"%]%]")  
            if sc2 ~= nil then
                startComment=false
            end  
                      
            comment=false
            sc3,ec3=string.find(str1,"%-%-")            
            if sc3 ~= nil then
                comment=true
                sc4,ec4=string.find(str1,"class")
                if sc4~=nil and sc4<sc3 then
                    comment=false
                end
                sc5,ec5=string.find(str1,"function")
                if sc5~=nil and sc5<sc3 then
                    comment=false
                end
            end  
                  
            process=true
            if comment or startComment then
                process=false
            end 
            
            if process then
                s1,e1=string.find(str1,"class")
                if s1~=nil then
                    s2,e2=string.find(str1,")")
                    if s2~= nil then
                        str1=removeSpaces(string.sub(str1,1,e2))                            
                        table.insert(tab,"    "..str1)
                        b1=e2+1
                    end
                    else
                    s2,e2=string.find(str1,"function ")
                    if s2~=nil then
                        s3,e3=string.find(str1,")")
                        if s3~= nil then
                            table.insert(tab,"        "..string.sub(str1,s2,e3))
                            b1=e3+1
                        end
                    end
                end
                if s==nil then
                    break
                end
            end
            if e~=nil then
                b1=e+1
            end
        end
    end
    table.insert(tab,"\
")
    table.insert(tab,"\
")
    table.insert(tab,"END of "..project)
end

function removeSpaces(s)
    for z=1,#s do
        if string.sub(s,z,z)~=" " then
            return(string.sub(s,z))
        end
    end
end

function draw()
    background(40, 40, 50)
    fill(255)
    for a,b in pairs(tab) do
        text(b,100,HEIGHT-a*20+dy)
    end
end

function touched(t)
    if t.state==BEGAN or t.state==MOVING then
        dy=dy+t.deltaY
        if dy<0 then
            dy=0
        end
    end
end

that’s quite nice!

yes, i was thinking i can search for “class()”, etc. was hoping for something less fragile, in runtime memory, but maybe source analysis is better. thanks!

you’re right on find, i removed the discussion :smile:

@dave1707 at the top of that program there is a loop reading tabs. Is there a purpose for that, or is it a leftover? Thanks!

@RonJeffries The listProjectTab and readProjectTab code at the very beginning isn’t needed. Those are probably leftover from when I started.

yes, thought so. today’s article is about your prog, check it out. let me know if i said anything bad.

@RonJeffries I like the article. Interesting to see how someone else would redo my code. Generally when I write something, I write something small to get it to work and then start expanding it until it does what I want. I never wrote any class code until I started playing with Codea. At work when I switched from C to C++, I was totally lost as to why anyone would want to use classes. I had newly hired programmers who learned C++ as their only language try to explain the purpose of classes to me, but for some reason it didn’t make sense. I now know the purpose, but still don’t use it that often.

Here’s the companion program to the first one. It displays two columns on the screen. The left column shows “Classes defined within “. The right column shows “Instances created within ”. The titles are at the top of each column. Not sure if this is anymore useful or useless than the first. It was just something to write when I couldn’t think of anything else to do.

-- find classes and instances of those classes

function setup()
    parameter.action("list projects",listProj)
    parameter.text("project")
    parameter.action("search",srch)
    sTab={}
    dy=-80
    listProj()
end

function listProj()
    project=""
    sTab={}
    output.clear()
    tab=listProjects()
    for a,b in pairs(tab) do
        print(b)
    end
end

function srch()
    s,e=string.find(project,"\
")
    if s~=nil then
        project=string.sub(project,1,s-1)
    end
    textMode(CORNER)
    sTab={}
    iTab={}
    cls={}
    tab={}
    ins={}
    print("Find classes")
    findClasses()    
    for a,b in pairs(cls) do
        print("Find instances in "..b)
        findInstances("="..b.."(")
    end
    table.sort(sTab)
    viewer.mode=FULLSCREEN
    output.clear()
end

function draw()
    background(40, 40, 50)
    fill(255)
    
    if #sTab>0 then
        text("Classes defined within < tabs >",50,HEIGHT+50+dy)
        text("Instances created within < tabs >",WIDTH/2,HEIGHT+50+dy)
        text(project,300,HEIGHT+20+dy)
            
        cnt=0
        for _,a in pairs(sTab) do
            b=tab[a]
            cnt=cnt+1
            text("< "..a.." >",50,HEIGHT-cnt*20+dy)
            for c,d in pairs(b) do
                cnt=cnt+1
                text(d,50,HEIGHT-cnt*20+dy)
            end
            cnt=cnt+2
        end

        cnt=0
        for _,a in pairs(sTab) do
            b=iTab[a]
            if b~=nil and #iTab[a]>0 then
                cnt=cnt+1
                text("< "..a.." >",WIDTH/2,HEIGHT-cnt*20+dy)
                for c,d in pairs(b) do
                    cnt=cnt+1
                    text(d,WIDTH/2+20,HEIGHT-cnt*20+dy)
                end
                cnt=cnt+2
            end
        end 
    end   
end

function touched(t)
    if t.state==BEGAN or t.state==MOVING then
        dy=dy+t.deltaY
        if dy<-80 then
            dy=-80
        end
    end
end

function findClasses()
    local r=listProjectTabs(project)
    for a,b in pairs(r) do
        local str=readProjectTab(project..":"..b)
        table.insert(tab,b)
        tab[b]={}
        table.insert(sTab,b)
        local b1=1
        local s,e=1,0
        while true do
            s,e=string.find(str,"\
",s)
            if s==nil then
                break
            end
            local str1=leaveSpaces(0,string.sub(str,b1,e+1))
            local s1,e1=string.find(str1,"=class(",1,true)
            if s1~=nil then
                table.insert(tab[b],"       "..string.sub(str,b1,e-1))
                local s2,e2=string.find(str1,"=")
                if s2~=nil then
                    table.insert(cls,string.sub(str1,1,e2-1))
                end                
            end
            b1=e+1
            s=b1
        end
    end
end

function findInstances(class)
    local r=listProjectTabs(project)
    for a,b in pairs(r) do
        local str=readProjectTab(project..":"..b)
        if iTab[b]==nil then
            iTab[b]={}
        end
        local b1=1
        local s,e=1,0
        while true do
            s,e=string.find(str,"\
",s)
            if s==nil then
                break
            end
            local str1=string.sub(str,b1,e+1)
            local str2=leaveSpaces(0,str1)
            local s1,e1=string.find(str2,class,1,true)
            if s1~=nil then 
                local s2,e2=string.find(str1,"(",1,true)
                table.insert(iTab[b],leaveSpaces(1,string.sub(str1,1,e2-1)))
            end
            b1=e+1
            s=b1
        end
    end
end

function leaveSpaces(nbr,str)   -- nbr spaces between words in str (0 or 1)
    local str1=""
    local sp=0
    for z=1,#str do
        local c=string.sub(str,z,z)
        if c~=" " then
            sp=0
            str1=str1..c
        elseif sp<nbr then
            sp=sp+1
            str1=str1..c
        end
    end
    return str1
end

cool, i’ll check it out right now!

interesting trick with leaveSpaces(0). Evil, but works. i’d have done that the hard way, i think.

@RonJeffries Enjoying your article. Nice having someone pointing out my sloppy coding which I do mostly by choice. I hate coming up with long variable names, hence my 1 or 2 character names. One thing I’d like you to mention in your writings so that everyone reading them don’t think that I’m such a terrible coder, is that I write all of my code while I’m watching TV. There’s no pre-planning for my programs and most of the time no planning in what I’m actually writing. That’s why you’ll sometimes find code that doesn’t need to be there. It was something I was trying and forgot to remove it. If it works, it goes in the code. A comment on TV will remind me of something or if I see someone make a comment on the forum, I’ll think that might be an interesting program and start writing. Anyways, I’m interested to see how well you’ll condense my code and make it more readable and understandable.

i’ll do that. it’s not bad code, as i’ve tried to say a couple of times. just not to my liking. :smile:

@RonJeffries I didn’t mean to say that you think my code is bad. Well, it is bad from a readability point of view. My meaningless variable names, and everything packed into large function. Half the time when I look a my code I don’t know what’s happening. It takes awhile to figure it out. We have different coding styles and I like yours better than mine. I write quick code, so I don’t plan it very well. I just write it to get the job done with no plans to expand on it at a later time. Interested to see how your version turns out.

@RonJeffries Liked your latest article. I also like the approach you did about removing the comments from the code before parsing thru it. The only problem is the multi line comment can take on various forms. See the example below. If there are nested multi line comments, a matching number of = can be placed between the beginning and ending square brackets. Not sure what the max number of = are. The line that would kill a normal multi line comment would be something like
a=b[c[d]] . The = in [[ works to ignore that and other multi line comments.

function setup()
    --[=[
    print("aaa")
    b={2,4,6,8}
    c={1,2,3}
    d=2
    --[[
    print("comment 1")
    print("comment 2")
    --]]
    a=b[c[d]]
    print("a",a)
    print("yy")    
    --]=]
end

yes. i should have mentioned that i’m consciously ignoring some cases of the multi-line thing. i don’t recall, does your original deal with those properly?

@RonJeffries My original code doesn’t deal with them. I never used the = sign with the multi line comment, so I didn’t look for it. My programs don’t usually cover all possibilities of problems, I just get them to work on normal things. A lot of my code is never seen except by me so I just code for what I need.

yes, i feel much the same, esp with tools like these

@RonJeffries Just finished reading your latest article. Two things I’d like to mention.

The first is with the multi line comments with the = signs. I don’t know how many people will nest comments, but my immediate use is trying to comment out a function that contains a line of code similar to a = b[c[d]] or something that has ]] . The ]] will mess up the multi line comment. By using the = sign in the multi line comment, you can successfully comment out a function containing that line of code.

The second has to do with my second program. When I list all the projects in the print area, if you tap on one of the project names, you’ll notice that it’s background will darken more. Then if you long press in the parameter Project text area, you’ll get a paste option. Tapping paste, that project name will be copied there. Then you’ll have to press backspace to get rid of the new line character so the project name is just one line. So you don’t have to type the name there.

Just so you know, I have a bookmark to your articles. Every now and then I just pop in and read some of what you’re doing.

yes … i haven’t needed the nested comments but i am confident the program handles them correctly now. i hadn’t thought of the copy paste but makes sense. i’m glad you check out the articles and hope you find them amusing if not valuable :wink: