[rkward-cvs] SF.net SVN: rkward: [1168] trunk/rkward

tfry at users.sourceforge.net tfry at users.sourceforge.net
Wed Jan 17 17:14:40 UTC 2007


Revision: 1168
          http://svn.sourceforge.net/rkward/?rev=1168&view=rev
Author:   tfry
Date:     2007-01-17 09:14:40 -0800 (Wed, 17 Jan 2007)

Log Message:
-----------
Change the way user commands are handled internally.
This was necessary as R_Visible is no longer exported in current R sources, but it also fixes some minor issues

Modified Paths:
--------------
    trunk/rkward/ChangeLog
    trunk/rkward/TODO
    trunk/rkward/rkward/rbackend/rembedinternal.cpp
    trunk/rkward/rkward/rkconsole.cpp

Modified: trunk/rkward/ChangeLog
===================================================================
--- trunk/rkward/ChangeLog	2007-01-16 00:56:59 UTC (rev 1167)
+++ trunk/rkward/ChangeLog	2007-01-17 17:14:40 UTC (rev 1168)
@@ -1,3 +1,7 @@
+- fix compilation for the upcoming R 2.5.0		TODO: check again, later, or write to R-devel about R_ParseVector
+- show full error message for syntax errors (only if compiled with R 2.4.0 or newer)
+- more correct auto-printing of values for user commands (only if compiled with R 2.4.0 or newer)
+- more correct handling of user commands consisting of several statements (only if compiled with R 2.4.0 or newer)
 - add ability to search command history context sensitively
 - add possibility to use dropdown lists in plugins
 

Modified: trunk/rkward/TODO
===================================================================
--- trunk/rkward/TODO	2007-01-16 00:56:59 UTC (rev 1167)
+++ trunk/rkward/TODO	2007-01-17 17:14:40 UTC (rev 1168)
@@ -110,18 +110,7 @@
 		- True Support for Logicals
 		- In the current design, RKVariable would not handle storage mode changes from outside well at all
 		- use QIntDict instead of string-map for value-labels / factor levels? Qt4: QHash
-	- maybe we can do stuff like auto-printing, (toplevel handlers: no, not those, they are not called in R_ReplDLLdo1 ()), syntax error information by using R_ReplDLLdo1 () for user/console commands. The command-text would be fed in via R_ReadConsole (would need to keep a buffer).
-		- How to differentiate readline calls to get new command data from readline calls to get user info?! The prompt may not be realiable enough. Is there other info?
-			- the hist parameter may be a hint, but is also set in do_browser
-			- Does R_ResetConsole play any role in this?
-			- maybe (but this would really be taking chances) do so by determining, if the buffer belongs to the main Repl_Console (currently that buffer always remains the same during one loop, but can we be certain, this never changes?). Same buffer is used while inside do_browser ().
-			- RBusy is set to 0 just before the command data is read! (but also while inside do_browser ())
-				- These patterns may emerge after a call to R_ReplDLLdo1 ():
-					- first: R_Busy (0), second: R_Busy (1), ... : Between first and second, the R_ReadConsole is a request for code
-					- first: R_Busy (1), ...: No code is requested
-				- hence, as soon as R_Busy (1) is set after a call to R_ReplDLLdo1 (), the following R_ReadConsole calls are for user input, not code
-		- Where would we jump after a SIGINT? I suppose we'd have to make sure to clear the buffer before signalling (another mutex)
-		- Is it UTF-8 safe?
+	- call toplevel handlers for user/console commands?
 	RCommandReceiver:
 		- add virtual rCommandStarted () function, so receivers can find out, when their command becomes active
 	REmbedInternal:
@@ -264,9 +253,6 @@
 	- see also: connections.c line 3246ff InitConnections
 	- seems ok now. But maybe we could still use this to catch immediate warning messages (which go to R_Consolefile)?
 
-- still mysterious in warning-handling: 'help (doesnotexist); print ("stuff");'. Why is the order wrong?!
-	- because first both are evaluated, then the warnings are printed. R_ReplIteration works differently in that it stops at each ";" and "\n"
-
 tryCatch (message ("a"), error=function (x) {print ("e"); x$message}, warning=function (y) {print ("w"); conditionMessage(y)}, message=function (z) {print ("m"); conditionCall (z)})
 withCallingHandlers ({message ("a"); stop ("b");}, error=function (x) {print ("e"); x$message}, warning=function (y) {print ("w"); conditionMessage(y)}, message=function (z) {print ("c"); conditionCall (z)})
 

Modified: trunk/rkward/rkward/rbackend/rembedinternal.cpp
===================================================================
--- trunk/rkward/rkward/rbackend/rembedinternal.cpp	2007-01-16 00:56:59 UTC (rev 1167)
+++ trunk/rkward/rkward/rbackend/rembedinternal.cpp	2007-01-17 17:14:40 UTC (rev 1168)
@@ -20,7 +20,7 @@
 
 // static
 REmbedInternal *REmbedInternal::this_pointer = 0; 
