rubex 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubex'
4
+
5
+ file_name = ARGV[0]
6
+ if File.exists? file_name
7
+ file_name = Dir.pwd + "/#{file_name}"
8
+ end
9
+
10
+ Rubex.compile file_name
@@ -0,0 +1,56 @@
1
+ require 'rubex/code_writer'
2
+ require 'rubex/data_type'
3
+ require 'rubex/constants'
4
+ require 'rubex/ast'
5
+ require 'rubex/symbol_table'
6
+ require 'rubex/parser.racc.rb'
7
+
8
+ module Rubex
9
+ class << self
10
+ def compile path, test=false
11
+ tree = ast path
12
+ target_name = extract_target_name path
13
+ code = generate_code tree, target_name
14
+ ext = extconf target_name
15
+
16
+ return [code, ext] if test
17
+ write_files target_name, code, ext
18
+ end
19
+
20
+ def ast path
21
+ parser = Rubex::Parser.new
22
+ parser.parse(path)
23
+ parser.do_parse
24
+ end
25
+
26
+ def extconf target_name, dir=nil
27
+ extconf = ""
28
+ extconf << "require 'mkmf'\n"
29
+ extconf << "create_makefile('#{target_name}/#{target_name}')\n"
30
+ extconf
31
+ end
32
+
33
+ def generate_code tree, target_name
34
+ code = Rubex::CodeWriter.new target_name
35
+ raise "Must be a Rubex::AST::Node, not #{tree.class}" unless
36
+ tree.is_a? Rubex::AST::Node
37
+ tree.process_statements target_name, code
38
+ code
39
+ end
40
+
41
+ def extract_target_name path
42
+ File.basename(path).split('.')[0]
43
+ end
44
+
45
+ def write_files target_name, code, ext
46
+ Dir.mkdir(target_name)
47
+ code_file = File.new "#{target_name}/#{target_name}.c", "w+"
48
+ code_file.puts code.to_s
49
+ code_file.close
50
+
51
+ extconf_file = File.new "#{target_name}/extconf.rb", "w+"
52
+ extconf_file.puts ext
53
+ extconf_file.close
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubex/ast/node'
2
+ require 'rubex/ast/ruby_method_def'
3
+ require 'rubex/ast/c_base_type'
4
+ require 'rubex/ast/argument_list'
5
+ require 'rubex/ast/statement'
6
+ require 'rubex/ast/expression'
@@ -0,0 +1,20 @@
1
+ module Rubex
2
+ module AST
3
+ class ArgumentList
4
+ include Enumerable
5
+ attr_reader :args
6
+
7
+ def each &block
8
+ @args.each(&block)
9
+ end
10
+
11
+ def initialize
12
+ @args = []
13
+ end
14
+
15
+ def push arg
16
+ @args << arg
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module Rubex
2
+ module AST
3
+ class CBaseType
4
+ attr_reader :type, :name
5
+
6
+ def initialize type, name
7
+ @type, @name = type, name
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Rubex
2
+ module AST
3
+ class Expression
4
+ class Addition
5
+ attr_reader :left, :right
6
+
7
+ def initialize left, right
8
+ @left, @right = left, right
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,71 @@
1
+ module Rubex
2
+ module AST
3
+ class Node
4
+ attr_reader :statements
5
+
6
+ def initialize statements
7
+ @statements = statements.is_a?(Array) ? statements : [statements]
8
+ end
9
+
10
+ def add_child child
11
+ @statements.concat child
12
+ end
13
+
14
+ def process_statements target_name, code
15
+ @scope = Rubex::SymbolTable::Scope::Klass.new 'Object'
16
+ generate_symbol_table_entries
17
+ analyse_expressions
18
+ generate_preamble code
19
+ generate_code code
20
+ generate_init_method target_name, code
21
+ end
22
+
23
+ # Pretty print the AST
24
+ def pp
25
+ # TODO
26
+ end
27
+
28
+ private
29
+
30
+ def generate_preamble code
31
+ code << "#include <ruby.h>\n"
32
+ code << "#include <stdint.h>\n"
33
+ code << "\n"
34
+ end
35
+
36
+ def generate_symbol_table_entries
37
+ @statements.each do |stat|
38
+ stat.generate_symbol_table_entries @scope
39
+ end
40
+ end
41
+
42
+ def analyse_expressions
43
+ @statements.each do |stat|
44
+ stat.analyse_expressions @scope
45
+ end
46
+ end
47
+
48
+ def generate_code code
49
+ @statements.each do |stat|
50
+ stat.generate_code code
51
+ end
52
+ end
53
+
54
+ def generate_init_method target_name, code
55
+ name = "Init_#{target_name}"
56
+ code.new_line
57
+ code.write_func_declaration "void", name, "void"
58
+ code.write_func_definition_header "void", name, "void"
59
+
60
+ @statements.each do |stat|
61
+ if stat.is_a? Rubex::AST::RubyMethodDef
62
+ code.define_instance_method_under @scope, stat.name, stat.c_name
63
+ end
64
+ end
65
+
66
+ code << "\n"
67
+ code << "}\n"
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,84 @@
1
+ module Rubex
2
+ module AST
3
+ class RubyMethodDef
4
+ # Ruby name of the method.
5
+ attr_reader :name
6
+ # The equivalent C name of the method.
7
+ attr_reader :c_name
8
+ # Method arguments.
9
+ attr_reader :args
10
+ # The statments/expressions contained within the method.
11
+ attr_reader :statements
12
+ # Symbol Table entry.
13
+ attr_reader :entry
14
+ # Return type of the function.
15
+ attr_reader :return_type
16
+
17
+ def initialize name, args
18
+ @name, @args = name, args
19
+ @c_name = Rubex::FUNC_PREFIX + name
20
+ @statements = []
21
+ @return_type = Rubex::DataType::RubyObject.new
22
+ end
23
+
24
+ def add_statements statements
25
+ statements.each { |s| @statements << s }
26
+ end
27
+
28
+ def generate_symbol_table_entries outer_scope
29
+ @scope = Rubex::SymbolTable::Scope::Local.new
30
+ @scope.outer_scope = outer_scope
31
+ @scope.return_type = @return_type.dup
32
+ @scope.declare_args @args
33
+ end
34
+
35
+ def analyse_expressions outer_scope
36
+ @statements.each do |stat|
37
+ stat.analyse_expression @scope
38
+ end
39
+ end
40
+
41
+ def generate_code code
42
+ code.write_func_declaration @return_type.to_s, @c_name
43
+ code.write_func_definition_header @return_type.to_s, @c_name
44
+ generate_function_definition code
45
+ code << "}"
46
+ end
47
+
48
+ private
49
+
50
+ def generate_function_definition code
51
+ declare_args code
52
+ generate_arg_checking code
53
+ init_args code
54
+ generate_statements code
55
+ end
56
+
57
+ def generate_statements code
58
+ @statements.each do |stat|
59
+ stat.generate_code code, @scope
60
+ end
61
+ end
62
+
63
+ def declare_args code
64
+ @scope.arg_entries.each do |arg|
65
+ code.declare_variable arg
66
+ end
67
+ end
68
+
69
+ def init_args code
70
+ @scope.arg_entries.each_with_index do |arg, i|
71
+ code << arg.c_name + '=' + arg.type.from_ruby_function + '(' +
72
+ 'argv[' + i.to_s + ']);' + "\n"
73
+ end
74
+ end
75
+
76
+ def generate_arg_checking code
77
+ code << 'if (argc != ' + @scope.arg_entries.size.to_s + ")\n"
78
+ code << "{\n"
79
+ code << %Q{rb_raise(rb_eArgError, "Need #{@scope.arg_entries.size} args, not %d", argc);\n}
80
+ code << "}\n"
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,54 @@
1
+ module Rubex
2
+ module AST
3
+ class Statement
4
+ class Return
5
+ attr_reader :expression, :return_type
6
+
7
+ def initialize expression
8
+ @expression = expression
9
+ end
10
+
11
+ def analyse_expression local_scope
12
+ case @expression
13
+ when Rubex::AST::Expression::Addition
14
+ left = @expression.left
15
+ right = @expression.right
16
+ end
17
+
18
+ left_type = local_scope[left].type
19
+ right_type = local_scope[right].type
20
+
21
+ @return_type = result_type_for left_type, right_type
22
+ # TODO: Raise error if return_type is not compatible with the return
23
+ # type of the function.
24
+ end
25
+
26
+ def generate_code code, local_scope
27
+ code << "return "
28
+ case @expression
29
+ when Rubex::AST::Expression::Addition
30
+ left = @expression.left
31
+ right = @expression.right
32
+ code << @return_type.to_ruby_function
33
+ code << "("
34
+ code << local_scope[left].c_name
35
+ code << " + "
36
+ code << local_scope[right].c_name
37
+ code << ")"
38
+ code << ";\n"
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def result_type_for left_type, right_type
45
+ dtype = Rubex::DataType
46
+
47
+ if left_type.is_a?(dtype::CInt32) && right_type.is_a?(dtype::CInt32)
48
+ return dtype::CInt32.new
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,67 @@
1
+ module Rubex
2
+ class CodeWriter
3
+ attr_reader :code
4
+
5
+ def initialize target_name
6
+ @code = "/* C extension for #{target_name}.\n"\
7
+ "This file in generated by Rubex. Do not change!\n"\
8
+ "*/\n"
9
+ @indent = 0
10
+ end
11
+
12
+ def write_func_declaration return_type, c_name, args=""
13
+ write_func_prototype return_type, c_name, args
14
+ @code << ";"
15
+ new_line
16
+ end
17
+
18
+ def write_func_definition_header return_type, c_name, args=""
19
+ write_func_prototype return_type, c_name, args
20
+ @code << "\n"
21
+ @code << "{\n"
22
+ end
23
+
24
+ def declare_variable var
25
+ @code << "#{var.type.to_s} #{var.c_name};\n"
26
+ end
27
+
28
+ def << s
29
+ @code << s
30
+ end
31
+
32
+ def new_line
33
+ @code << "\n"
34
+ end
35
+
36
+ def indent
37
+ @indent += 1
38
+ end
39
+
40
+ def dedent
41
+ raise "Cannot dedent, already 0." if @indent == 0
42
+ @indent -= 1
43
+ end
44
+
45
+ def define_instance_method_under scope, name, c_name
46
+ @code << "rb_define_method(" + scope.c_name + " ,\"" + name + "\", " +
47
+ c_name + ", -1);\n"
48
+ end
49
+
50
+ def to_s
51
+ @code
52
+ end
53
+
54
+ private
55
+
56
+ def write_func_prototype return_type, c_name, args
57
+ @code << "#{return_type} #{c_name} "
58
+ @code << "("
59
+ if args.empty?
60
+ @code << "int argc, VALUE* argv, VALUE #{Rubex::ARG_PREFIX}self"
61
+ else
62
+ @code << args
63
+ end
64
+ @code << ")"
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,17 @@
1
+ module Rubex
2
+ RUBEX_PREFIX = "__rubex_"
3
+
4
+ FUNC_PREFIX = RUBEX_PREFIX + "f_"
5
+ VAR_PREFIX = RUBEX_PREFIX + "v_"
6
+ CLASS_PREFIX = RUBEX_PREFIX + "c_"
7
+ ARG_PREFIX = RUBEX_PREFIX + "arg_"
8
+
9
+ TYPE_MAPPINGS = {
10
+ 'i32' => Rubex::DataType::CInt32,
11
+ 'object' => Rubex::DataType::RubyObject
12
+ }
13
+
14
+ CLASS_MAPPINGS = {
15
+ 'Object' => 'rb_cObject'
16
+ }
17
+ end
@@ -0,0 +1,15 @@
1
+ module Rubex
2
+ module DataType
3
+ class RubyObject
4
+ def to_s; "VALUE"; end
5
+ end
6
+
7
+ class CInt32
8
+ def to_s; "int32_t"; end
9
+
10
+ def to_ruby_function; "INT2NUM"; end
11
+
12
+ def from_ruby_function; "NUM2INT"; end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ class Rubex::Lexer
2
+ macros
3
+ DEF /def/
4
+ RETURN /return/
5
+
6
+ IDENTIFIER /[a-z_][a-zA-Z_0-9]*/
7
+ LPAREN /\(/
8
+ RPAREN /\)/
9
+ NL /\n/
10
+ COMMA /,/
11
+
12
+ # operators
13
+ EXPO /\*\*/
14
+ MULTIPLY /\*/
15
+ DIVIDE /\//
16
+ PLUS /\+/
17
+ MINUS /\-/
18
+ MODULUS /%/
19
+ EQUAL /=/
20
+ rules
21
+ /#{DEF}/ { [:kDEF, text] }
22
+ /end/ { [:kEND, text] }
23
+ /#{RETURN}/ { [:kRETURN, text] }
24
+
25
+ /i32/ { [:kDTYPE_I32, text] }
26
+
27
+ /#{IDENTIFIER}/ { [:tIDENTIFIER, text] }
28
+ /#{LPAREN}/ { [:tLPAREN, text] }
29
+ /#{RPAREN}/ { [:tRPAREN, text] }
30
+ /#{NL}/ { [:tNL, text] }
31
+ /#{COMMA}/ { [:tCOMMA, text] }
32
+
33
+ # operators
34
+
35
+ /#{PLUS}/ { [:tPLUS, text]}
36
+ /#{MINUS}/ { [:tMINUS, text]}
37
+ /#{MULTIPLY}/ { [:tMULTIPLY, text]}
38
+ /#{DIVIDE}/ { [:tDIVIDE, text]}
39
+ /#{EXPO}/ { [:tEXPO, text]}
40
+ /#{MODULUS}/ { [:tMODULUS, text]}
41
+ /#{EXPO}/ { [:tEXPO, text]}
42
+
43
+ # whitespace
44
+
45
+ / / {}
46
+ inner
47
+ def do_parse
48
+ # this is a stub since oedipus lex uses this internally.
49
+ end
50
+ end # Rubex::Lexer