about summary refs log tree commit diff stats
path: root/vimrc.vim
blob: 2f39ad8d9314ff7e2be7eda4b18078bcb6f5a561 (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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
" Highlighting literate directives in C++ sources.
function! HighlightTangledFile()
  " Tangled comments only make sense in the sources and are stripped out of
  " the generated .cc file. They're highlighted same as regular comments.
  syntax match tangledComment /\/\/:.*/ | highlight link tangledComment Comment
  syntax match tangledSalientComment /\/\/::.*/ | highlight link tangledSalientComment SalientComment
  set comments-=://
  set comments-=n://
  set comments+=n://:,n://

  " Inside tangle scenarios.
  syntax region tangleDirective start=+:(+ skip=+".*"+ end=+)+
  highlight link tangleDirective Delimiter
  syntax match traceContains /^+.*/
  highlight traceContains ctermfg=22
  syntax match traceAbsent /^-.*/
  highlight traceAbsent ctermfg=darkred
  syntax match tangleScenarioSetup /^\s*% .*/ | highlight link tangleScenarioSetup SpecialChar
  highlight Special ctermfg=160

  syntax match subxString %"[^"]*"% | highlight link subxString Constant
  " match globals but not registers like 'EAX'
  syntax match subxGlobal %\<[A-Z][a-z0-9_-]*\>% | highlight link subxGlobal SpecialChar
endfunction
augroup LocalVimrc
  autocmd BufRead,BufNewFile *.cc call HighlightTangledFile()
  autocmd BufRead,BufNewFile *.subx set ft=subx
augroup END

" Scenarios considered:
"   opening or starting vim with a new or existing file without an extension (should interpret as C++)
"   opening or starting vim with a new or existing file with a .mu extension
"   starting vim or opening a buffer without a file name (ok to do nothing)
"   opening a second file in a new or existing window (shouldn't mess up existing highlighting)
"   reloading an existing file (shouldn't mess up existing highlighting)

command! -nargs=1 E call EditSubx("edit", <f-args>)
if exists("&splitvertical")
  command! -nargs=1 S call EditSubx("vert split", <f-args>)
  command! -nargs=1 H call EditSubx("hor split", <f-args>)
else
  command! -nargs=1 S call EditSubx("vert split", <f-args>)
  command! -nargs=1 H call EditSubx("split", <f-args>)
endif

function! EditSubx(cmd, arg)
  exec "silent! " . a:cmd . " " . SubxPath(a:arg)
endfunction

function! SubxPath(arg)
  if a:arg =~ "^ex"
    return "examples/" . a:arg . ".subx"
  else
    return "apps/" . a:arg . ".subx"
  endif
endfunction

" we often want to crib lines of machine code from other files
function! GrepSubX(regex)
  " https://github.com/mtth/scratch.vim
  Scratch!
  silent exec "r !grep -h '".a:regex."' *.subx */*.subx"
endfunction
command! -nargs=1 G call GrepSubX(<q-args>)

if exists("&splitvertical")
  command! -nargs=0 P hor split opcodes
else
  command! -nargs=0 P split opcodes
endif

" useful for inspecting just the control flow in a trace
" see https://github.com/akkartik/mu/blob/master/Readme.md#a-few-hints-for-debugging
" the '-a' is because traces can sometimes contain unprintable characters that bother grep
command! -nargs=0 L exec "%!grep -a label |grep -v clear-stream:loop"