- 
+
 extern "C" {
 #define R_INTERFACE_PTRS 1
 
@@ -34,6 +34,7 @@
 #include "Rdevices.h"
 #include "Rversion.h"
 #include "R_ext/Parse.h"
+#include "R_ext/Utils.h"
 
 #include <dlfcn.h>
 #include <stdlib.h>
@@ -52,7 +53,15 @@
 #define R_2_4
 #endif
 
+#if (R_VERSION > R_Version(2, 4, 9))
+#define R_2_5
+#endif
+
 #ifdef R_2_4
+#define USE_R_REPLDLLDO1
+#endif
+
+#ifdef R_2_4
 #include "Rembedded.h"
 #else
 extern void R_ReplDLLinit (void);
@@ -60,7 +69,6 @@
 
 // some functions we need that are not declared
 extern int Rf_initEmbeddedR(int argc, char **argv);
-extern SEXP R_ParseVector(SEXP, int, ParseStatus*);
 extern void Rf_PrintWarnings (void);
 extern int R_interrupts_pending;
 #ifdef R_2_3
@@ -68,12 +76,25 @@
 extern void setup_Rmainloop(void); /* in main.c */
 extern unsigned long R_CStackLimit;
 #endif
+#ifndef USE_R_REPLDLLDO1
 extern Rboolean R_Visible;
+#endif
+#ifndef R_2_5
+extern SEXP R_ParseVector(SEXP, int, ParseStatus*);
+#endif
 }
 
 #include "../rkglobals.h"
 #include "rdata.h"
 
+#ifdef USE_R_REPLDLLDO1
+const char *current_buffer = 0;
+bool repldlldo1_wants_code = false;
+bool repldll_buffer_transfer_finished = false;
+int repldll_result = 0;		/* -2: error; -1: incomplete; 0: nothing, yet 1: ok 2: incomplete statement, while buffer not empty. Should not happen */
+bool repldll_last_parse_successful = false;
+#endif
+
 // ############## R Standard callback overrides BEGIN ####################
 void RSuicide (char* message) {
 	RCallbackArgs args;
@@ -91,6 +112,31 @@
 }
 
 int RReadConsole (char* prompt, unsigned char* buf, int buflen, int hist) {
+#ifdef USE_R_REPLDLLDO1
+	// handle requests for new code
+	if (repldlldo1_wants_code) {
+		//Rprintf ("wants code, buffsize: %d\n", buflen);
+		if (repldll_buffer_transfer_finished) {
+			return 0;
+		}
+
+		int pos = 0;		// fgets emulation
+		while (pos < (buflen-1)) {
+			buf[pos] = *current_buffer;
+			if (*current_buffer == '\0') {
+				repldll_buffer_transfer_finished = true;
+				break;
+			}
+			++current_buffer;
+			++pos;
+		}
+		if (repldll_buffer_transfer_finished) buf[pos] = '\n';
+		buf[++pos] = '\0';
+		//Rprintf ("buffer now: '%s'\n", buf);
+		return 1;
+	}
+#endif
+	// here, we handle readline calls and such, i.e. not the regular prompt for code
 	RCallbackArgs args;
 	args.type = RCallbackArgs::RReadConsole;
 	args.chars_a = &prompt;
@@ -134,11 +180,6 @@
 // we leave this un-implemented on purpose! We simply don't want that sort of thing to be done.
 }
 
