about summary refs log tree commit diff stats
path: root/114error.subx
blob: c3d8ca6827735f866b71d99670021ff6302a31f9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# Print an error message and exit.

== code
#   instruction                     effective address                                                   register    displacement    immediate
# . op          subop               mod             rm32          base        index         scale       r32
# . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes

# write(out, "Error: "+msg+"\n") then stop(ed, 1)
error:  # ed: (addr exit-descriptor), out: fd or (addr stream byte), msg: (addr array byte)
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # write(out, "Error: ")
    # . . push args
    68/push  "Error: "/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write(out, msg)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # write(out, "\n")
    # . . push args
    68/push  Newline/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # stop(ed, 1)
    # . . push args
    68/push  1/imm32
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  stop/disp32
    # should never get past this point
$error:dead-end:
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# . . vim:nowrap:textwidth=0
/* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
Menu_background_color = {r=0.6, g=0.8, b=0.6}
Menu_border_color = {r=0.6, g=0.7, b=0.6}
Menu_command_color = {r=0.2, g=0.2, b=0.2}
Menu_highlight_color = {r=0.5, g=0.7, b=0.3}

function source.draw_menu_bar()
  if App.run_tests then return end  -- disable in tests
  App.color(Menu_background_color)
  love.graphics.rectangle('fill', 0,0, App.screen.width, Menu_status_bar_height)
  App.color(Menu_border_color)
  love.graphics.rectangle('line', 0,0, App.screen.width, Menu_status_bar_height)
  App.color(Menu_command_color)
  Menu_cursor = 5
  if Show_file_navigator then
    source.draw_file_navigator()
    return
  end
  add_hotkey_to_menu('ctrl+e: run')
  if Focus == 'edit' then
    add_hotkey_to_menu('ctrl+g: switch file')
    if Show_log_browser_side then
      add_hotkey_to_menu('ctrl+l: hide log browser')
    else
      add_hotkey_to_menu('ctrl+l: show log browser')
    end
    if Editor_state.expanded then
      add_hotkey_to_menu('alt+b: collapse debug prints')
    else
      add_hotkey_to_menu('alt+b: expand debug prints')
    end
    add_hotkey_to_menu('alt+d: create/edit debug print')
    add_hotkey_to_menu('ctrl+f: find in file')
    add_hotkey_to_menu('alt+left alt+right: prev/next word')
  elseif Focus == 'log_browser' then
    -- nothing yet
  else
    assert(false, 'unknown focus "'..Focus..'"')
  end
  add_hotkey_to_menu('ctrl+z ctrl+y: undo/redo')
  add_hotkey_to_menu('ctrl+x ctrl+c ctrl+v: cut/copy/paste')
  add_hotkey_to_menu('ctrl+= ctrl+- ctrl+0: zoom')
end

function add_hotkey_to_menu(s)
  local s_text = to_text(s)
  local width = App.width(s_text)
  if Menu_cursor + width > App.screen.width - 5 then
    return
  end
  App.color(Menu_command_color)
  App.screen.draw(s_text, Menu_cursor,5)
  Menu_cursor = Menu_cursor + width + 30
end

function source.draw_file_navigator()
  App.color(Menu_command_color)
  local filter_text = to_text(File_navigation.filter)
  App.screen.draw(filter_text, 5, 5)
  draw_cursor(5 + App.width(filter_text), 5)
  if File_navigation.num_lines == nil then
    File_navigation.num_lines = source.num_lines_for_file_navigator(File_navigation.candidates)
  end
  App.color(Menu_background_color)
  love.graphics.rectangle('fill', 0,Menu_status_bar_height, App.screen.width, File_navigation.num_lines * Editor_state.line_height + --[[highlight padding]] 2)
  local x,y = 5, Menu_status_bar_height
  for i,filename in ipairs(File_navigation.candidates) do
    x,y = add_file_to_menu(x,y, filename, i == File_navigation.index)
    if Menu_cursor >= App.screen.width - 5 then
      break
    end
  end
end

function draw_cursor(x, y)
  -- blink every 0.5s
  if math.floor(Cursor_time*2)%2 == 0 then
    App.color(Cursor_color)
    love.graphics.rectangle('fill', x,y, 3,Editor_state.line_height)
  end
end

function source.file_navigator_candidates()
  if File_navigation.filter == '' then
    return File_navigation.all_candidates
  end
  local result = {}
  for _,filename in ipairs(File_navigation.all_candidates) do
    if starts_with(filename, File_navigation.filter) then
      table.insert(result, filename)
    end
  end
  return result
end

function source.num_lines_for_file_navigator(candidates)
  local result = 1
  local x = 5
  for i,filename in ipairs(candidates) do
    local width = App.width(to_text(filename))
    if x + width > App.screen.width - 5 then
      result = result+1
      x = 5 + width
    else
      x = x + width + 30
    end
  end
  return result
end

function add_file_to_menu(x,y, s, cursor_highlight)
  local s_text = to_text(s)
  local width = App.width(s_text)
  if x + width > App.screen.width - 5 then
    y = y + Editor_state.line_height
    x = 5
  end
  local color = Menu_background_color
  if cursor_highlight then
    color = Menu_highlight_color
  end
  button(Editor_state, 'menu', {x=x-5, y=y-2, w=width+5*2, h=Editor_state.line_height+2*2, color=colortable(color),
    onpress1 = function()
      navigate_to_file(s)
    end
  })
  App.color(Menu_command_color)
  App.screen.draw(s_text, x,y)
  x = x + width + 30
  return x,y
end

function navigate_to_file(s)
  move_candidate_to_front(s)
  local candidate = guess_source(s..'.lua')
  source.switch_to_file(candidate)
  reset_file_navigator()
end

function move_candidate_to_front(s)
  local index = array.find(File_navigation.all_candidates, s)
  assert(index)
  table.remove(File_navigation.all_candidates, index)
  table.insert(File_navigation.all_candidates, 1, s)
end

function reset_file_navigator()
  Show_file_navigator = false
  File_navigation.index = 1
  File_navigation.filter = ''
  File_navigation.candidates = File_navigation.all_candidates
end

function keychord_pressed_on_file_navigator(chord, key)
  log(2, 'file navigator: '..chord)
  log(2, {name='file_navigator_state', files=File_navigation.candidates, index=File_navigation.index})
  if chord == 'escape' then
    reset_file_navigator()
  elseif chord == 'return' then
    navigate_to_file(File_navigation.candidates[File_navigation.index])
  elseif chord == 'backspace' then
    local len = utf8.len(File_navigation.filter)
    local byte_offset = Text.offset(File_navigation.filter, len)
    File_navigation.filter = string.sub(File_navigation.filter, 1, byte_offset-1)
    File_navigation.index = 1
    File_navigation.candidates = source.file_navigator_candidates()
  elseif chord == 'left' then
    if File_navigation.index > 1 then
      File_navigation.index = File_navigation.index-1
    end
  elseif chord == 'right' then
    if File_navigation.index < #File_navigation.candidates then
      File_navigation.index = File_navigation.index+1
    end
  elseif chord == 'down' then
    file_navigator_down()
  elseif chord == 'up' then
    file_navigator_up()
  end
end

function log_render.file_navigator_state(o, x,y, w)
  -- duplicate structure of source.draw_file_navigator
  local num_lines = source.num_lines_for_file_navigator(o.files)
  local h = num_lines * Editor_state.line_height
  App.color(Menu_background_color)
  love.graphics.rectangle('fill', x,y, w,h)
  -- compute the x,y,width of the current index (in offsets from top left)
  local x2,y2 = 0,0
  local width = 0
  for i,filename in ipairs(o.files) do
    local filename_text = to_text(filename)
    width = App.width(filename_text)
    if x2 + width > App.screen.width - 5 then
      y2 = y2 + Editor_state.line_height
      x2 = 0
    end
    if i == o.index then
      break
    end
    x2 = x2 + width + 30
  end
  -- figure out how much of the menu to display
  local menu_xmin = math.max(0, x2-w/2)
  local menu_xmax = math.min(App.screen.width, x2+w/2)
  -- now selectively print out entries
  local x3,y3 = 0,y  -- x3 is relative, y3 is absolute
  local width = 0
  for i,filename in ipairs(o.files) do
    local filename_text = to_text(filename)
    width = App.width(filename_text)
    if x3 + width > App.screen.width - 5 then
      y3 = y3 + Editor_state.line_height
      x3 = 0
    end
    if i == o.index then
      App.color(Menu_highlight_color)
      love.graphics.rectangle('fill', x + x3-menu_xmin - 5, y3-2, width+5*2, Editor_state.line_height+2*2)
    end
    if x3 >= menu_xmin and x3 + width < menu_xmax then
      App.color(Menu_command_color)
      App.screen.draw(filename_text, x + x3-menu_xmin, y3)
    end
    x3 = x3 + width + 30
  end
  --
  return h+20
end

function file_navigator_up()
  local y, x, width = file_coord(File_navigation.index)
  local index = file_index(y-Editor_state.line_height, x, width)
  if index then
    File_navigation.index = index
  end
end

function file_navigator_down()
  local y, x, width = file_coord(File_navigation.index)
  local index = file_index(y+Editor_state.line_height, x, width)
  if index then
    File_navigation.index = index
  end
end

function file_coord(index)
  local y,x = Menu_status_bar_height, 5
  for i,filename in ipairs(File_navigation.candidates) do
    local width = App.width(to_text(filename))
    if x + width > App.screen.width - 5 then
      y = y + Editor_state.line_height
      x = 5
    end
    if i == index then
    return y, x, width
    end
    x = x + width + 30
  end
end

function file_index(fy, fx, fwidth)
  log_start('file index')
  log(2, ('for %d %d %d'):format(fy, fx, fwidth))
  local y,x = Menu_status_bar_height, 5
  local best_guess, best_guess_x, best_guess_width
  for i,filename in ipairs(File_navigation.candidates) do
    local width = App.width(to_text(filename))
    if x + width > App.screen.width - 5 then
      y = y + Editor_state.line_height
      x = 5
    end
    if y == fy then
      log(2, ('%d: correct row; considering %d %s %d %d'):format(y, i, filename, x, width))
      if best_guess == nil then
        log(2, 'nil')
        best_guess = i
        best_guess_x = x
        best_guess_width = width
      elseif math.abs(fx + fwidth/2 - x - width/2) < math.abs(fx + fwidth/2 - best_guess_x - best_guess_width/2) then
        best_guess = i
        best_guess_x = x
        best_guess_width = width
      end
      log(2, ('best guess now %d %s %d %d'):format(best_guess, File_navigation.candidates[best_guess], best_guess_x, best_guess_width))
    end
    x = x + width + 30
  end
  log_end('file index')
  return best_guess
end

function textinput_on_file_navigator(t)
  File_navigation.filter = File_navigation.filter..t
  File_navigation.candidates = source.file_navigator_candidates()
end