superinstance-flux-runtime 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/superinstance/flux-runtime/assembler.rb +305 -0
- data/lib/superinstance/flux-runtime/cli.rb +190 -0
- data/lib/superinstance/flux-runtime/disassembler.rb +197 -0
- data/lib/superinstance/flux-runtime/exceptions.rb +49 -0
- data/lib/superinstance/flux-runtime/flux_vm.rb +1020 -0
- data/lib/superinstance/flux-runtime/loader.rb +55 -0
- data/lib/superinstance/flux-runtime/opcode.rb +141 -0
- data/lib/superinstance/flux-runtime/runtime/agent.rb +128 -0
- data/lib/superinstance/flux-runtime/runtime/opcode.rb +57 -0
- data/lib/superinstance/flux-runtime/version.rb +8 -0
- data/lib/superinstance-flux-runtime.rb +22 -0
- metadata +70 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Flux
|
|
4
|
+
# Binary loader for FLUX bytecode files
|
|
5
|
+
class Loader
|
|
6
|
+
FLUX_MAGIC = 'FLUX'.b
|
|
7
|
+
|
|
8
|
+
# Load a FLUX bytecode file
|
|
9
|
+
# Returns raw bytecode, stripping the FLUX header if present
|
|
10
|
+
def load_file(path)
|
|
11
|
+
data = File.binread(path)
|
|
12
|
+
|
|
13
|
+
if data.start_with?(FLUX_MAGIC)
|
|
14
|
+
strip_header(data)
|
|
15
|
+
else
|
|
16
|
+
data
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Check if file has FLUX header
|
|
21
|
+
def has_header?(path)
|
|
22
|
+
data = File.binread(path, 4)
|
|
23
|
+
data == FLUX_MAGIC
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Parse header information
|
|
27
|
+
def parse_header(path)
|
|
28
|
+
data = File.binread(path)
|
|
29
|
+
|
|
30
|
+
unless data.start_with?(FLUX_MAGIC)
|
|
31
|
+
return nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
magic: data[0..3],
|
|
36
|
+
version_major: data.getbyte(4) | (data.getbyte(5) << 8),
|
|
37
|
+
version_minor: data.getbyte(6) | (data.getbyte(7) << 8),
|
|
38
|
+
flags: data.getbyte(8) | (data.getbyte(9) << 8),
|
|
39
|
+
entry_point: data.getbyte(10) | (data.getbyte(11) << 8) |
|
|
40
|
+
(data.getbyte(12) << 16) | (data.getbyte(13) << 24),
|
|
41
|
+
reserved: data[14..17]
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def strip_header(data)
|
|
48
|
+
# FLUX header is 16 bytes
|
|
49
|
+
# Magic (4) + Version (2) + Flags (2) + Entry point (4) + Reserved (4)
|
|
50
|
+
return data[16..] if data.bytesize > 16
|
|
51
|
+
|
|
52
|
+
data
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'exceptions'
|
|
4
|
+
|
|
5
|
+
module Flux
|
|
6
|
+
# Opcode registry mapping opcode byte values to method names
|
|
7
|
+
# and providing all core opcode implementations
|
|
8
|
+
module OpcodeRegistry
|
|
9
|
+
OPCODE_CLASSES = {
|
|
10
|
+
# Control Flow (0x00-0x0F)
|
|
11
|
+
0x00 => :Halt,
|
|
12
|
+
0x01 => :Nop,
|
|
13
|
+
0x02 => :Ret,
|
|
14
|
+
0x03 => :Jump,
|
|
15
|
+
0x04 => :JumpIf,
|
|
16
|
+
0x05 => :JumpIfNot,
|
|
17
|
+
0x06 => :Call,
|
|
18
|
+
0x07 => :CallIndirect,
|
|
19
|
+
0x08 => :Yield,
|
|
20
|
+
0x09 => :Panic,
|
|
21
|
+
0x0A => :Unreachable,
|
|
22
|
+
|
|
23
|
+
# Stack Operations (0x10-0x1F)
|
|
24
|
+
0x10 => :Push,
|
|
25
|
+
0x11 => :Pop,
|
|
26
|
+
0x12 => :Dup,
|
|
27
|
+
0x13 => :Swap,
|
|
28
|
+
|
|
29
|
+
# Integer Arithmetic (0x20-0x3F)
|
|
30
|
+
0x20 => :IMov,
|
|
31
|
+
0x21 => :IAdd,
|
|
32
|
+
0x22 => :ISub,
|
|
33
|
+
0x23 => :IMul,
|
|
34
|
+
0x24 => :IDiv,
|
|
35
|
+
0x25 => :IMod,
|
|
36
|
+
0x26 => :INeg,
|
|
37
|
+
0x27 => :IAbs,
|
|
38
|
+
0x28 => :IInc,
|
|
39
|
+
0x29 => :IDec,
|
|
40
|
+
0x2A => :IMin,
|
|
41
|
+
0x2B => :IMax,
|
|
42
|
+
0x2C => :IAnd,
|
|
43
|
+
0x2D => :IOr,
|
|
44
|
+
0x2E => :IXor,
|
|
45
|
+
0x2F => :IShl,
|
|
46
|
+
0x30 => :IShr,
|
|
47
|
+
0x31 => :INot,
|
|
48
|
+
0x32 => :ICmpEq,
|
|
49
|
+
0x33 => :ICmpNe,
|
|
50
|
+
0x34 => :ICmpLt,
|
|
51
|
+
0x35 => :ICmpLe,
|
|
52
|
+
0x36 => :ICmpGt,
|
|
53
|
+
0x37 => :ICmpGe,
|
|
54
|
+
|
|
55
|
+
# Float Arithmetic (0x40-0x5F)
|
|
56
|
+
0x40 => :FMov,
|
|
57
|
+
0x41 => :FAdd,
|
|
58
|
+
0x42 => :FSub,
|
|
59
|
+
0x43 => :FMul,
|
|
60
|
+
0x44 => :FDiv,
|
|
61
|
+
0x45 => :FMod,
|
|
62
|
+
0x46 => :FNeg,
|
|
63
|
+
0x47 => :FAbs,
|
|
64
|
+
0x48 => :FSqrt,
|
|
65
|
+
0x49 => :FFloor,
|
|
66
|
+
0x4A => :FCeil,
|
|
67
|
+
0x4B => :FRound,
|
|
68
|
+
0x4C => :FMin,
|
|
69
|
+
0x4D => :FMax,
|
|
70
|
+
0x4E => :FSin,
|
|
71
|
+
0x4F => :FCos,
|
|
72
|
+
0x50 => :FExp,
|
|
73
|
+
0x51 => :FLog,
|
|
74
|
+
0x52 => :FClamp,
|
|
75
|
+
0x53 => :FLerp,
|
|
76
|
+
0x54 => :FCmpEq,
|
|
77
|
+
0x55 => :FCmpNe,
|
|
78
|
+
0x56 => :FCmpLt,
|
|
79
|
+
0x57 => :FCmpLe,
|
|
80
|
+
0x58 => :FCmpGt,
|
|
81
|
+
0x59 => :FCmpGe,
|
|
82
|
+
|
|
83
|
+
# Conversions (0x60-0x6F)
|
|
84
|
+
0x60 => :IToF,
|
|
85
|
+
0x61 => :FToI,
|
|
86
|
+
0x62 => :BToI,
|
|
87
|
+
0x63 => :IToB,
|
|
88
|
+
|
|
89
|
+
# Memory Operations (0x70-0x7F)
|
|
90
|
+
0x70 => :Load8,
|
|
91
|
+
0x71 => :Load16,
|
|
92
|
+
0x72 => :Load32,
|
|
93
|
+
0x73 => :Load64,
|
|
94
|
+
0x74 => :Store8,
|
|
95
|
+
0x75 => :Store16,
|
|
96
|
+
0x76 => :Store32,
|
|
97
|
+
0x77 => :Store64,
|
|
98
|
+
0x78 => :LoadAddr,
|
|
99
|
+
0x79 => :StackAlloc,
|
|
100
|
+
|
|
101
|
+
# Agent-to-Agent Communication (0x80-0x8F)
|
|
102
|
+
0x80 => :ASend,
|
|
103
|
+
0x81 => :ARecv,
|
|
104
|
+
0x82 => :AAsk,
|
|
105
|
+
0x83 => :ATell,
|
|
106
|
+
0x84 => :ADelegate,
|
|
107
|
+
0x85 => :ABroadcast,
|
|
108
|
+
0x86 => :ASubscribe,
|
|
109
|
+
0x87 => :AWait,
|
|
110
|
+
0x88 => :ATrust,
|
|
111
|
+
0x89 => :AVerify,
|
|
112
|
+
|
|
113
|
+
# Type/Meta Operations (0x90-0x9F)
|
|
114
|
+
0x90 => :Cast,
|
|
115
|
+
0x91 => :SizeOf,
|
|
116
|
+
0x92 => :TypeOf,
|
|
117
|
+
|
|
118
|
+
# Bitwise Operations (0xA0-0xAF)
|
|
119
|
+
0xA0 => :BAnd,
|
|
120
|
+
0xA1 => :BOr,
|
|
121
|
+
0xA2 => :BXor,
|
|
122
|
+
0xA3 => :BShl,
|
|
123
|
+
0xA4 => :BShr,
|
|
124
|
+
0xA5 => :BNot,
|
|
125
|
+
|
|
126
|
+
# Vector/SIMD Operations (0xB0-0xBF)
|
|
127
|
+
0xB0 => :VLoad,
|
|
128
|
+
0xB1 => :VStore,
|
|
129
|
+
0xB2 => :VAdd,
|
|
130
|
+
0xB3 => :VMul,
|
|
131
|
+
0xB4 => :VDot
|
|
132
|
+
}.freeze
|
|
133
|
+
|
|
134
|
+
OPCODE_NAMES = OPCODE_CLASSES.transform_values(&:to_s).freeze
|
|
135
|
+
|
|
136
|
+
# Get opcode name from byte
|
|
137
|
+
def self.opcode_name(opcode_byte)
|
|
138
|
+
OPCODE_NAMES[opcode_byte] || "Unknown_0x#{opcode_byte.to_s(16).upcase}"
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../flux_vm'
|
|
4
|
+
|
|
5
|
+
module Flux
|
|
6
|
+
module Runtime
|
|
7
|
+
# Agent shell that wraps a FluxVM and provides method_missing
|
|
8
|
+
# for PLATO-based capability lookup
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
# agent = Flux::Runtime::Agent.new
|
|
12
|
+
# agent.load(bytecode)
|
|
13
|
+
# agent.run
|
|
14
|
+
#
|
|
15
|
+
# @example with PLATO
|
|
16
|
+
# client = PLATO::Client.new
|
|
17
|
+
# agent = Flux::Runtime::Agent.new(plato_client: client, vessel_id: 'my-agent')
|
|
18
|
+
#
|
|
19
|
+
# # Unknown method triggers PLATO lookup
|
|
20
|
+
# result = agent.learned_capability(arg1, arg2)
|
|
21
|
+
#
|
|
22
|
+
class Agent
|
|
23
|
+
attr_reader :vm, :vessel_id
|
|
24
|
+
|
|
25
|
+
def initialize(plato_client: nil, vessel_id: nil)
|
|
26
|
+
@vm = FluxVM.new
|
|
27
|
+
@plato = plato_client
|
|
28
|
+
@vessel_id = vessel_id
|
|
29
|
+
@capabilities = {}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Load bytecode into the VM
|
|
33
|
+
def load(bytecode)
|
|
34
|
+
@vm.load(bytecode)
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Run the VM
|
|
39
|
+
def run(max_cycles: nil)
|
|
40
|
+
@vm.run(max_cycles: max_cycles)
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Step one instruction
|
|
45
|
+
def step
|
|
46
|
+
@vm.step
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Reset the VM
|
|
51
|
+
def reset
|
|
52
|
+
@vm.reset
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Get current state
|
|
57
|
+
def state
|
|
58
|
+
@vm.state
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Get register values
|
|
62
|
+
def regs
|
|
63
|
+
@vm.regs
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Get execution stats
|
|
67
|
+
def stats
|
|
68
|
+
@vm.stats
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Delegate unknown methods to VM if they exist there
|
|
72
|
+
# Otherwise, look up in PLATO
|
|
73
|
+
def method_missing(method_name, *args, &block)
|
|
74
|
+
# Check if it's a VM method
|
|
75
|
+
if @vm.respond_to?(method_name)
|
|
76
|
+
@vm.send(method_name, *args, &block)
|
|
77
|
+
else
|
|
78
|
+
# Look up capability in PLATO
|
|
79
|
+
capability = lookup_capability(method_name)
|
|
80
|
+
|
|
81
|
+
if capability
|
|
82
|
+
execute_capability(capability, *args, &block)
|
|
83
|
+
else
|
|
84
|
+
super
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Proper introspection support
|
|
90
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
91
|
+
@vm.respond_to?(method_name, include_private) ||
|
|
92
|
+
lookup_capability(method_name) ||
|
|
93
|
+
super
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
# Look up a capability by name in PLATO
|
|
99
|
+
def lookup_capability(capability_name)
|
|
100
|
+
return nil unless @plato && @vessel_id
|
|
101
|
+
|
|
102
|
+
@capabilities[capability_name] ||= @plato.query_tiles(
|
|
103
|
+
"capabilities:#{@vessel_id}",
|
|
104
|
+
capability_name.to_s
|
|
105
|
+
).first
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Execute a capability from PLATO
|
|
109
|
+
def execute_capability(capability, *args, &block)
|
|
110
|
+
# Capability is a PLATO tile containing:
|
|
111
|
+
# - opcode: the FLUX opcode to execute
|
|
112
|
+
# - handler: Ruby code to run
|
|
113
|
+
if capability.is_a?(Hash)
|
|
114
|
+
if capability[:handler]
|
|
115
|
+
instance_exec(*args, capability[:handler], &capability[:handler])
|
|
116
|
+
elsif capability[:opcode]
|
|
117
|
+
@vm.send("op#{capability[:opcode]}", *args)
|
|
118
|
+
else
|
|
119
|
+
raise ArgumentError, 'Capability must have :handler or :opcode'
|
|
120
|
+
end
|
|
121
|
+
else
|
|
122
|
+
# Assume it's executable
|
|
123
|
+
capability.call(*args)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../flux_vm'
|
|
4
|
+
|
|
5
|
+
module Flux
|
|
6
|
+
module Runtime
|
|
7
|
+
# Runtime opcode registration module
|
|
8
|
+
# Allows Ruby code to add custom FLUX opcodes dynamically
|
|
9
|
+
class Opcode
|
|
10
|
+
class << self
|
|
11
|
+
attr_accessor :opcode_id, :format, :execute_block
|
|
12
|
+
|
|
13
|
+
# Define a new opcode at runtime
|
|
14
|
+
# @param opcode_id [Integer] 0-255 opcode number
|
|
15
|
+
# @param format [Symbol] :A, :B, :C, :D, :E, or :G
|
|
16
|
+
# @param block [Proc] execution block receiving vm and operands
|
|
17
|
+
#
|
|
18
|
+
# @example
|
|
19
|
+
# Flux::Runtime::Opcode.define(0xF0, format: :C) do |vm, rd, ra, rb|
|
|
20
|
+
# vm.gp[rd] = vm.gp[ra] + vm.gp[rb] * 2
|
|
21
|
+
# end
|
|
22
|
+
def define(opcode_id, format: :C, &block)
|
|
23
|
+
@opcode_id = opcode_id
|
|
24
|
+
@format = format
|
|
25
|
+
@execute_block = block
|
|
26
|
+
|
|
27
|
+
# Register with VM
|
|
28
|
+
FluxVM.register_opcode(self)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Execute this opcode on a VM
|
|
32
|
+
def execute(vm, *operands)
|
|
33
|
+
@execute_block.call(vm, *operands)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Create and register in one call
|
|
37
|
+
def create(opcode_id, format: :C, &block)
|
|
38
|
+
Class.new(self) do
|
|
39
|
+
define(opcode_id, format: format, &block)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# DSL for defining opcodes
|
|
46
|
+
module OpcodeDSL
|
|
47
|
+
def define_opcode(opcode_id, format: :C, &block)
|
|
48
|
+
Opcode.define(opcode_id, format: format, &block)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Convenience: include in any class to get define_opcode method
|
|
55
|
+
module FluxRuntimeOpcodeDSL
|
|
56
|
+
include Flux::Runtime::OpcodeDSL
|
|
57
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Flux
|
|
4
|
+
VERSION = '1.0.0'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require_relative 'superinstance/flux-runtime/version'
|
|
8
|
+
require_relative 'superinstance/flux-runtime/flux_vm'
|
|
9
|
+
require_relative 'superinstance/flux-runtime/opcode'
|
|
10
|
+
require_relative 'superinstance/flux-runtime/assembler'
|
|
11
|
+
require_relative 'superinstance/flux-runtime/disassembler'
|
|
12
|
+
require_relative 'superinstance/flux-runtime/loader'
|
|
13
|
+
require_relative 'superinstance/flux-runtime/exceptions'
|
|
14
|
+
require_relative 'superinstance/flux-runtime/runtime/opcode'
|
|
15
|
+
require_relative 'superinstance/flux-runtime/runtime/agent'
|
|
16
|
+
require_relative 'superinstance/flux-runtime/cli'
|
|
17
|
+
|
|
18
|
+
module Superinstance
|
|
19
|
+
module Flux
|
|
20
|
+
Runtime = Flux
|
|
21
|
+
end
|
|
22
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: superinstance-flux-runtime
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- SuperInstance
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-05-04 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rspec
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.12'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '3.12'
|
|
27
|
+
description: |
|
|
28
|
+
A pure Ruby implementation of the FLUX ISA v3.0 virtual machine.
|
|
29
|
+
Supports register-based execution, bytecode loading, assembly/disassembly,
|
|
30
|
+
and runtime metaprogramming for agent capabilities.
|
|
31
|
+
email: engineering@superinstance.dev
|
|
32
|
+
executables: []
|
|
33
|
+
extensions: []
|
|
34
|
+
extra_rdoc_files: []
|
|
35
|
+
files:
|
|
36
|
+
- lib/superinstance-flux-runtime.rb
|
|
37
|
+
- lib/superinstance/flux-runtime/assembler.rb
|
|
38
|
+
- lib/superinstance/flux-runtime/cli.rb
|
|
39
|
+
- lib/superinstance/flux-runtime/disassembler.rb
|
|
40
|
+
- lib/superinstance/flux-runtime/exceptions.rb
|
|
41
|
+
- lib/superinstance/flux-runtime/flux_vm.rb
|
|
42
|
+
- lib/superinstance/flux-runtime/loader.rb
|
|
43
|
+
- lib/superinstance/flux-runtime/opcode.rb
|
|
44
|
+
- lib/superinstance/flux-runtime/runtime/agent.rb
|
|
45
|
+
- lib/superinstance/flux-runtime/runtime/opcode.rb
|
|
46
|
+
- lib/superinstance/flux-runtime/version.rb
|
|
47
|
+
homepage: https://github.com/SuperInstance/superinstance-flux-runtime
|
|
48
|
+
licenses:
|
|
49
|
+
- MIT
|
|
50
|
+
metadata: {}
|
|
51
|
+
post_install_message:
|
|
52
|
+
rdoc_options: []
|
|
53
|
+
require_paths:
|
|
54
|
+
- lib
|
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '3.0'
|
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
|
+
requirements:
|
|
62
|
+
- - ">="
|
|
63
|
+
- !ruby/object:Gem::Version
|
|
64
|
+
version: '0'
|
|
65
|
+
requirements: []
|
|
66
|
+
rubygems_version: 3.3.5
|
|
67
|
+
signing_key:
|
|
68
|
+
specification_version: 4
|
|
69
|
+
summary: Pure Ruby FLUX ISA v3.0 virtual machine with runtime metaprogramming
|
|
70
|
+
test_files: []
|