microruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+