lib/nydp/runner.rb in nydp-0.5.1 vs lib/nydp/runner.rb in nydp-0.6.0

- old
+ new

@@ -1,23 +1,55 @@ +require 'digest' require 'readline' require 'nydp/readline_history' module Nydp class StringReader - def initialize string ; @string = string ; end + attr_accessor :name + + def initialize name, string + @name, @string, @read = name, string, string + end + def nextline - s = @string ; @string = nil ; s + s = @read ; @read = nil ; s end + + def read + @string + end end class StreamReader - def initialize stream ; @stream = stream ; end + attr_accessor :name + + def initialize name, stream + @name, @stream = name, stream + end + def nextline @stream.readline unless @stream.eof? end + + def read + "" + end end + class FileReader < StreamReader + attr_accessor :filename + + def initialize name, filename + super name, File.new(filename) + @filename = filename + end + + def read + File.read filename + end + end + class ReadlineReader include Nydp::ReadlineHistory def initialize stream, prompt @prompt = prompt @@ -35,55 +67,141 @@ line end end class Evaluator - attr_accessor :vm, :ns, :name + attr_accessor :ns, :name - def initialize vm, ns, name - @name = name - @vm = vm - @ns = ns - @precompile = Symbol.mk(:"pre-compile", ns) - @quote = Symbol.mk(:quote, ns) + def initialize ns, name + @name = name + @ns = ns + @rubydir = FileUtils.mkdir_p "rubycode" end - def compile_and_eval expr + def compile_expr expr begin - vm.thread_with_expr Pair.new(Compiler.compile(expr, Nydp::NIL), Nydp::NIL) + Compiler.compile(expr, nil, ns) rescue StandardError => e - raise Nydp::Error, "failed to eval #{expr.inspect}" + raise Nydp::Error, "failed to compile #{expr._nydp_inspect}" end end - def pre_compile expr - compile_and_eval(Pair.from_list [@precompile, Pair.from_list([@quote, expr])]) + def self.mk_manifest name, class_list + class_expr = <<KLA +#{class_list.map {|k| "require '#{k}'" }.join("\n")} + +class #{name} + def self.build ns + #{class_list.map {|k| "#{k}.new(ns).call" }.join("\n ")} + end +end +KLA + File.open("rubycode/#{name}.rb", "w") { |f| + fullpath = File.expand_path("rubycode/#{name}.rb") + Nydp.logger.info "writing #{fullpath}" if Nydp.logger + f.write class_expr + } end - def evaluate expr - compile_and_eval(pre_compile(expr)) + class CompiledExpression + attr_accessor :ns + def initialize ns + @ns = ns + end + + def list *things + Nydp::Pair.from_list things + end end + + def mk_ruby_source src, precompiled, compiled_expr, cname + srcs = [] + ruby_expr = compiled_expr.compile_to_ruby " ", srcs + six = 0 + srcs = srcs.map { |s| + s = " @@src_#{six} = #{s.inspect}" + six += 1 + s + } + class_expr = "class #{cname} < Nydp::Runner::CompiledExpression + +#{srcs.join("\n")} + + def src + #{src.inspect.inspect} end + def precompiled + #{precompiled.inspect.inspect} + end + + def call +#{ruby_expr} + end +end + +#{cname} +" + File.open("rubycode/#{cname}.rb", "w") { |f| f.write class_expr } + class_expr + end + + def mk_ruby_class src, precompiled, compiled_expr, cname + begin + require cname + self.class.const_get(cname) + + rescue LoadError => e + # compiled_expr = compile_expr precompiled # TODO : delete line in #evaluate and uncomment this one + fname = "rubycode/#{cname}.rb" + txt = mk_ruby_source src, precompiled, compiled_expr, cname + + eval(txt, nil, fname) || raise("failed to generate class #{cname} from src #{src}") + end + end + + def eval_compiled compiled_expr, precompiled, src, manifest + return nil unless precompiled + + digest = Digest::SHA256.hexdigest(precompiled.inspect) + cname = "#{GENERATED_CLASS_PREFIX}_#{digest.upcase}" + kla = mk_ruby_class src, precompiled, compiled_expr, cname + + manifest << cname + + kla.new(ns).call + + rescue Exception => e + raise Nydp::Error, "failed to eval #{compiled_expr._nydp_inspect} from src #{src._nydp_inspect}" + end + + def evaluate expr, manifest=[] + precompiled = ns.apply :"pre-compile-new-expression", expr + compiled = compile_expr precompiled # TODO : we don't need this step if the class already exists! Do it later only when we need it + eval_compiled compiled, precompiled, expr, manifest + end + end + class Runner < Evaluator - def initialize vm, ns, stream, printer=nil, name=nil - super vm, ns, name + def initialize ns, stream, printer=nil, name=nil, manifest=[] + super ns, name @printer = printer - @parser = Nydp.new_parser(ns) + @parser = Nydp.new_parser @tokens = Nydp.new_tokeniser stream + @manifest = manifest end def print val - @printer.puts val.inspect if @printer + @printer.puts val._nydp_inspect if @printer end def run Nydp.apply_function ns, :"script-run", :"script-start", name - res = Nydp::NIL + res = nil begin while !@tokens.finished expr = @parser.expression(@tokens) - print(res = evaluate(expr)) unless expr.nil? + print(res = evaluate(expr, @manifest)) unless expr.nil? end ensure Nydp.apply_function ns, :"script-run", :"script-end", name end res