Actually finished the expr generation and started implementing function context menus
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 12 Apr 2020 18:51:56 +0000 (13:51 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 12 Apr 2020 18:51:56 +0000 (13:51 -0500)
app.lua
src/ui.lua
src/ui/components.lua
src/wasm/exprs.lua
testing.lua

diff --git a/app.lua b/app.lua
index c735a30f4062254731c8759349dda5b59f79665e..fc319fb6a0793b82a3f0e774d0d1c601c7531bb5 100644 (file)
--- a/app.lua
+++ b/app.lua
@@ -24,7 +24,7 @@ function init()
                rect = Rectangle(0, 0, 1200, 900);
                background_color = COLORS.background;
                line_color = COLORS.dark_background;
-               layer = 10;
+               layer = 100;
        }
 
        ui.insert_child(globals.ui.root, globals.ui.scrolling_area)
index d3f48a6c68f4bcb07480a97d7d86e56632b6ad6d..8ed6a5c7c072ada4a8eadd63072f9b3fc9378444 100644 (file)
@@ -72,6 +72,10 @@ end
 function ui.insert_child(parent, child)
        child.parent = parent
        table.insert(parent.children, child)
+
+       local inserted_func = component_lookup(child.type, "inserted")
+       if inserted_func then inserted_func(child) end
+
        ui.sort_children(parent)
 end
 
index 4de52b6c25885d7a60a2b39e966bd6f36e5d9ad4..37d65c38db8d7ae23832b5922f6facafe7099e5a 100644 (file)
@@ -4,6 +4,7 @@ import {
 
        Rectangle = "src.utils:Rectangle";
        wasm_text = "src.wasm.text";
+       wasm_exprs = "src.wasm.exprs";
 
        globals = "src.globals";
        COLORS = "conf:COLOR_SCHEME";
@@ -76,6 +77,41 @@ function drag_rect:mousemoved(x, y, dx, dy)
        end
 end
 
+local button = { extends = "rect" }
+function button:init(text)
+       self.text = text
+       self.color = COLORS.primary_dark
+       self.hovered_color = COLORS.secondary
+       self.text_color = COLORS.primary_text
+       self.click = function() print "Button clicked" end
+       self.hovered = false
+end
+
+function button:mousemoved(x, y, dx, dy)
+       self.hovered = self.rect:contains_trans(x, y)
+end
+
+function button:mousereleased(button, x, y)
+       if ui.focused == self and button == 1 and self.rect:contains_trans(x, y) then
+               self:click(button, x, y)
+       elseif ui.focused == self and button == 1 then
+               ui.focus(nil)
+       end
+end
+
+function button:predraw()
+       if self.hovered then
+               love.graphics.setColor(self.hovered_color)
+       else
+               love.graphics.setColor(self.color)
+       end
+       love.graphics.rectangle("fill", self.rect.x, self.rect.y, self.rect.w, self.rect.h)
+       love.graphics.setColor(self.text_color)
+       love.graphics.printf(self.text, self.rect.x, self.rect.y, self.rect.w, "center")
+end
+
+function button:postdraw() end
+
 local function_block = { extends = "drag_rect" }
 function function_block:init(wasm_function)
        self.func = wasm_function
@@ -118,10 +154,7 @@ function function_block:mousereleased(button, x, y)
        if ui.focused == self and button == 2 then self.resize_down = false end
 
        if ui.focused == self and button == 3 then
-               ui.insert_child(self, with(ui.make_element "deletable_rect") {
-                       rect = Rectangle(x, y, 80, 60);
-                       color = { 1, 0, 0 };
-               })
+               ui.insert_child(self, ui.make_element("function_context_menu", x, y))
        end
 end
 
@@ -216,6 +249,40 @@ function function_block:postdraw()
        love.graphics.pop()
 end
 
+local function_context_menu = { extends = "rect" }
+function function_context_menu:init(x, y)
+       self.rect = Rectangle(x, y, 200, 100)
+       self.color = COLORS.primary
+
+       ui.insert_child(self, with(ui.make_element("button", "View decompiled")) {
+               click = function_context_menu.btn_view_decompiled;
+               rect = Rectangle(0, 0, 200, 40)
+       })
+
+       ui.focus(self)
+end
+
+function function_context_menu:inserted()
+       assert(self.parent.type == "function_block", "function context menu only exists on function blocks")
+       ui.focus(self)
+end
+
+function function_context_menu:mousepressed(button, x, y)
+       if not self.rect:contains_trans(x, y) then
+               self.remove = true
+               return
+       end
+
+       return rect.mousepressed(self, button, x, y)
+end
+
+function function_context_menu:btn_view_decompiled(button, x, y)
+       local wasm_func = self.parent.parent.func
+       print(wasm_func.name .. " ------------------------------------------------")
+       local lines = wasm_exprs.build_expr(wasm_func, globals.wasm_module)
+       for _, r in ipairs(lines) do print(r) end
+end
+
 local scrolling_area = {}
 function scrolling_area:init()
        self.offset = { x = 0; y = 0 }
@@ -352,7 +419,9 @@ end
 
 ui.register_component "rect" (rect)
 ui.register_component "drag_rect" (drag_rect)
+ui.register_component "button" (button)
 ui.register_component "function_block" (function_block)
+ui.register_component "function_context_menu" (function_context_menu)
 ui.register_component "scrolling_area" (scrolling_area)
 
 return module {
index 5f957aeb67a7ef65aaec8d70cafd7d52b146550d..85c0b6dd82a70d14230c01eed26ad0f40dffc0ab 100644 (file)
@@ -26,190 +26,6 @@ This should be quick, just need to look up all the instructions
 
 --]]
 