-/*
-void RBusy (int which) {
-// I guess this is not any better (actually worse) than rkward's own busy indikator
-} */
-
 void RCleanUp (SA_TYPE saveact, int status, int RunLast) {
 	if (saveact != SA_SUICIDE) {
 		RCallbackArgs args;
@@ -221,6 +262,16 @@
 	return REditFiles (1, &buf, &title, editor);
 }
 
+#ifdef USE_R_REPLDLLDO1
+void RBusy (int busy) {
+	// R_ReplDLLDo1 calls R_Busy (1) after reading in code (if needed), parsing it, and right before evaluating it.
+	if (busy) {
+		repldlldo1_wants_code = false;
+		repldll_last_parse_successful = true;
+	}
+}
+#endif
+
 // ############## R Standard callback overrides END ####################
 
 char *REmbedInternal::na_char_internal = new char;
@@ -246,7 +297,9 @@
 	ptr_R_ResetConsole = RResetConsole;
 	ptr_R_FlushConsole = RFlushConsole;
 	ptr_R_ClearerrConsole = RClearerrConsole;
-//	ptr_R_Busy = RBusy;				// probably we don't have any use for this
+#ifdef USE_R_REPLDLLDO1
+	ptr_R_Busy = RBusy;
+#endif
 	ptr_R_CleanUp = RCleanUp;			// unfortunately, it seems, we can't safely cancel quitting anymore, here!
 	ptr_R_ShowFiles = RShowFiles;
 	ptr_R_ChooseFile = RChooseFile;
@@ -498,8 +551,12 @@
 	PROTECT(cv=allocVector(STRSXP, 1));
 	SET_VECTOR_ELT(cv, 0, mkChar(command));  
 
-	// TODO: Maybe we can use R_ParseGeneral instead. Then we could find the exact character, where parsing fails
+	// TODO: Maybe we can use R_ParseGeneral instead. Then we could find the exact character, where parsing fails. Nope: not exported API
+#ifdef R_2_5
+	pr=R_ParseVector(cv, -1, &status, NILSXP);
+#else
 	pr=R_ParseVector(cv, -1, &status);
+#endif
 	UNPROTECT(1);
 
 	if ((!pr) || (TYPEOF (pr) == NILSXP)) {
@@ -561,6 +618,7 @@
 	return exp;
 }
 
+#ifndef USE_R_REPLDLLDO1
 /* Basically a safe version of Rf_PrintValue, as yes, Rf_PrintValue may lead to an error and long_jump->crash!
 For example in help (function, htmlhelp=TRUE), when no HTML-help is installed!
 SEXP exp should be PROTECTed prior to calling this function.
@@ -587,11 +645,62 @@
 		*error = REmbedInternal::NoError;
 	}
 }
+#endif
 
+#ifdef USE_R_REPLDLLDO1
+void runUserCommandInternal (void *) {
+/* R_ReplDLLdo1 return codes:
+-1: EOF
+1: normal prompt
+2: continuation prompt (parse incomplete) */
+	do {
+		//Rprintf ("iteration status: %d\n", repldll_result);
+		repldll_result = -2;
+		repldlldo1_wants_code = true;
+		repldll_last_parse_successful = false;
+	} while (((repldll_result = R_ReplDLLdo1 ()) == 2) && (!repldll_buffer_transfer_finished));	// keep iterating while the statement is incomplete, and we still have more in the buffer to transfer
+	//Rprintf ("iteration complete, status: %d\n", repldll_result);
+	PROTECT (R_LastvalueSymbol);		// why do we need this? No idea, but R_ToplevelExec tries to unprotect something
+}
+#endif
+
 void REmbedInternal::runCommandInternal (const char *command, RKWardRError *error, bool print_result) {
 	if (!print_result) {
 		runCommandInternalBase (command, error);
-	} else {
+	} else {		// run a user command
+#ifdef USE_R_REPLDLLDO1
+		R_ReplDLLinit ();		// resets the parse buffer (things might be left over from a previous incomplete parse)
+		bool prev_iteration_was_incomplete = false;
+
+		current_buffer = command;
+		repldll_buffer_transfer_finished = false;
+		Rboolean ok = (Rboolean) 1;	// set to false, if there is a jump during the R_ToplevelExec (i.e.. some sort of error)
+
+		repldll_result = 0;
+		while ((ok != FALSE) && ((!repldll_buffer_transfer_finished) || (repldll_result != -1))) {
+			// we always need to iterate until the parse returned an EOF AND we have no more code in the buffer to supply.
+			// However, if this happens right after we last received an INCOMPLETE, this means the parse really was incomplete.
+			// Otherwise, there's simply nothing more to parse.
+			prev_iteration_was_incomplete = (repldll_result == 2);
+			ok = R_ToplevelExec (runUserCommandInternal, 0);
+		}
+		if (ok == FALSE) {
+			if (repldll_last_parse_successful) {
+				*error = REmbedInternal::OtherError;
+			} else {
+				*error = REmbedInternal::SyntaxError;
+			}
+		} else {
+			if (prev_iteration_was_incomplete) {
+				*error = REmbedInternal::Incomplete;
+			} else {
+				*error = REmbedInternal::NoError;
+			}
+		}
+		repldlldo1_wants_code = false;		// make sure we don't get confused in RReadConsole
+
+#else
+
 		R_Visible = (Rboolean) 0;
 
 		SEXP exp;
@@ -611,6 +720,7 @@
 		Rprintf ("");
 
 		Rf_PrintWarnings ();
+#endif
 	}
 }
 

Modified: trunk/rkward/rkward/rkconsole.cpp
===================================================================
--- trunk/rkward/rkward/rkconsole.cpp	2007-01-16 00:56:59 UTC (rev 1167)
+++ trunk/rkward/rkward/rkconsole.cpp	2007-01-17 17:14:40 UTC (rev 1168)
@@ -467,7 +467,7 @@
 
 void RKConsole::rCommandDone (RCommand *command) {
 	RK_TRACE (APP);
-	if (command->errorSyntax ()) {
+	if (command->errorSyntax () && command->error ().isEmpty ()) {
 		editInterface(doc)->insertLine(doc->numLines()-1, i18n ("Syntax error\n"));
 	}
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the rkward-tracker mailing list