Murga-Projects Forums

Full Version: Interactive Fish interpreter
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I'm having trouble creating a text editor, for creating sort of an interactive editor/interpreter for the Fish language.

With Fluid, I've managed to generate the window etc, but in the textarea text can not be entered.

The code:

-- Declaration of global variables
make_window = make_window or nil
win = {}
function make_window()
  win.window = fltk:Fl_Double_Window(334, 210, 565, 355, "Fish interpreter")
    win.edt_buffer = fltk:Fl_Text_Buffer()
    win.edt = fltk:Fl_Text_Editor(25, 25, 260, 280)
    win.edt:textsize(10) -- TODO un magic number

    local o = fltk:Fl_Text_Display(285, 25, 260, 280)
    local o = fltk:Fl_Roller(135, 320, 55, 25, "Delay")
    local o = fltk:Fl_Value_Output(190, 320, 25, 25)
    local o = fltk:Fl_Button(215, 320, 70, 25, "Back")
    local o = fltk:Fl_Button(285, 320, 70, 25, "Step")
    local o = fltk:Fl_Return_Button(355, 320, 70, 25, "Run")
  return win.window

for _,i in ipairs {make_window()} do i:show() end

Any ideas how to solve this?



win.edt_buffer = fltk:Fl_Text_Buffer()
win.edt = fltk:Fl_Text_Editor(25, 25, 260, 280)

what does this do?: win.window['endd'](win.window)

mikshaw Wrote:
what does this do?: win.window['endd'](win.window)

No idea! It's just generated like that by the fluid to murgaLua converter (though as o['endd'](o)). I guess it's similar to fltk.Fl_End().

Thanks a lot,