--- TODO: Maybe add type checking at some point?
-local stack_opts = {
---  Name                                       Inputs, Outputs
-       ["unreachable"]                 = { 0, 0 };
-       ["nop"]                                 = { 0, 0 };
-
-       --block is dynamic
-       --loop is dynamic
-       --if and else are dynamic
-
-       ["br"]                                  = { 0, 0 };
-       ["br_if"]                               = { 1, 0 };
-       ["br_table"]                    = { 1, 0 };
-       ["return"]                              = { 0, 0 };
-       --call is dynamic
-       --call_indirect is dynamic
-
-       ["drop"]                                = { 1, 0 };
-       ["select"]                              = { 3, 1 };
-
-       ["local.get"]                   = { 0, 1 };
-       ["local.set"]                   = { 1, 0 };
-       ["local.tee"]                   = { 1, 1 };
-       ["global.get"]                  = { 0, 1 };
-       ["global.set"]                  = { 1, 0 };
-
-       ["i32.load"]                    = { 1, 1 };
-       ["i64.load"]                    = { 1, 1 };
-       ["f32.load"]                    = { 1, 1 };
-       ["f64.load"]                    = { 1, 1 };
-       ["i32.load8_s"]                 = { 1, 1 };
-       ["i32.load8_u"]                 = { 1, 1 };
-       ["i32.load16_s"]                = { 1, 1 };
-       ["i32.load16_u"]                = { 1, 1 };
-       ["i64.load8_s"]                 = { 1, 1 };
-       ["i64.load8_u"]                 = { 1, 1 };
-       ["i64.load16_s"]                = { 1, 1 };
-       ["i64.load16_u"]                = { 1, 1 };
-       ["i64.load32_s"]                = { 1, 1 };
-       ["i64.load32_u"]                = { 1, 1 };
-       ["i32.store"]                   = { 2, 0 };
-       ["i64.store"]                   = { 2, 0 };
-       ["f32.store"]                   = { 2, 0 };
-       ["f64.store"]                   = { 2, 0 };
-       ["i32.store8"]                  = { 2, 0 };
-       ["i32.store16"]                 = { 2, 0 };
-       ["i64.store8"]                  = { 2, 0 };
-       ["i64.store16"]                 = { 2, 0 };
-       ["i64.store32"]                 = { 2, 0 };
-
-       ["memory.size"]                 = { 0, 1 };
-       ["memory.grow"]                 = { 1, 1 };
-
-       ["i32.const"]                   = { 0, 1 };
-       ["i64.const"]                   = { 0, 1 };
-       ["f32.const"]                   = { 0, 1 };
-       ["f64.const"]                   = { 0, 1 };
-
-       ["i32.eqz"]                             = { 1, 1 };
-       ["i32.eq"]                              = { 2, 1 };
-       ["i32.ne"]                              = { 2, 1 };
-       ["i32.lt_s"]                    = { 2, 1 };
-       ["i32.lt_u"]                    = { 2, 1 };
-       ["i32.gt_s"]                    = { 2, 1 };
-       ["i32.gt_u"]                    = { 2, 1 };
-       ["i32.le_s"]                    = { 2, 1 };
-       ["i32.le_u"]                    = { 2, 1 };
-       ["i32.ge_s"]                    = { 2, 1 };
-       ["i32.ge_u"]                    = { 2, 1 };
-       ["i64.eqz"]                             = { 1, 1 };
-       ["i64.eq"]                              = { 2, 1 };
-       ["i64.ne"]                              = { 2, 1 };
-       ["i64.lt_s"]                    = { 2, 1 };
-       ["i64.lt_u"]                    = { 2, 1 };
-       ["i64.gt_s"]                    = { 2, 1 };
-       ["i64.gt_u"]                    = { 2, 1 };
-       ["i64.le_s"]                    = { 2, 1 };
-       ["i64.le_u"]                    = { 2, 1 };
-       ["i64.ge_s"]                    = { 2, 1 };
-       ["i64.ge_u"]                    = { 2, 1 };
-       ["f32.eq"]                              = { 2, 1 };
-       ["f32.ne"]                              = { 2, 1 };
-       ["f32.lt"]                              = { 2, 1 };
-       ["f32.gt"]                              = { 2, 1 };
-       ["f32.le"]                              = { 2, 1 };
-       ["f32.ge"]                              = { 2, 1 };
-       ["f64.eq"]                              = { 2, 1 };
-       ["f64.ne"]                              = { 2, 1 };
-       ["f64.lt"]                              = { 2, 1 };
-       ["f64.gt"]                              = { 2, 1 };
-       ["f64.le"]                              = { 2, 1 };
-       ["f64.ge"]                              = { 2, 1 };
-       ["i32.clz"]                             = { 1, 1 };
-       ["i32.ctz"]                             = { 1, 1 };
-       ["i32.popcnt"]                  = { 1, 1 };
-       ["i32.add"]                             = { 2, 1 };
-       ["i32.sub"]                             = { 2, 1 };
-       ["i32.mul"]                             = { 2, 1 };
-       ["i32.div_s"]                   = { 2, 1 };
-       ["i32.div_u"]                   = { 2, 1 };
-       ["i32.rem_s"]                   = { 2, 1 };
-       ["i32.rem_u"]                   = { 2, 1 };
-       ["i32.and"]                             = { 2, 1 };
-       ["i32.or"]                              = { 2, 1 };
-       ["i32.xor"]                             = { 2, 1 };
-       ["i32.shl"]                             = { 2, 1 };
-       ["i32.shr_s"]                   = { 2, 1 };
-       ["i32.shr_u"]                   = { 2, 1 };
-       ["i32.rotl"]                    = { 2, 1 };
-       ["i32.rotr"]                    = { 2, 1 };
-       ["i64.clz"]                             = { 1, 1 };
-       ["i64.ctz"]                             = { 1, 1 };
-       ["i64.popcnt"]                  = { 1, 1 };
-       ["i64.add"]                             = { 2, 1 };
-       ["i64.sub"]                             = { 2, 1 };
-       ["i64.mul"]                             = { 2, 1 };
-       ["i64.div_s"]                   = { 2, 1 };
-       ["i64.div_u"]                   = { 2, 1 };
-       ["i64.rem_s"]                   = { 2, 1 };
-       ["i64.rem_u"]                   = { 2, 1 };
-       ["i64.and"]                             = { 2, 1 };
-       ["i64.or"]                              = { 2, 1 };
-       ["i64.xor"]                             = { 2, 1 };
-       ["i64.shl"]                             = { 2, 1 };
-       ["i64.shr_s"]                   = { 2, 1 };
-       ["i64.shr_u"]                   = { 2, 1 };
-       ["i64.rotl"]                    = { 2, 1 };
-       ["i64.rotr"]                    = { 2, 1 };
-       ["f32.abs"]                             = { 1, 1 };
-       ["f32.neg"]                             = { 1, 1 };
-       ["f32.ceil"]                    = { 1, 1 };
-       ["f32.floor"]                   = { 1, 1 };
-       ["f32.trunc"]                   = { 1, 1 };
-       ["f32.nearest"]                 = { 1, 1 };
-       ["f32.sqrt"]                    = { 1, 1 };
-       ["f32.add"]                             = { 2, 1 };
-       ["f32.sub"]                             = { 2, 1 };
-       ["f32.mul"]                             = { 2, 1 };
-       ["f32.div"]                             = { 2, 1 };
-       ["f32.min"]                             = { 2, 1 };
-       ["f32.max"]                             = { 2, 1 };
-       ["f32.copysign"]                = { 2, 1 };
-       ["f64.abs"]                             = { 1, 1 };
-       ["f64.neg"]                             = { 1, 1 };
-       ["f64.ceil"]                    = { 1, 1 };
-       ["f64.floor"]                   = { 1, 1 };
-       ["f64.trunc"]                   = { 1, 1 };
-       ["f64.nearest"]                 = { 1, 1 };
-       ["f64.sqrt"]                    = { 1, 1 };
-       ["f64.add"]                             = { 2, 1 };
-       ["f64.sub"]                             = { 2, 1 };
-       ["f64.mul"]                             = { 2, 1 };
-       ["f64.div"]                             = { 2, 1 };
-       ["f64.min"]                             = { 2, 1 };
-       ["f64.max"]                             = { 2, 1 };
-       ["f64.copysign"]                = { 2, 1 };
-
-       ["i32.wrap_i64"]                = { 1, 1 };
-       ["i32.trunc_f32_s"]             = { 1, 1 };
-       ["i32.trunc_f32_u"]             = { 1, 1 };
-       ["i32.trunc_f64_s"]             = { 1, 1 };
-       ["i32.trunc_f64_u"]             = { 1, 1 };
-       ["i64.extend_i32_s"]    = { 1, 1 };
-       ["i64.extend_i32_u"]    = { 1, 1 };
-       ["i64.trunc_f32_s"]             = { 1, 1 };
-       ["i64.trunc_f32_u"]             = { 1, 1 };
-       ["i64.trunc_f64_s"]             = { 1, 1 };
-       ["i64.trunc_f64_u"]             = { 1, 1 };
-       ["f32.convert_i32_s"]   = { 1, 1 };
-       ["f32.convert_i32_u"]   = { 1, 1 };
-       ["f32.convert_i64_s"]   = { 1, 1 };
-       ["f32.convert_i64_u"]   = { 1, 1 };
-       ["f32.demote_f64"]              = { 1, 1 };
-       ["f64.convert_i32_s"]   = { 1, 1 };
-       ["f64.convert_i32_u"]   = { 1, 1 };
-       ["f64.convert_i64_s"]   = { 1, 1 };
-       ["f64.convert_i64_u"]   = { 1, 1 };
-       ["f64.promote_f32"]             = { 1, 1 };
-       ["i32.reinterpret_f32"] = { 1, 1 };
-       ["i64.reinterpret_f64"] = { 1, 1 };
-       ["f32.reinterpret_i32"] = { 1, 1 };
-       ["f64.reinterpret_i64"] = { 1, 1 };
-}
-
 local build_instr_list
 
 function binop(op)
