Tcl Source Code

Artifact [8103069606]
Login

Artifact 8103069606fdb19126dc1aa7af409c52c38d2f4b:

Attachment "1032805.patch" to ticket [1032805fff] added by dgp 2004-09-23 05:18:59.
Index: generic/tclCmdMZ.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCmdMZ.c,v
retrieving revision 1.106
diff -u -r1.106 tclCmdMZ.c
--- generic/tclCmdMZ.c	17 Sep 2004 22:59:14 -0000	1.106
+++ generic/tclCmdMZ.c	22 Sep 2004 22:15:48 -0000
@@ -921,6 +921,13 @@
 	    if (valuePtr != NULL) {
 		Tcl_SetObjErrorCode(interp, valuePtr);
 	    }
+
+	    valuePtr = NULL;
+	    Tcl_DictObjGet(NULL, iPtr->returnOpts,
+		    iPtr->returnErrorlineKey, &valuePtr);
+	    if (valuePtr != NULL) {
+		Tcl_GetIntFromObj(NULL, valuePtr, &iPtr->errorLine);
+	    }
 	}
     } else {
 	code = TCL_RETURN;
Index: generic/tclCompile.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompile.c,v
retrieving revision 1.72
diff -u -r1.72 tclCompile.c
--- generic/tclCompile.c	21 Sep 2004 22:45:41 -0000	1.72
+++ generic/tclCompile.c	22 Sep 2004 22:15:48 -0000
@@ -948,8 +948,46 @@
     gotParse = 0;
     do {
 	if (Tcl_ParseCommand(interp, p, bytesLeft, 0, &parse) != TCL_OK) {
-	    code = TCL_ERROR;
-	    goto error;
+	    /* Compile bytecodes to report the parse error at runtime */
+	    Tcl_Obj *returnCmd = Tcl_NewStringObj(
+		    "return -code 1 -level 0 -errorinfo", -1);
+	    Tcl_Obj *errMsg = Tcl_GetObjResult(interp);
+	    Tcl_Obj *errInfo = Tcl_DuplicateObj(errMsg);
+	    char *cmdString;
+	    int cmdLength;
+	    Tcl_Parse subParse;
+	    int errorLine = 1;
+
+	    Tcl_IncrRefCount(returnCmd);
+	    Tcl_IncrRefCount(errInfo);
+	    Tcl_AppendToObj(errInfo, "\n    while executing\n\"", -1);
+	    TclAppendLimitedToObj(errInfo, parse.commandStart,
+		/* Drop the command terminator (";" or "]") if appropriate */
+		(parse.term == parse.commandStart + parse.commandSize - 1) ?
+			parse.commandSize - 1 : parse.commandSize, 153, NULL);
+	    Tcl_AppendToObj(errInfo, "\"", -1);
+
+	    Tcl_ListObjAppendElement(NULL, returnCmd, errInfo);
+
+	    for (p = script; p != parse.commandStart; p++) {
+		if (*p == '\n') {
+		    errorLine++;
+		}
+	    }
+	    Tcl_ListObjAppendElement(NULL, returnCmd,
+		    Tcl_NewStringObj("-errorline", -1));
+	    Tcl_ListObjAppendElement(NULL, returnCmd,
+		    Tcl_NewIntObj(errorLine));
+
+	    Tcl_ListObjAppendElement(NULL, returnCmd, errMsg);
+	    Tcl_DecrRefCount(errInfo);
+
+	    cmdString = Tcl_GetStringFromObj(returnCmd, &cmdLength);
+	    Tcl_ParseCommand(interp, cmdString, cmdLength, 0, &subParse);
+	    TclCompileReturnCmd(interp, &subParse, envPtr);
+	    Tcl_DecrRefCount(returnCmd);
+	    Tcl_FreeParse(&subParse);
+	    return TCL_OK;
 	}
 	gotParse = 1;
 	if (parse.numWords > 0) {
@@ -1224,26 +1262,6 @@
     Tcl_DStringFree(&ds);
     return TCL_OK;
 	
-    error:
-    /*
-     * Generate various pieces of error information, such as the line
-     * number where the error occurred and information to add to the
-     * errorInfo variable. Then free resources that had been allocated
-     * to the command.
-     */
-
-    commandLength = parse.commandSize;
-    if (parse.term == parse.commandStart + commandLength - 1) {
-	/*
-	 * The terminator character (such as ; or ]) of the command where
-	 * the error occurred is the last character in the parsed command.
-	 * Reduce the length by one so that the error message doesn't
-	 * include the terminator character.
-	 */
-
-	commandLength -= 1;
-    }
-
     log:
     LogCompilationInfo(interp, script, parse.commandStart, commandLength);
     if (gotParse) {
@@ -3339,7 +3357,7 @@
 		             || (opCode == INST_JUMP_FALSE1))) {
 		fprintf(stdout, "%d  	# pc %u", opnd, (pcOffset + opnd));
 	    } else {
-		fprintf(stdout, "%d", opnd);
+		fprintf(stdout, "%d ", opnd);
 	    }
 	    break;
 	case OPERAND_INT4:
@@ -3349,7 +3367,7 @@
 		             || (opCode == INST_JUMP_FALSE4))) {
 		fprintf(stdout, "%d  	# pc %u", opnd, (pcOffset + opnd));
 	    } else {
-		fprintf(stdout, "%d", opnd);
+		fprintf(stdout, "%d ", opnd);
 	    }
 	    break;
 	case OPERAND_UINT1:
Index: tests/compile.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/compile.test,v
retrieving revision 1.31
diff -u -r1.31 compile.test
--- tests/compile.test	2 Aug 2004 15:33:36 -0000	1.31
+++ tests/compile.test	22 Sep 2004 22:15:49 -0000
@@ -570,6 +570,19 @@
     rename ReturnResults {}
 } -returnCodes ok -result [string trim [string repeat {x } 260]]
 
+test compile-16.23.$noComp {
+    Bug 1032805: defer parse error until run time
+} -body {
+    namespace eval x {
+	run {
+	    proc if {a b} {uplevel 1 [list set $a $b]}
+	    if 1 {syntax {}{}}
+	}
+    }
+} -cleanup {
+    namespace delete x
+} -returnCodes ok -result {syntax {}{}}
+
 }	;# End of noComp loop
 
 # cleanup
Index: tests/misc.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/misc.test,v
retrieving revision 1.9
diff -u -r1.9 misc.test
--- tests/misc.test	4 Jul 2004 18:02:42 -0000	1.9
+++ tests/misc.test	22 Sep 2004 22:15:49 -0000
@@ -57,14 +57,14 @@
 } [subst -novariables -nocommands {1
 missing close-brace for variable name
 missing close-brace for variable name
-    while compiling
+    while executing
 "set tst $a([winfo name $\{zz)
 	# this is a bogus comment
 	# this is a bogus comment
 	# this is a bogus comment
 	# this is a bogus comment
 	# this is a ..."
-    (compiling body of proc "tstProc", line 4)
+    (procedure "tstProc" line 4)
     invoked from within
 "tstProc"}]