I've been coding this interactive fish interpreter, because it's a really nice language ( I'm almost there, but I can't get the output window to redraw when using the run button (which goes into a loop calling the main coroutine). So I can't see the individual characters being printed.

Using the step button (which just resumes the coroutine once) does work.

Any Ideas? This is the code:

-- configuration --
demo=[["hello, world"r> ?o?<;]]
-- end config --

-- parsing different commands
p=z.insert    -- push
P=z.remove    -- pop
W=function(...) win.output_buffer:append(...) end
t="><^v/\\|_#x+-*,%=)(!?:~$@&r}{gponi;[].mX"        -- all tokens
"z=P(s.s)if z~=0 then p(s.s,P(s.s)/z)else error'Div by 0'end","y=P(s.s)z=P(s.s)p(s.s,z%y)", -- div
"p(s.s,P(s.s)==P(s.s) and 1 or 0)",
"p(s.s,P(s.s)>P(s.s) and 1 or 0)",
"p(s.s,P(s.s)<P(s.s) and 1 or 0)",
"if #s.s==0 or s.s[#s.s]==0 then f['!'](s) end",
"z=#s.s s.s[z],s.s[z-1]=s.s[z-1],s.s[z]",
"z=#s.s s.s[z],s.s[z-1],s.s[z-2]=s.s[z-1],s.s[z-2],s.s[z]",
"if s.r then p(s.s,s.r)s.r=nil else s.r=P(s.s)end",
"if s.s==s.l then z=s.l s.l={}s.s=s.l else z=S S={}s.s=S end for k=1,#z do s.s[#z-k+1]=z[k]end",
"z=P(s.s) p(s.s,c[P(s.s)][z])",
"z,w=P(s.s),P(s.s) c[w][P(s.s)]=z",
" if not z then p(s.s,4)else while z:match'%s'do not z then z='\\4'end end p(s.s,B(z))end",
"fltk.fl_message('Fish program quit')step=coroutine.create(function()return end) coroutine.resume(step)", --"os.exit()", -- TODO modify!
"P(T,,#T do T[k].id=k end", -- update after removing a thread.
"s.s = s.s==S and s.l or S",
"z= s.s==S and s.l or S for k=#s.s,1,-1 do p(z,P(s.s,1))end",
function dbg(s)
    print("Current Stack:",s.s==s.l and "Local Stack" or "Global Stack")
    print("Local stack:")
    for k,v in pairs(s.l) do print("",k,v,v>=0 and string.char(v) or "NEG") end
    print("Global stack:")
    for k,v in pairs(S) do print("",k,v,v>=0 and string.char(v) or "NEG") end
    print("Register: ",s.r)
    for k=0,#c do
        io.write(string.format("%0"..#tostring(#c).."i",k),": ")
        for l=0,#c[k] do

-- Linking commands to functions
for k in t:gmatch"." do -- will contain the tokens
    --TODO setfenv / setmetatable to avoid all indexing in functions.

T={        -- table of threads
    --nt = new thread to be created.
c={}    -- codebox IP wraps around
S={}    -- global stack
-- codebox layout
--     -----> +x
--  @  |line of text            -- wrap around to second line
--     |second line of text.    -- negative indices can be used for variables
--     |
--     V +Y

-- y first coord, x second
-- wrap around rows if nil row
-- wrap around cols if nil char.
function T.n(T,x,y,dx,dy) -- New thread function
    id=#T+1,                    -- keep number id
    l={},                    -- local stack
    dx=dx or 1,                    -- 1 for +x, -1 for -x, 0 for y/-y
    dy=dy or 0,                    -- 1 for +y, -1 for -y, 0 for x/-x
    x=x or 0,                    -- X of IP
    y=y or 0,                    -- Y of IP
    -- i,                    -- will contain type of quote when reading in a string
    -- r,                    -- registry
        if s.y > #c then
        elseif s.y<0 then
        if s.x>#c[s.y] and s.dx==1 then
        elseif s.x<0 then
    z.s=z.l -- current stack is local stack
    T[]=z    -- add at next index

function run()
-- compile to codebox
--fh= arg[1] and[1]) or io.stdin    -- use file or stdin
-- Todo: find a way to "lock" the editor.
while pos<=win.edt_buffer:length() do
    c[y]=M({},{__index=function()return 32 end})--default to space
    local l = win.edt_buffer:line_text(pos)
    for k=1,#l do
        local z=l:sub(k,k)
        if not i then        -- normal mode
            if F(z,"['\"]") then i=z end
            if F(z,"[^\n\r]")then --filter out only newlines
            end -- any spacing allowed.
        else                -- verbatim string mode
            if z==i then i=nil end

while #T>0 do
    for id=1,#T do --TODO make that f[q] uses the correct stacks etc.
        s:m()                                        -- move the IP
        n,o=s.dx,s.dy -- keep old directions for new thread detection
        if s.i then                        -- stringparsing mode        
            if F(q,"['\"]") then        -- end-quote
                p(s.s,c[s.y][s.x])    -- push contents of box, then advance
        else                             -- not in string parsing mode
            if F(q,"['\"]") then        -- start-quote
            elseif F(q,"%x") then        -- parsing a number
            elseif F(q,"[^ ]") then
                f[q](s)    -- call, feed with state/thread
    if T.nt and (n~=s.dx or o~=s.dy) then
        -- create new thread
        s.dx,s.dy=n,o        -- restore directions of parent

step = coroutine.create(run)

win = {}
  win.window = fltk:Fl_Double_Window(334, 210, 565, 355, "Fish interpreter")
    win.edt_buffer = fltk:Fl_Text_Buffer()
    win.edt = fltk:Fl_Text_Editor(25, 25, 260, 280)

    win.output_buffer = fltk:Fl_Text_Buffer()
    win.output = fltk:Fl_Text_Display(285, 25, 260, 280)

    win.rol = fltk:Fl_Roller(105, 320, 45, 25, "Delay")
    win.rol_output = fltk:Fl_Value_Output(160, 320, 50, 25)
    win.rol:callback(function() win.rol_output:value(win.rol:value()) end)

    local o = fltk:Fl_Button(215, 320, 70, 25, "Back")
    o:callback( function() print"Back button not implemented" end)
    local o = fltk:Fl_Button(285, 320, 70, 25, "Step")
    o:callback( function() coroutine.resume(step) end)
    local o = fltk:Fl_Return_Button(355, 320, 70, 25, "Run")
        while coroutine.status(step)~="dead" do
            print("step, sleeping for "
            coroutine.resume(step) win.window:show() win.output:redraw()



Still know very little about coroutines, but perhaps the "while" loop is interfering. It's my understanding that even though the coroutine is yielding, you're still in a loop, which as I understand it prevents the window from being redrawn.

Just a wild guess.
Allright! I found what it takes: a call to Fl:wait()! Apparently that makes the Fl app to wait until something happens (like a redraw Smile). Now I'm taking off the rough edges before publishing the final version.

Well, I had a lot of fun coding this one, and I think it can be quite entertaining, and perhaps serve for basis for writing other interactive interpreters (Though there should be a bit more separation between logic an UI). The code for the instructions might not be super-readable, but that's because this project started out as an answer in a codegolfing contest.

Anyway here it is, explications are at the top of the file, some demo programs are included and you can find some more here: Note that this program implements the "Old" Fish, where now the whole threading idea has been given up for a "multiple stack" concept. If anyone feels for updating this to the new specs, it shouldn't be too much work.

Any help with the TODO's in the file are also very welcome.
Have fun!


Reference URL's