@@ -227,8 +43,9 @@ function cast(to)
        end
 end
 
-function func_call(name, nparams)
-       nparams = nparams or 1
+function func_call(name, nparams, nreturns)
+       if nparams == nil then nparams = 1 end
+       if nreturns == nil then nreturns = 1 end
        return function(stack, instr)
                local str = name .. "("
                local args = ""
@@ -237,7 +54,11 @@ function func_call(name, nparams)
                        args = ", " .. val .. args
                end
                str = str .. args:sub(3) .. ")"
-               stack:push(str)
+               if nreturns == 0 then
+                       return str
+               else
+                       stack:push(str)
+               end
        end
 end
 
@@ -264,7 +85,18 @@ function expr_br_if(stack, instr)
 end
 
 function expr_br_table(stack, instr)
-       error "Cannot handle br_table"
+       local lines = {}
+       table.insert(lines, "br_table (" .. stack:pop() .. ") {")
+       local mappings = {}
+       for i, lab in ipairs(instr.labels) do
+               table.insert(mappings, tostring(i - 1) .. " => <" .. lab.block.label .. ">")
+       end
+       table.insert(mappings, "default => <" .. instr.labeln.block.label .. ">")
+       for _, line in ipairs(indent(mappings, "  ")) do
+               table.insert(lines, line)
+       end
+       table.insert(lines, "}")
+       return lines
 end
 
 function expr_drop(stack, instr)
