Skip to content

Instantly share code, notes, and snippets.

@faultier
Created April 1, 2010 11:09
Show Gist options
  • Save faultier/351671 to your computer and use it in GitHub Desktop.
Save faultier/351671 to your computer and use it in GitHub Desktop.
# vim: fileencoding=utf-8 filetype=ruby
require 'rack'
require 'stringio'
require 'ruby2ruby'
require 'esoteric/dt'
module Esoteric
module DT
class Server
def initialize(dir='handler')
@processor = Ruby2Ruby.new
@handlers = {}
@base_dir = dir
end
def call(env)
req = Rack::Request.new(env)
status = 200
body = ''
headers = { 'content-type' => 'text/plain' }
buffer = StringIO.new
begin
input = req['rack.input'].nil? ? StringIO.new(req.query_string) : req['rack.input']
exit_code = handler(req.path, req.params).call(input, buffer)
raise "DT error: (exit code=#{exit_code})" if exit_code != 0
body = buffer.string
buffer.close
if body =~ /^((?:(?:[\w\-]+: [^\n]+)\n)+)\n(.+)$/im
body = $2
header = $1
header.each_line {|line| headers[$1.downcase] = $2 if line =~ /\A([\w\-]+): (.+)\n?\z/}
end
rescue
warn $!
status = 500
body = 'Internal Server Error'
end
res = Rack::Response.new {|r|
r.status = status
headers.each_pair {|key,val| r[key] = val }
r.write body
}
res.finish
end
private
def ast_normalize(ast)
if (ast.kind_of?(Array))
case ast[0]
when :gasgn
lvar_name = case ast[1]
when :$stack then :_s
when :$heap then nil
else ast[1].to_s.sub('$','').intern end
[:lasgn, lvar_name, ast_normalize(ast[2])] if lvar_name
when :gvar
ast[0] = :lvar
ast[1] = case ast[1]
when :$stack then :_s
when :$heap then :_h
when :$stdin then :_i
when :$stdout then :_o
else ast[1].to_s.sub('$','').intern end
ast
when :call
ast[2] = :return if ast[2] == :exit
[ast[0]] + ast[1..ast.size-1].map{|exp|ast_normalize(exp)}
when :arglist, :block
[ast[0]] + ast[1..ast.size-1].map{|exp|ast_normalize(exp)}
else
ast
end
else
ast
end
end
def params_normalize(params)
n_params = {}
params.each_pair do |key,val|
next unless key.kind_of?(String) && key.length == 1
case val
when /\A\d+\z/
n_params[key.ord] = val.to_i
when /\A[a-zA-Z]\z/
n_params[key.ord] = val.ord
end
end
n_params
end
def handler(path, params={})
file = @base_dir + path
file = file + 'index.dt' if file =~ /\/\z/
file = file + '.dt' unless file =~ /\.dt\z/
params = params_normalize(params)
handler = @handlers[file]
unless handler && handler.kind_of?(Proc)
ast = ast_normalize(::Esoteric::DT::Parser.parse(::File.read(file))).compact
ast.push [:call, nil, :return, [:arglist, [:lit, 0]]] unless ast.last[0] == :call && ast.last[2] == :return
sexp = Sexp.from_array(ast)
code = "lambda {|_i,_o,_h|\n#{@processor.process(sexp)}}"
handler = @handlers[file] = eval(code)
end
lambda { |input,output| handler.call(input,output,params) }
end
end
end
end
run Esoteric::DT::Server.new(::File.expand_path(::File.dirname(__FILE__)))
「○○くんて、もしかして童貞?」
「どどど童貞ちゃうわっ!どど童貞ちゃうわっ!どどど…童貞ちゃうわっ!」
「えー。その慌てっぷりが余計怪しなぁw」
「…どどどどど童貞ちゃうわっ!童貞ちゃうわっ!ど童貞ちゃうわっ!どど童貞ちゃうわっ!…童貞ちゃうわっ!」
「はいはい、わ、わかったってば。そんなにムキになんないでよ。」
「…どどどどど童貞ちゃうわっ!どどどど童貞ちゃうわっ!…童貞ちゃうわっ!」
「だから、わかったってば。もう言わないから。」
「…どどどどど童貞ちゃうわっ!ど童貞ちゃうわっ!ど…童貞ちゃうわっ!」
「いやその、なんか、ほんとごめんね。そんな気にしてると思わなかったから…」
「どど…」
「(ほんとキモいなぁ…)」
「…」
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment