Add task `rake doc:update-opcode.md`
Allow to update `doc/internal/opcode.md` file mechanically from `include/mruby/ops.h` file.
At the same time, the `doc/internal/opcode.md` file has been updated.
Consecutive hyphens at the end of the table were removed as they would have created noise as markdown flavours.
MODIFY
doc/internal/opcode.md
doc/internal/opcode.md
@@ -59,6 +59,8 @@ sign) of operands.
| `OP_SETMCNST` | `BB` | `R(a+1)::Syms(b) = R(a)` |
| `OP_GETUPVAR` | `BBB` | `R(a) = uvget(b,c)` |
| `OP_SETUPVAR` | `BBB` | `uvset(b,c,R(a))` |
+| `OP_GETIDX` | `B` | `R(a) = R(a)[R(a+1)]` |
+| `OP_SETIDX` | `B` | `R(a)[R(a+1)] = R(a+2)` |
| `OP_JMP` | `S` | `pc+=a` |
| `OP_JMPIF` | `BS` | `if R(a) pc+=b` |
| `OP_JMPNOT` | `BS` | `if !R(a) pc+=b` |
@@ -67,8 +69,10 @@ sign) of operands.
| `OP_EXCEPT` | `B` | `R(a) = exc` |
| `OP_RESCUE` | `BB` | `R(b) = R(a).isa?(R(b))` |
| `OP_RAISEIF` | `B` | `raise(R(a)) if R(a)` |
-| `OP_SEND` | `BBB` | `R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c))` |
-| `OP_SENDB` | `BBB` | `R(a) = call(R(a),Syms(b),R(a+1),...,R(a+c),&R(a+c+1))` |
+| `OP_SSEND` | `BBB` | `R(a) = self.send(Syms(b),R(a+1)..,R(a+n+1):R(a+n+2)..) (c=n|k<<4)` |
+| `OP_SSENDB` | `BBB` | `R(a) = self.send(Syms(b),R(a+1)..,R(a+n+1):R(a+n+2)..,&R(a+n+2k+1))` |
+| `OP_SEND` | `BBB` | `R(a) = R(a).send(Syms(b),R(a+1)..,R(a+n+1):R(a+n+2)..) (c=n|k<<4)` |
+| `OP_SENDB` | `BBB` | `R(a) = R(a).send(Syms(b),R(a+1)..,R(a+n+1):R(a+n+2)..,&R(a+n+2k+1))` |
| `OP_CALL` | `-` | `R(0) = self.call(frame.argc, frame.argv)` |
| `OP_SUPER` | `BB` | `R(a) = super(R(a+1),... ,R(a+b+1))` |
| `OP_ARGARY` | `BS` | `R(a) = argument array (16=m5:r1:m5:d1:lv4)` |
@@ -100,6 +104,7 @@ sign) of operands.
| `OP_ASET` | `BBB` | `R(b)[c] = R(a)` |
| `OP_APOST` | `BBB` | `*R(a),R(a+1)..R(a+c) = R(a)[b..]` |
| `OP_INTERN` | `B` | `R(a) = intern(R(a))` |
+| `OP_SYMBOL` | `BB` | `R(a) = intern(Pool(b))` |
| `OP_STRING` | `BB` | `R(a) = str_dup(Pool(b))` |
| `OP_STRCAT` | `B` | `str_cat(R(a),R(a+1))` |
| `OP_HASH` | `BB` | `R(a) = hash_new(R(a),R(a+1)..R(a+b*2-1))` |
@@ -113,7 +118,7 @@ sign) of operands.
| `OP_OCLASS` | `B` | `R(a) = ::Object` |
| `OP_CLASS` | `BB` | `R(a) = newclass(R(a),Syms(b),R(a+1))` |
| `OP_MODULE` | `BB` | `R(a) = newmodule(R(a),Syms(b))` |
-| `OP_EXEC` | `BB` | `R(a) = blockexec(R(a),Irep[b])` |
+| `OP_EXEC` | `BB` | `R(a) = blockexec(R(a),Irep(b))` |
| `OP_DEF` | `BB` | `R(a).newmethod(Syms(b),R(a+1)); R(a) = Syms(b)` |
| `OP_ALIAS` | `BB` | `alias_method(target_class,Syms(a),Syms(b))` |
| `OP_UNDEF` | `B` | `undef_method(target_class,Syms(a))` |
@@ -121,8 +126,7 @@ sign) of operands.
| `OP_TCLASS` | `B` | `R(a) = target_class` |
| `OP_DEBUG` | `BBB` | `print a,b,c` |
| `OP_ERR` | `B` | `raise(LocalJumpError, Pool(a))` |
-| `OP_EXT1` | `-` | `make 1st operand 16bit` |
-| `OP_EXT2` | `-` | `make 2nd operand 16bit` |
+| `OP_EXT1` | `-` | `make 1st operand (a) 16bit` |
+| `OP_EXT2` | `-` | `make 2nd operand (b) 16bit` |
| `OP_EXT3` | `-` | `make 1st and 2nd operands 16bit` |
| `OP_STOP` | `-` | `stop VM` |
-| ------------------ | -------------- | ---------------------------------------------------------- |