@@ -325,7 +157,11 @@ function expr_block(stack, instr, func, mod)
        )
        table.insert(lines, 1, "block <" .. instr.label .. "> {")
        table.insert(lines, "}")
-       return lines
+       if #instr.rt == 0 then
+               return lines
+       else
+               stack:push(table.concat(lines, "\n"))
+       end
 end
 
 function expr_loop(stack, instr, func, mod)
@@ -335,7 +171,11 @@ function expr_loop(stack, instr, func, mod)
        )
        table.insert(lines, 1, "loop <" .. instr.label .. "> {")
        table.insert(lines, "}")
-       return lines
+       if #instr.rt == 0 then
+               return lines
+       else
+               stack:push(table.concat(lines, "\n"))
+       end
 end
 
 function expr_if(stack, instr, func, mod)
@@ -355,7 +195,11 @@ function expr_if(stack, instr, func, mod)
                end
        end
        table.insert(lines, "}")
-       return lines
+       if #instr.rt == 0 then
+               return lines
+       else
+               stack:push(table.concat(lines, "\n"))
+       end
 end
 
 function expr_call(stack, instr, func, mod)
@@ -363,7 +207,7 @@ function expr_call(stack, instr, func, mod)
        local nreturns = #mod.funcs[instr.x].type_.result_types
        local name = mod.funcs[instr.x].name
 
