#include <jsc/jsc.h>
#include <Core/Core.h>
using namespace Upp;

JSReturnType functionPrint(ExecState* exec) {
	for (unsigned i = 0; i < exec->argumentCount(); ++i)
		Cout()<< (i?" ":"") << exec->argument(i).toString(exec).UTF8String().data();
	Cout()<<"\n";
	return JSValue::encode(jsUndefined());
}

JSReturnType functionGC(ExecState* exec) {
	JSLock lock(SilenceAssertionsOnly);
	exec->heap()->collectAllGarbage();
	//Cout()<<"Garbage collected\n";
	return JSValue::encode(jsUndefined());
}

JSReturnType functionReadline(ExecState* exec) {
	return JSValue::encode(jsString(exec, UString(ReadStdIn())));
}

JSReturnType functionQuit(ExecState* exec) {
	// Technically, destroying the heap in the middle of JS execution is a no-no,
	// but we want to maintain compatibility with the Mozilla test suite, so
	// we pretend that execution has terminated to avoid ASSERTs, then tear down the heap.
	JSLock lock(SilenceAssertionsOnly);
	exec->globalData().dynamicGlobalObject = 0;
	exec->globalData().deref();
	exec->globalData().heap.destroy();
	exit(EXIT_SUCCESS);
}

CONSOLE_APP_MAIN{
	// JavaScript object provides easy access to JS interpreter. It initiallizes everything
	// in constructor and takes care about the garbage in destructor.
	JavaScript js;
	// You can add your own native functions, to be accesible from within JS
	js.AddNativeFunction("readline",functionReadline);
	js.AddNativeFunction("print",functionPrint);
	js.AddNativeFunction("gc",functionGC);
	js.AddNativeFunction("quit",functionQuit);
	// First lets try to execute some bigger piece of code:
	const char* hello="function hello(){\n"
	                  "  print(\"Hello, what's your name?\")\n"
	                  "  name=readline()\n"
	                  "  return \"Hello \"+name+\"!\\nEnjoy the interpreter...\"\n"
	                  "}\n"
	                  "hello()";
	String result;
	if(js.Execute(hello,result)) Cout()<<result<<"\n";
	// And now, let the user play with the interpreter:
	while(true){
		Cout()<<"> ";
		String line = ReadStdIn();
		if(line.IsEmpty()) break;
		if(js.Execute(line,result)) {Cout()<<result<<"\n";}
		// If the interpreter encounters error, Execute() returns false and result contains
		// the description of the error, so we can show it to the user.
		else {Cout()<<"Error: "<<result<<"\n";}
	}
}
