require 'compiler/duby'
module Duby
module Compiler
class C
class MathCompiler
def call(compiler, name, recv, args)
recv.call
compiler.src << " #{name} "
args.call
end
end
attr_accessor :filename, :src
def initialize(filename)
@filename = filename
@src = ""
self.type_mapper[AST::TypeReference.new(:fixnum)] = "int"
self.call_compilers[AST::TypeReference.new(:fixnum)] = MathCompiler.new
end
def compile(ast)
ast.compile(this)
end
def define_method(name, signature, args, body)
@src << "#{type_mapper[signature[:return]]} #{name}("
args.call
@src << ") {"
body.call
@src << "}\n\n"
end
def declare_argument(name, type)
@src << "#{type_mapper[type]} #{name}"
end
def branch(condition, body_proc, else_proc)
@src << "if ("
condition.call
@src << ") {"
body_proc.call
if else_proc
@src << "} else {"
else_proc.call
end
@src << "}"
end
def call(name, recv_type, recv, args)
call_compilers[recv_type].call(self, name, recv, args)
end
def call_compilers
@call_compilers ||= {}
end
def self_call(name, args)
@src << "#{name}("
args.call
@src << ")"
end
def local(name)
@src << name
end
def fixnum(value)
@src << value.to_s
end
def newline
@src << ";\n"
end
def ret
@src << "return "
yield
end
def generate
@src
end
def type_mapper
@type_mapper ||= {}
end
end
end
module AST
class Script
def compile(compiler)
body.compile(compiler)
end
end
class Body
def compile(compiler)
last = children[-1]
children.each do |child|
child.compile(compiler)
compiler.newline
end
end
end
class MethodDefinition
def compile(compiler)
args_callback = proc {arguments.compile(compiler)}
body_callback = proc {body.compile(compiler)}
compiler.define_method(name, signature, args_callback, body_callback)
end
end
class Arguments
def compile(compiler)
args.each {|arg| compiler.declare_argument(arg.name, arg.inferred_type)} if args
end
end
class Noop
def compile(compiler)
end
end
class Fixnum
def compile(compiler)
compiler.fixnum(literal)
end
end
class If
def compile(compiler)
cond_callback = proc { condition.compile(compiler) }
body_callback = proc { body.compile(compiler) }
else_callback = proc { self.else.compile(compiler)}
compiler.branch(cond_callback, body_callback, else_callback)
end
end
class Condition
def compile(compiler)
predicate.compile(compiler)
end
end
class FunctionalCall
def compile(compiler)
args_callback = proc { parameters.each {|param| param.compile(compiler)}}
compiler.self_call(name, args_callback)
end
end
class Call
def compile(compiler)
recv_callback = proc { target.compile(compiler) }
args_callback = proc { parameters.each {|param| param.compile(compiler)}}
compiler.call(name, target.inferred_type, recv_callback, args_callback)
end
end
class Local
def compile(compiler)
compiler.local(name)
end
end
end
end
if __FILE__ == $0
ast = Duby::AST.parse(File.read(ARGV[0]))
typer = Duby::Typer::Simple.new(:script)
ast.infer(typer)
typer.resolve(true)
compiler = Duby::Compiler::C.new("#{ARGV[0]}.c")
ast.compile(compiler)
File.open(compiler.filename, "w") {|file| file.write(compiler.generate)}
end