-       local res = func_call(name, nparams)(stack, instr, func, mod)
+       local res = func_call(name, nparams, nreturns)(stack, instr, func, mod)
        if nreturns >= 1 then
                stack:push(res)
        else
@@ -371,14 +215,26 @@ function expr_call(stack, instr, func, mod)
        end
 end
 
-function call_indirect(stack, instr)
-       error "Cannot handle call indirect"
+function expr_call_indirect(stack, instr, func, mod)
+       local type_ = mod.types.contents[instr.x + 1]
+       local nparams = #type_.param_types
+       local nreturns = #type_.result_types
+       local addr = stack:pop()
+       local res = func_call("[" .. addr .. "]", nparams, nreturns)(stack, instr, func, mod)
+       if nreturns >= 1 then
+               stack:push(res)
+       else
+               return res
+       end
 end
 
+function expr_nop() return "nop" end
+function expr_unreachable() return "unreachable" end
+
 local expr_generators = {
 --  Name                                       Inputs, Outputs
-       ["unreachable"]                 = { 0, 0 };
-       ["nop"]                                 = { 0, 0 };
+       ["unreachable"]                 = expr_unreachable;
+       ["nop"]                                 = expr_nop;
 
        ["block"]                               = expr_block;
        ["loop"]                                = expr_loop;
@@ -389,7 +245,7 @@ local expr_generators = {
        ["br_table"]                    = expr_br_table;
        ["return"]                              = expr_return;
        ["call"]                                = expr_call;
-       --call_indirect is dynamic
+       ["call_indirect"]               = expr_call_indirect;
 
        ["drop"]                                = expr_drop;
        ["select"]                              = expr_select;
@@ -503,7 +359,7 @@ local expr_generators = {
        ["i64.rotl"]                    = binop "rotl";
        ["i64.rotr"]                    = binop "rotr";
        ["f32.abs"]                             = func_call "abs";
-       ["f32.neg"]                             = func_call "neg"; -- TODO: make this better
+       ["f32.neg"]                             = func_call "-";
        ["f32.ceil"]                    = func_call "ceil";
        ["f32.floor"]                   = func_call "floor";
        ["f32.trunc"]                   = func_call "trunc";
@@ -517,7 +373,7 @@ local expr_generators = {
        ["f32.max"]                             = func_call("max", 2);
        ["f32.copysign"]                = func_call("copysign", 2);
        ["f64.abs"]                             = func_call "abs";
-       ["f64.neg"]                             = func_call "neg";
+       ["f64.neg"]                             = func_call "-";
        ["f64.ceil"]                    = func_call "ceil";
        ["f64.floor"]                   = func_call "floor";
        ["f64.trunc"]                   = func_call "trunc";
@@ -558,8 +414,6 @@ local expr_generators = {
        ["f64.reinterpret_i64"] = cast "f64";
 }
 
-
--- This works... ish but we should use proper symbols (+-*/) and other things
 function build_instr_list(instrs, func, mod)
        local lines = {}
        local stack = Stack()
index 10362d8f7a02db451da4b004789e8fbdbe43ca66..9415924541fe0cd6828106bcc60737b4472e79fc 100644 (file)
@@ -12,7 +12,7 @@ local mod = decompile(arg[1])
 mod = analyze(mod)
 -- pprint(mod)
 
-for i, func in ipairs(mod.funcs) do
+for i, func in pairs(mod.funcs) do
        if func.body then
                print(func.name .. " -----------------------------------")
                local res = build_expr(func, mod)