// $Id: BRb.cpp,v 1.34 2003/02/21 01:57:19 yuya Exp $

#include "BRb.h"

////////////////////////////////////////////////////////////////////////////////

extern "C" {
	char * rb_source_filename(const char *f); // gc.c
	VALUE rb_eval(VALUE, NODE*);              // eval.c
}

////////////////////////////////////////////////////////////////////////////////

VALUE
BRb::readfile(VALUE filename)
{
	static ID id_open  = ::rb_intern("open");
	static ID id_read  = ::rb_intern("read");
	static ID id_close = ::rb_intern("close");

	VALUE mode = ::rb_str_new2("rb");
	VALUE file = ::rb_funcall(rb_cFile, id_open, 2, filename, mode);
	VALUE text = ::rb_funcall(file, id_read, 0);
	::rb_funcall(file, id_close, 0);

	return text;
}

#ifdef BRB_WRITER

NODE*
BRb::compile(VALUE code, VALUE filename)
{
	static ID id_basename = ::rb_intern("basename");

	const char* basename = RSTRING(::rb_funcall(rb_cFile, id_basename, 1, filename))->ptr;
	const int   lineno   = 1;

	return ::rb_compile_string(basename, code, lineno);
}

VALUE
BRb::dumpnode(NODE* node, bool debugflag, VALUE exception)
{
	BRbDebug        debug(debugflag, stderr, exception);
	BRbOutputBuffer buffer;
	BRbWriteNode    writer(debug);

	writer.write(node, buffer);

	return buffer.to_string();
}

VALUE
BRb::dumpcode(VALUE code, VALUE filename, bool debugflag, VALUE exception)
{
	NODE* node = compile(code, filename);
	VALUE bin  = dumpnode(node, debugflag, exception);

	return bin;
}

VALUE
BRb::dumpfile(VALUE filename, bool debugflag, VALUE exception)
{
	VALUE code = readfile(filename);
	VALUE bin  = dumpcode(code, filename, debugflag, exception);

	return bin;
}

#endif

#ifdef BRB_READER

NODE*
BRb::loadnode(VALUE code, VALUE filename, bool debugflag, VALUE exception)
{
	BRbDebug       debug(debugflag, stderr, exception);
	BRbInputBuffer buffer(code);
	BRbReadNode    reader(buffer, debug);

	char* sourcefile = ruby_sourcefile;
	ruby_sourcefile = ::rb_source_filename(RSTRING(filename)->ptr);

	NODE* node = reader.read();

	ruby_sourcefile = sourcefile;

	return node;
}

VALUE
BRb::loadcode(VALUE code, VALUE filename, bool debugflag, VALUE exception)
{
	NODE* node = loadnode(code, filename, debugflag, exception);
	VALUE self = ::rb_eval_string("self");

	return ::rb_eval(self, node);
}

VALUE
BRb::loadfile(VALUE filename, bool debugflag, VALUE exception)
{
	VALUE code = readfile(filename);

	return loadcode(code, filename, debugflag, exception);
}

#endif

#if defined(BRB_WRITER) && defined(BRB_READER)

bool
BRb::verifycode(VALUE code, VALUE filename, bool debugflag, VALUE exception)
{
	VALUE bin1 = dumpcode(code, filename, debugflag, exception);
	NODE* node = loadnode(bin1, filename, debugflag, exception);
	VALUE bin2 = dumpnode(node, debugflag, exception);

	return (::rb_funcall(bin1, ::rb_intern("=="), 1, bin2) ? true : false);
}

bool
BRb::verifyfile(VALUE filename, bool debugflag, VALUE exception)
{
	VALUE code = readfile(filename);

	return (verifycode(code, filename, debugflag, exception) ? true : false);
}

#endif

////////////////////////////////////////////////////////////////////////////////
