microruby 0.0.1

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.
data/bin/microruby ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ require 'microruby'
3
+
4
+ cmd = ARGV.shift
5
+ abort "Missing command" if cmd.nil?
6
+
7
+ case cmd.downcase.to_sym
8
+ when :compile
9
+ path = ARGV.shift
10
+ abort "Missing file path" if path.nil?
11
+ MicroRuby.compile_file(path)
12
+ else
13
+ abort "Unknown command: #{cmd}"
14
+ end
15
+
16
+
17
+
data/lib/microruby.rb ADDED
@@ -0,0 +1,26 @@
1
+ require_relative "microruby/bytecode"
2
+
3
+ class MicroRuby
4
+
5
+ def self.compile_file(path)
6
+ raise "File not found: #{path}" unless File.file?(path)
7
+
8
+ dir = File.dirname(path)
9
+ filename = File.basename(path, ".rb")
10
+
11
+ bc = compile File.read(path)
12
+
13
+ target_path = "#{dir}/#{filename}.mrbc"
14
+ File.open(target_path, "w") do |f|
15
+ f.write(bc)
16
+ puts "Compiled to #{target_path}"
17
+ end
18
+
19
+ end
20
+
21
+ def self.compile(code)
22
+ seq = RubyVM::InstructionSequence.compile(code).to_a
23
+ Bytecode.encode(seq).to_bin
24
+ end
25
+
26
+ end
@@ -0,0 +1,156 @@
1
+
2
+ require_relative "instruction_set"
3
+
4
+ class Bytecode
5
+
6
+ TYPES = {
7
+ :null => 0,
8
+ :int8 => 1,
9
+ :int16 => 2,
10
+ :int32 => 3,
11
+ :uint8 => 4,
12
+ :uint16 => 5,
13
+ :uint32 => 6,
14
+ :float => 7,
15
+ :double => 8,
16
+ :bool => 9,
17
+ :string => 10,
18
+ :array => 11
19
+ }
20
+
21
+ attr_accessor :arg_size
22
+ attr_accessor :local_size
23
+ attr_accessor :stack_max
24
+ attr_accessor :inst_seq
25
+ attr_accessor :bytes
26
+
27
+
28
+ def initialize
29
+ @bytes = []
30
+ end
31
+
32
+
33
+ def self.encode(sequence)
34
+ bc = Bytecode.new
35
+ bc.arg_size = sequence[4][:arg_size]
36
+ bc.local_size = sequence[4][:local_size]
37
+ bc.stack_max = sequence[4][:stack_max]
38
+ # TODO: preserve line numbers (optionally)
39
+ instructions = sequence[13].find_all {|i| i.is_a?(Array)}
40
+ instructions.each do |i|
41
+ bc.bytes += encode_instruction(i)
42
+ end
43
+ bc
44
+ end
45
+
46
+
47
+ def to_bin
48
+ self.bytes.pack("C*")
49
+ end
50
+
51
+
52
+ private
53
+
54
+
55
+ def self.encode_instruction(instruction)
56
+
57
+ inst_bytes = []
58
+ opcode = instruction[0]
59
+
60
+ inst_def = INSTRUCTIONS[opcode]
61
+
62
+ if inst_def
63
+
64
+ inst_bytes << inst_def[0]
65
+
66
+ if [:putobject, :putstring].include?(opcode)
67
+ # literal object - requires special encoding
68
+ val = instruction[1]
69
+ inst_bytes += encode_object(val)
70
+ elsif [:trace, :setlocal, :getlocal, :opt_plus, :opt_minus, :opt_mult, :opt_div].include?(opcode)
71
+ # simple operand opcodes
72
+ inst_bytes += instruction[1..-1]
73
+ elsif [:nop, :dup, :leave].include?(opcode)
74
+ # zero operand opcodes
75
+ end
76
+
77
+ else
78
+ raise "Unexpected opcode (#{opcode})"
79
+ end
80
+
81
+ inst_bytes
82
+
83
+ end
84
+
85
+
86
+ def self.encode_object(val)
87
+ val_bytes = []
88
+
89
+ case val
90
+ when NilClass
91
+ val_bytes << TYPES[:null]
92
+ # empty value
93
+
94
+ when FalseClass
95
+ val_bytes << TYPES[:bool]
96
+ val_bytes << 0
97
+ when TrueClass
98
+ val_bytes << TYPES[:bool]
99
+ val_bytes << 1
100
+
101
+ when Fixnum
102
+ if val >= 0
103
+ # unsigned
104
+ if val < 2**8
105
+ val_bytes << TYPES[:uint8]
106
+ val_bytes += [val].pack("C").unpack("C*")
107
+ elsif val < 2**16
108
+ val_bytes << TYPES[:uint16]
109
+ val_bytes += [val].pack("S>").unpack("C*")
110
+ elsif val < 2**32
111
+ val_bytes << TYPES[:uint32]
112
+ val_bytes += [val].pack("L>").unpack("C*")
113
+ else
114
+ raise "64 bit integers not supported... yet."
115
+ end
116
+ else
117
+ # signed
118
+ if val.abs < 2**7
119
+ val_bytes << TYPES[:int8]
120
+ val_bytes += [val].pack("c").unpack("C*")
121
+ elsif val.abs < 2**15
122
+ val_bytes << TYPES[:int16]
123
+ val_bytes += [val].pack("s>").unpack("C*")
124
+ elsif val.abs < 2**31
125
+ val_bytes << TYPES[:int32]
126
+ val_bytes += [val].pack("l>").unpack("C*")
127
+ else
128
+ raise "64 bit integers not supported... yet."
129
+ end
130
+ end
131
+
132
+ when Float
133
+ # TODO: add single-precision support
134
+ val_bytes << TYPES[:double]
135
+ val_bytes += [val].pack("G").unpack("C*")
136
+
137
+ when String
138
+ # TODO: support for strings larger than 255 bytes
139
+ val_bytes << TYPES[:string]
140
+ val_bytes << val.length
141
+ val_bytes += val.bytes.to_a
142
+
143
+ when Array
144
+ # TODO: support for arrays larger than 255 bytes
145
+ val_bytes << TYPES[:array]
146
+ val_bytes << val.length
147
+ val.each do |v|
148
+ val_bytes += encode_object(v)
149
+ end
150
+ end
151
+
152
+ val_bytes
153
+ end
154
+
155
+
156
+ end
@@ -0,0 +1,22 @@
1
+
2
+ class Bytecode
3
+
4
+ INSTRUCTIONS = {
5
+ # opcode key => [opcode value, operand count]
6
+ :nop => [0, 0],
7
+ :getlocal => [1, 1],
8
+ :setlocal => [2, 1],
9
+ :putobject => [17, 1],
10
+ :putstring => [18, 1],
11
+ :dup => [31, 0],
12
+ :trace => [43, 1],
13
+ :leave => [48, 0],
14
+ :opt_plus => [59, 1],
15
+ :opt_minus => [60, 1],
16
+ :opt_mult => [61, 1],
17
+ :opt_div => [62, 1],
18
+ :newarray => [22, 1],
19
+ :expandarray => [24, 1]
20
+ }
21
+
22
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: microruby
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Mark Lyons
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-12-03 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: MicroRuby compiles Ruby to compact bytecode for execution on embedded microcontrollers.
17
+ email: mark@microruby.com
18
+ executables:
19
+ - microruby
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/microruby/bytecode.rb
26
+ - lib/microruby/instruction_set.rb
27
+ - lib/microruby.rb
28
+ - bin/microruby
29
+ homepage: http://microruby.com
30
+ licenses: []
31
+
32
+ post_install_message: "Warning: This is an alpha release! Opcode support is limited."
33
+ rdoc_options: []
34
+
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.9.2
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.8.24
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: MicroRuby compiler
56
+ test_files: []
57
+