" run test cursor around cursor
"   if test fails, open trace in split window
"   if test passes, just show output and wait for <CR>
"   don't move cursor in original window
" this solution is unfortunate, but seems forced:
"   can't put initial cursor movement inside function because we rely on <C-r><C-w> to grab word at cursor
"   can't put final cursor movement out of function because that disables the wait for <CR> prompt; function must be final operation of map
"   can't avoid the function because that disables the wait for <CR> prompt
" known issue:
"   cursor on '#' causes error
noremap <Leader>t {j0:call RunTestMoveCursor("<C-r><C-w>")<CR>
function RunTestMoveCursor(arg)
  exec "!./run_one_test ".expand("%")." ".a:arg
  exec "normal \<C-o>"
endfunction
function RunTestMoveCursorAndMaybeOpenTrace(arg)
  exec "!./run_one_test ".expand("%")." ".a:arg
  exec "normal \<C-o>"
  if v:shell_error
    noautocmd vertical split last_run
  endif
endfunction

set switchbuf=useopen
if exists("&splitvertical")
  command! -nargs=0 T badd last_run | sbuffer last_run
else
  command! -nargs=0 T badd last_run | vert sbuffer last_run
endif
s="o"><- copy 0 $to-grapheme:compute-length: { # single byte: just return it compare c, 0x7f { break-if-> var g/eax: grapheme <- copy c return g } # 2 bytes compare c, 0x7ff { break-if-> num-trailers <- copy 1 first <- copy 0xc0 break $to-grapheme:compute-length } # 3 bytes compare c, 0xffff { break-if-> num-trailers <- copy 2 first <- copy 0xe0 break $to-grapheme:compute-length } # 4 bytes compare c, 0x1fffff { break-if-> num-trailers <- copy 3 first <- copy 0xf0 break $to-grapheme:compute-length } # more than 4 bytes: unsupported # TODO: print error message to stderr compare c, 0x1fffff { break-if-> return 0 } } # emit trailer bytes, 6 bits from 'in', first two bits '10' var result/edi: grapheme <- copy 0 { compare num-trailers, 0 break-if-<= var tmp/esi: int <- copy c tmp <- and 0x3f tmp <- or 0x80 result <- shift-left 8 result <- or tmp # update loop state c <- shift-right 6 num-trailers <- decrement loop } # emit engine result <- shift-left 8 result <- or c result <- or first # return result } # TODO: bring in tests once we have check-ints-equal # read the next grapheme from a stream of bytes fn read-grapheme in: (addr stream byte) -> _/eax: grapheme { # if at eof, return EOF { var eof?/eax: boolean <- stream-empty? in compare eof?, 0/false break-if-= return 0xffffffff } var c/eax: byte <- read-byte in var num-trailers/ecx: int <- copy 0 $read-grapheme:compute-length: { # single byte: just return it compare c, 0xc0 { break-if->= var g/eax: grapheme <- copy c return g } compare c, 0xfe { break-if-< var g/eax: grapheme <- copy c return g } # 2 bytes compare c, 0xe0 { break-if->= num-trailers <- copy 1 break $read-grapheme:compute-length } # 3 bytes compare c, 0xf0 { break-if->= num-trailers <- copy 2 break $read-grapheme:compute-length } # 4 bytes compare c, 0xf8 { break-if->= num-trailers <- copy 3 break $read-grapheme:compute-length } # TODO: print error message return 0 } # prepend trailer bytes var result/edi: grapheme <- copy c var num-byte-shifts/edx: int <- copy 1 { compare num-trailers, 0 break-if-<= var tmp/eax: byte <- read-byte in var tmp2/eax: int <- copy tmp tmp2 <- shift-left-bytes tmp2, num-byte-shifts result <- or tmp2 # update loop state num-byte-shifts <- increment num-trailers <- decrement loop } return result } # needed because available primitives only shift by a literal/constant number of bits fn shift-left-bytes n: int, k: int -> _/eax: int { var i/ecx: int <- copy 0 var result/eax: int <- copy n { compare i, k break-if->= compare i, 4 # only 4 bytes in 32 bits break-if->= result <- shift-left 8 i <- increment loop } return result } # write a grapheme to a stream of bytes # this is like write-to-stream, except we skip leading 0 bytes fn write-grapheme out: (addr stream byte), g: grapheme { $write-grapheme:body: { var c/eax: int <- copy g append-byte out, c # first byte is always written c <- shift-right 8 compare c, 0 break-if-= $write-grapheme:body append-byte out, c c <- shift-right 8 compare c, 0 break-if-= $write-grapheme:body append-byte out, c c <- shift-right 8 compare c, 0 break-if-= $write-grapheme:body append-byte out, c } }