ADD
lib/mruby/doc.rb
+autoload :Pathname, 'pathname'
+
+module MRuby
+ module Documentation
+ def Documentation.update_opcode_md
+ mrubydir = Pathname(MRUBY_ROOT)
+ path_ops_h = mrubydir + "include/mruby/ops.h"
+ path_opcode_md = mrubydir + "doc/internal/opcode.md"
+
+ opspecs = {
+ "Z" => { prefix: "", modified: "-" },
+ "B" => { prefix: "\'" },
+ "BB" => { prefix: "\"" },
+ "BBB" => { prefix: "\"" },
+ "BS" => { prefix: "\'" },
+ "BSS" => { prefix: "\'" },
+ "S" => { prefix: "" },
+ "W" => { prefix: "" },
+ }
+
+ diff = ""
+
+ spliter = <<~'SPLITER'
+ | Instruction Name | Operand type | Semantics |
+ |--------------------|----------------|------------------------------------------------------------|
+ SPLITER
+
+ diff = path_opcode_md.read.sub(/^#{Regexp.escape spliter}.*?(?=\z|^$\n)/m) do
+ repl = spliter
+
+ ops = path_ops_h.read
+ ops.scan(/^\s*OPCODE\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*(?:\/\*\s*(.*?)\s*\*\/\s*)?/).each do |ins, opr, cmt|
+ if cmt
+ cmt.sub!(/\s*#.*/, "")
+ cmt.sub!(/\b(?=L_\w+\b)/, "OP_")
+ cmt.gsub!(/\b(Irep|Pool|R|Syms)\[([^\[\]]+)\]/, "\\1(\\2)")
+ end
+ spec = opspecs[opr] or raise "unknown operand type: #{opr}"
+ item = format(%(| %-18s | %-14s | %-58s |\n), "`OP_#{ins}`", "`#{spec[:modified] || opr}`", cmt && "`#{cmt}`")
+ repl << item
+ end
+
+ repl
+ end
+
+ path_opcode_md.binwrite diff
+ end
+ end
+end

MODIFY
tasks/doc.rake
tasks/doc.rake
+MRuby.autoload :Documentation, 'mruby/doc'
+
desc 'generate document'
task :doc => %w[doc:api doc:capi]
@@ -61,6 +63,18 @@ namespace :doc do
end
end
end
+
+ desc 'update doc/internal/opcode.md'
+ task 'update-opcode.md' do
+ unless system(*%W(git --git-dir #{MRUBY_ROOT}/.git --work-tree #{MRUBY_ROOT} diff --quiet @ -- doc/internal/opcode.md))
+ abort <<~'ERRMESG'
+ The file "doc/internal/opcode.md" has been modified but not committed.
+ To avoid loss of your edits, the automatic update process has been aborted.
+ ERRMESG
+ end
+
+ MRuby::Documentation.update_opcode_md
+ end
end
# deprecated

Add task `rake doc:update-opcode.md`

Allow to update `doc/internal/opcode.md` file mechanically from `include/mruby/ops.h` file.

At the same time, the `doc/internal/opcode.md` file has been updated.
Consecutive hyphens at the end of the table were removed as they would have created noise as markdown flavours.