Skip to content

Commit

Permalink
add redparse compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
quix committed Jan 15, 2010
1 parent 937fbcf commit 8adf2a2
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 0 deletions.
62 changes: 62 additions & 0 deletions lib/pure/compiler/red_parse.rb
@@ -0,0 +1,62 @@
#
# This file is self-contained, intended for use by an external server.
#
# It is not included by the top-level pure.rb.
#

require 'pure/version'
require 'pure/names'
require 'redparse'

module Pure
module Compiler #:nodoc:
class RedParse #:nodoc:
#
# Compiles and evaluates a function spec with arg values.
#
def evaluate_function(spec, *args)
compile_function(spec).send(spec[:name], *args)
end

#
# Compiles a function spec extracted by
# Pure::Parser::RedParse.
#
# Returns an object which responds to spec[:name].
#
def compile_function(spec)
code_data = (
if spec[:origin] == :fun
fun_to_define_method(spec[:name], spec[:code])
else
spec[:code]
end
)

instance = Names.new(spec[:name], spec[:args])
Thread.current[:pure_compiler_input] = code_data.unparse

# use singleton to hide locals
class << instance
eval(Thread.current[:pure_compiler_input])
end

instance
end

#
# Code-transform `fun' definitions into `define_method' definitions.
#
def fun_to_define_method(name, code_data)
# it's unclear how to create a LiteralNode by hand
literal_node = ::RedParse.new(":x").parse
literal_node[0] = name

code_data[1] = "define_method"
code_data[2] = [literal_node]
code_data
end
end
end
end

4 changes: 4 additions & 0 deletions lib/pure/parser/impl/red_parse.rb
Expand Up @@ -8,6 +8,10 @@ class << self
def extract(mod, method_name, file, line)
BaseParser.extract(mod, method_name, file, line, Processor)
end

def compiler
%w[pure/compiler/red_parse Pure::Compiler::RedParse]
end
end

class Processor
Expand Down
85 changes: 85 additions & 0 deletions spec/compiler_red_parse_spec.rb
@@ -0,0 +1,85 @@
require File.dirname(__FILE__) + '/pure_spec_base'

require 'pure/parser/red_parse'
require 'pure/compiler/red_parse'

describe Pure::Compiler::RedParse do
before :all do
@compiler = Pure::Compiler::RedParse.new
end

it "should transform `fun' definitions to `define_method' definitions" do
def_f = pure(Pure::Parser::RedParse) do
def f(x, y)
x + y
end
end

fun_f = pure(Pure::Parser::RedParse) do
fun :f => [:x, :y] do |a, b|
a + b
end
end

def_g = pure(Pure::Parser::RedParse) do
def g
end
end

fun_g = pure(Pure::Parser::RedParse) do
fun :g do
end
end

def_h = pure(Pure::Parser::RedParse) do
def h(x)
x**2
end
end

fun_h = pure(Pure::Parser::RedParse) do
fun :h => :x do |a|
a**2
end
end

fun_i = pure(Pure::Parser::RedParse) do
fun :i => [:p, :q] do |*s|
s.size
end
end

fun_j = pure(Pure::Parser::RedParse) do
fun :j => [:p, :q] do |r, *s|
r + s
end
end

[
[:def, def_f, :f, "def f(x,y)\nx+y;\nend"],
[:fun, fun_f, :f, "define_method :f do |a, b|\na+b\nend"],
[:def, def_g, :g, "def g\n;\nend"],
[:fun, fun_g, :g, "define_method :g do \nend"],
[:def, def_h, :h, "def h(x)\nx**2;\nend"],
[:fun, fun_h, :h, "define_method :h do |a|\na**2\nend"],
[:fun, fun_i, :i, "define_method :i do |*s|\ns.size\nend"],
[:fun, fun_j, :j, "define_method :j do |r, *s|\nr+s\nend"],
].each { |type, mod, name, expected|
entry = Pure::ExtractedFunctions[Pure::Parser::RedParse][mod][name]
entry[:code].should be_a(RedParse::Node)
code_data = Marshal.load(Marshal.dump(entry[:code]))
if entry[:origin] == :fun
code_data = @compiler.fun_to_define_method(entry[:name], code_data)
end
recovered = (
code_data.
unparse.
gsub(%r!\n+!, "\n").
gsub(%r!^ +!, "").
gsub(%r! +!, " ")
)
recovered.should == expected
}
end
end

0 comments on commit 8adf2a2

Please sign in to comment.