branch: externals/beardbolt commit a191eb9c73eb1c3ae10f35dde3741ed7ce73bb3c Author: Jay Kamat <jaygka...@gmail.com> Commit: Jay Kamat <jaygka...@gmail.com>
Add basic Java support --- README.org | 14 +++++--- rmsbolt-java.el | 99 ++++++++++++++++++++++++++++++++++++++++++++++++--- rmsbolt.el | 6 +++- starters/Rmsbolt.java | 27 ++++++++++++++ 4 files changed, 135 insertions(+), 11 deletions(-) diff --git a/README.org b/README.org index 714ab6e49d..594d692b0f 100644 --- a/README.org +++ b/README.org @@ -1,4 +1,4 @@ -* RMSbolt + * RMSbolt A basic implementation of the [[https://github.com/mattgodbolt/compiler-explorer][godbolt compiler-explorer]] for Emacs. @@ -13,9 +13,10 @@ versa. - Much faster turnaround time from writing code to seeing and interacting with disassembly - 100% usable without the mouse. - Runs entirely without node, npm, or js. - - No required dependencies other than emacs 25 and your compiler ~:)~ + - No required dependencies other than Emacs 25 and your compiler ~:)~ - It's easy to add new languages (even those that use unique bytecode formats) without touching many files. + - Dosen't eat your ram on the 'server' or the 'client' - Benefits from living in Emacs - Full undo tree from Emacs on disassembly/source so you don't loose work. - Vim bindings through evil/viper. @@ -34,7 +35,8 @@ versa. * Installation rmsbolt will almost certainly not work naively on windows as it depends on a -unix shell for building commands. It may work through cygwin though. +unix shell for building the compilation commands. It may work through cygwin +though. rmsbolt is not on melpa yet. If you find it useful, please let me know and I may add it.. @@ -53,8 +55,7 @@ add it.. enable ~rmsbolt-mode~ in a supported language. Then run ~rmsbolt-compile~ or use the default ~C-c C-c~ binding. -* Demo - +* Demos ** C/C++ [[https://s25.postimg.cc/c1zj5ghr3/sihr1g.gif]] @@ -114,3 +115,6 @@ available in the compiled form if they exist. existing examples. You're done! +* Alternatives +- [[https://github.com/yawkat/javap][yawkat/javap]] +- [[https://github.com/mattgodbolt/compiler-explorer][mattgodbolt/compiler-explorer]] diff --git a/rmsbolt-java.el b/rmsbolt-java.el index 7acf7743e6..11dd49c041 100644 --- a/rmsbolt-java.el +++ b/rmsbolt-java.el @@ -34,14 +34,103 @@ ;;; Code: -(defun rmsbolt-java-process-bytecode (asm-lines) +;;;; Regexes +(defvar rmsbolt-java-code-start (rx bol (1+ space) + (group "Code:"))) +(defvar rmsbolt-java-line-table-start (rx bol (1+ space) + (group "LineNumberTable:"))) +(defvar rmsbolt-java-local-table-start (rx bol (1+ space) + (group "LocalVariableTable:"))) +(defvar rmsbolt-java-code (rx bol (group (1+ space)) (group (1+ digit)) + ":" (1+ space) (group (1+ any)) eol)) +(defvar rmsbolt-java-line-table (rx bol (1+ space) "line" (1+ space) (group (1+ digit)) + ":" (1+ space) (group (1+ digit)))) + +;;;; Functions +(defun rmsbolt-java-process-bytecode (asm-lines &optional filter) "Process ASM-LINES to add properties refrencing the source code. -Also filters \"useless\" lines out." - ) +Also FILTER \"useless\" lines out, optionally." + (let (result state result-hold code-block code-linum in-bracket) + (dolist (line asm-lines) + (pcase state + ('nil ;; We haven't found any special blocks, so look for them and copy to output + (when (string-match-p rmsbolt-java-code-start line) + (setq state 'code-found) + (push line result))) + ('code-found ;; We are past Code: so begin parsing instructions + (if (string-match-p rmsbolt-java-line-table-start line) + (setq state 'linum-found) + (if (and (string-match rmsbolt-java-code line) + (match-string 1 line) + (match-string 2 line) + (match-string 3 line) + (not in-bracket)) + (progn (push (cons (string-to-number (match-string 2 line)) + line) + code-block) + (when (string-match-p "{" line) + (setq in-bracket t))) + ;; Assume we have a continuation line + (push (cons (cl-first (car code-block)) + line) + code-block) + (when (string-match-p "}" line) + (setq in-bracket nil)) + ))) + ('linum-found ;; We are past LineNumberTable, so begin generating the src->code table + (if (string-match-p rmsbolt-java-local-table-start line) + (progn + (setq state 'localvar-found) + ;; Get everything ready for agg + (setq code-block (nreverse code-block)) + (setq code-linum (nreverse code-linum))) + + (if (and (string-match rmsbolt-java-line-table line) + (match-string 1 line) + (match-string 2 line)) + (push (cons (string-to-number (match-string 2 line)) + (string-to-number (match-string 1 line))) + code-linum) + (error "Unexpected output inside LineNumberTable: block of javap")))) + ('localvar-found ;; Agg results if they exist + ;; TODO can we assume there is an empty line after LocalVar? + (if (string-empty-p line) + (setq state nil) + (when (and code-linum code-block) + (let (current-mapping current-line) + (dolist (l code-block) + (when (and code-linum + (>= (car l) + (car (cl-first code-linum)))) + ;; We are at (or passed) the line at the top of code-linum mapping, let's use the mapping + (setq current-mapping (pop code-linum))) + (setq current-line (cdr l)) + (when (and current-mapping + (numberp (cdr current-mapping))) + (add-text-properties 0 (length current-line) + `(rmsbolt-src-line ,(cdr current-mapping)) current-line)) + (push current-line result))) + ;; Don't keep agging + (setq code-linum nil + code-block nil))))) + (if (not state) + (progn + (when result-hold + ;; We have leftovers in result-hold, let's flush them + (setq result (append result-hold result)) + (setq result-hold nil)) + (push line result)) + (when (and (not filter) + ;; Never ouptut code, that's handled above. Code: is handled on transition + (not (eq state 'code-found))) + (push line result-hold)))) + (nreverse result))) -(defun rmsbolt--process-java-bytecode (_src_buffer asm-lines) +(defun rmsbolt--process-java-bytecode (src-buffer asm-lines) "Wrapper for easy integration into rmsbolt." - (rmsbolt-java-process-bytecode asm-lines)) + (rmsbolt-java-process-bytecode + asm-lines + (buffer-local-value 'rmsbolt-filter-directives src-buffer))) (provide 'rmsbolt-java) diff --git a/rmsbolt.el b/rmsbolt.el index 26317820c9..c9ab587eb0 100644 --- a/rmsbolt.el +++ b/rmsbolt.el @@ -30,6 +30,8 @@ (require 'map) (require 'cc-defs) +(require 'rmsbolt-java) + ;;; Code: ;;;; Customize: (defgroup rmsbolt nil @@ -483,8 +485,9 @@ Outputs assembly file if ASM." :supports-asm t :supports-disass nil :objdumper 'cat - :starter-file-name "rmsbolt.java" + :starter-file-name "Rmsbolt.java" :compile-cmd-function #'rmsbolt--java-compile-cmd + :process-asm-custom-fn #'rmsbolt--process-java-bytecode :disass-hidden-funcs nil)) )) @@ -972,6 +975,7 @@ Outputs assembly file if ASM." (rmsbolt-defstarter "cl" 'lisp-mode) (rmsbolt-defstarter "rust " 'rust-mode) (rmsbolt-defstarter "python" 'python-mode) +(rmsbolt-defstarter "java" 'java-mode) ;;;; Font lock matcher (defun rmsbolt--goto-line (line) diff --git a/starters/Rmsbolt.java b/starters/Rmsbolt.java new file mode 100644 index 0000000000..769cabdc2a --- /dev/null +++ b/starters/Rmsbolt.java @@ -0,0 +1,27 @@ +// Java rmsbolt starter file + +// Local Variables: +// rmsbolt-command: "javac" +// rmsbolt-filter-directives: t +// End: + +public class Rmsbolt { + public static int isRMS(char in) { + switch (in) { + case 'R': + return 1; + case 'M': + return 2; + case 'S': + return 3; + default: + return 0; + } + } + + public static void main(String[] args) { + char a = 1 + 1; + if (isRMS(a) == 0) + System.out.println(a); + } +}