Changes On Branch mistake
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch mistake Excluding Merge-Ins

This is equivalent to a diff from 38924072ae to 98c6c7c513

2026-09-07
22:08
10 more conversions check-in: f7a0cf1224 user: Torsten tags: tip-700
11:38
Merge trunk Closed-Leaf check-in: 98c6c7c513 user: jan.nijtmans tags: mistake
11:37
Cherrypick some trivial doc changes from tip-700 branch check-in: 151d53761e user: jan.nijtmans tags: trunk, main
2026-09-06
21:11
- 14 new conversions - bold Tcl_DString text is now also alway a link to the Dstring manual page - c... check-in: 38924072ae user: Torsten tags: tip-700
2026-09-05
22:05
- 10 more conversions - more fixes to timer.n (also worth to be backported to trunk) - correected a ... check-in: 8977e8ee80 user: Torsten tags: tip-700

Changes to .github/workflows/linux-build.yml.
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
name: Linux
on:
  push:
    branches:
    - "main"
    - "core-9-1-branch"
    tags:
    - "core-*"

permissions:
  contents: read
jobs:
  plan:
    runs-on: ubuntu-26.04
    outputs:
      gcc: ${{ steps.matrix.outputs.gcc }}








>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
name: Linux
on:
  push:
    branches:
    - "main"
    - "core-9-1-branch"
    tags:
    - "core-*"
  workflow_dispatch:
permissions:
  contents: read
jobs:
  plan:
    runs-on: ubuntu-26.04
    outputs:
      gcc: ${{ steps.matrix.outputs.gcc }}
Changes to .github/workflows/mac-build.yml.
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
name: macOS
on:
  push:
    branches:
    - "main"
    - "core-9-1-branch"
    tags:
    - "core-*"

permissions:
  contents: read
jobs:
  plan:
    runs-on: ubuntu-26.04
    outputs:
      clang: ${{ steps.matrix.outputs.clang }}








>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
name: macOS
on:
  push:
    branches:
    - "main"
    - "core-9-1-branch"
    tags:
    - "core-*"
  workflow_dispatch:
permissions:
  contents: read
jobs:
  plan:
    runs-on: ubuntu-26.04
    outputs:
      clang: ${{ steps.matrix.outputs.clang }}
Changes to .github/workflows/onefiledist.yml.
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
name: Build Binaries
on:
  push:
    branches:
    - "main"
    - "core-9-1-branch"
    tags:
    - "core-*"

permissions:
  contents: read
jobs:
  linux:
    name: Linux
    runs-on: ubuntu-26.04
    defaults:








>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
name: Build Binaries
on:
  push:
    branches:
    - "main"
    - "core-9-1-branch"
    tags:
    - "core-*"
  workflow_dispatch:
permissions:
  contents: read
jobs:
  linux:
    name: Linux
    runs-on: ubuntu-26.04
    defaults:
Changes to .github/workflows/win-build.yml.
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
name: Windows
on:
  push:
    branches:
    - "main"
    - "core-9-1-branch"
    tags:
    - "core-*"

permissions:
  contents: read
jobs:
  plan:
    runs-on: ubuntu-26.04
    outputs:
      msvc: ${{ steps.matrix.outputs.msvc }}
      gcc: ${{ steps.matrix.outputs.gcc }}
    steps:
      - name: Select build matrix based on branch name
        id: matrix
        run: |
          (
            echo msvc=$(jq -nc '{config: (if env.IsMatched == "true" then env.MSVC_FULL else env.MSVC_PARTIAL end) | fromjson }' )
            echo gcc=$(jq -nc '{config: (if env.IsMatched == "true" then env.GCC_FULL else env.GCC_PARTIAL end) | fromjson }' )
          ) | tee -a $GITHUB_OUTPUT
        env:
          IsMatched: ${{ github.ref_name == 'main' || github.ref_name == 'core-9-1-branch' }}
          # DO NOT CHANGE THESE MATRIX SPECS; IT AFFECTS OUR COST CONTROLS
          MSVC_FULL: >
            [








>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
name: Windows
on:
  push:
    branches:
    - "main"
    - "core-9-1-branch"
    tags:
    - "core-*"
  workflow_dispatch:
permissions:
  contents: read
jobs:
  plan:
    runs-on: ubuntu-26.04
    outputs:
      msvc: ${{ steps.matrix.outputs.msvc }}
      gcc: ${{ steps.matrix.outputs.gcc }}
    steps:
      - name: Select build matrix based on branch name
        id: matrix
        run: |
          (
            echo msvc=$(jq -nc '{arch: ["x64"], config: (if env.IsMatched == "true" then env.MSVC_FULL else env.MSVC_PARTIAL end) | fromjson }' )
            echo gcc=$(jq -nc '{config: (if env.IsMatched == "true" then env.GCC_FULL else env.GCC_PARTIAL end) | fromjson }' )
          ) | tee -a $GITHUB_OUTPUT
        env:
          IsMatched: ${{ github.ref_name == 'main' || github.ref_name == 'core-9-1-branch' }}
          # DO NOT CHANGE THESE MATRIX SPECS; IT AFFECTS OUR COST CONTROLS
          MSVC_FULL: >
            [
66
67
68
69
70
71
72
73
74



75
76
77
78
79
80
81
      matrix: ${{ fromJson(needs.plan.outputs.msvc) }}
    # Using powershell means we need to explicitly stop on failure
    steps:
      - name: Checkout
        uses: actions/checkout@v7
        timeout-minutes: 5
      - name: Init MSVC
        uses: ilammy/msvc-dev-cmd@v1
        timeout-minutes: 5



      - name: Build ${{ matrix.config }}
        run: |
          &nmake -f makefile.vc ${{ matrix.config }} all
          if ($lastexitcode -ne 0) {
             throw "nmake exit code: $lastexitcode"
          }
        timeout-minutes: 5







|
|
>
>
>







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
      matrix: ${{ fromJson(needs.plan.outputs.msvc) }}
    # Using powershell means we need to explicitly stop on failure
    steps:
      - name: Checkout
        uses: actions/checkout@v7
        timeout-minutes: 5
      - name: Init MSVC
        shell: cmd
        run: |
          for /f "usebackq tokens=*" %%i in (`vswhere -latest -property installationPath`) do set "VS_PATH=%%i"
          call "%VS_PATH%\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.arch }}
          set | findstr /i "^VC ^VCTools ^Windows ^Universal ^INCLUDE ^LIB ^PATH ^DevEnv" >> %GITHUB_ENV%
      - name: Build ${{ matrix.config }}
        run: |
          &nmake -f makefile.vc ${{ matrix.config }} all
          if ($lastexitcode -ne 0) {
             throw "nmake exit code: $lastexitcode"
          }
        timeout-minutes: 5
Changes to generic/tclBasic.c.
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
    {"string",		tclStringImplMap,	NULL, CMD_IS_SAFE},
    {"::tcl::prefix",	tclPrefixImplMap,	TclSetUpPrefixCmd, CMD_IS_SAFE},
    {"::tcl::process",	tclProcessImplMap,	TclSetUpProcessCmd, CMD_IS_SAFE},
    {"timer",		tclTimerImplMap,	NULL, CMD_IS_SAFE},
    {"unicode",		tclUnicodeImplMap,	NULL, CMD_IS_SAFE},
    {"zipfs",		tclZipfsImplMap,	NULL, 0},
    {"zlib",		tclZlibImplMap,		NULL, CMD_IS_SAFE},
    {"::tcl::unsupported::grapheme", tclGraphemeImplMap, NULL, 0},
    {NULL, NULL, NULL, 0}
};

/*
 * Math functions. All are safe.
 */








|







437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
    {"string",		tclStringImplMap,	NULL, CMD_IS_SAFE},
    {"::tcl::prefix",	tclPrefixImplMap,	TclSetUpPrefixCmd, CMD_IS_SAFE},
    {"::tcl::process",	tclProcessImplMap,	TclSetUpProcessCmd, CMD_IS_SAFE},
    {"timer",		tclTimerImplMap,	NULL, CMD_IS_SAFE},
    {"unicode",		tclUnicodeImplMap,	NULL, CMD_IS_SAFE},
    {"zipfs",		tclZipfsImplMap,	NULL, 0},
    {"zlib",		tclZlibImplMap,		NULL, CMD_IS_SAFE},
    {"::tcl::unsupported::grapheme", tclGraphemeImplMap, NULL, CMD_IS_SAFE},
    {NULL, NULL, NULL, 0}
};

/*
 * Math functions. All are safe.
 */

Changes to generic/tclCmdIL.c.
1357
1358
1359
1360
1361
1362
1363
1364

1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377




1378
1379
1380
1381
1382
1383
1384
1385
1386
    }

    /*
     * 'proc'. Common to all frame types. Conditional on having an associated
     * Procedure CallFrame.
     */

    if (procPtr != NULL) {

	Tcl_HashEntry *namePtr = procPtr->cmdPtr->hPtr;

	if (namePtr) {
	    Tcl_Obj *procNameObj;

	    /*
	     * This is a regular command.
	     */

	    TclNewObj(procNameObj);
	    Tcl_GetCommandFullName(interp, (Tcl_Command) procPtr->cmdPtr,
		    procNameObj);
	    ADD_PAIR("proc", procNameObj);




	} else if (procPtr->cmdPtr->clientData) {
	    ExtraFrameInfo *efiPtr = (ExtraFrameInfo *)procPtr->cmdPtr->clientData;
	    Tcl_Size i;

	    /*
	     * This is a non-standard command. Luckily, it's told us how to
	     * render extra information about its frame.
	     */








|
>
|









|


>
>
>
>
|
|







1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
    }

    /*
     * 'proc'. Common to all frame types. Conditional on having an associated
     * Procedure CallFrame.
     */

    if (procPtr != NULL && procPtr->cmdPtr) {
	Command *cmdPtr = procPtr->cmdPtr;
	Tcl_HashEntry *namePtr = cmdPtr->hPtr;

	if (namePtr) {
	    Tcl_Obj *procNameObj;

	    /*
	     * This is a regular command.
	     */

	    TclNewObj(procNameObj);
	    Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr,
		    procNameObj);
	    ADD_PAIR("proc", procNameObj);
	} else if ((procPtr->flags && PROC_CMD_OWNED) && !cmdPtr->objProc2 &&
		   cmdPtr->objClientData2
	) {
	    ADD_PAIR("lambda", (Tcl_Obj *)cmdPtr->objClientData2);
	} else if (cmdPtr->clientData) {
	    ExtraFrameInfo *efiPtr = (ExtraFrameInfo *)cmdPtr->clientData;
	    Tcl_Size i;

	    /*
	     * This is a non-standard command. Luckily, it's told us how to
	     * render extra information about its frame.
	     */

Changes to generic/tclDisassemble.c.
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], types, "type", 0, &idx)!=TCL_OK){
	return TCL_ERROR;
    }

    switch (idx) {
    case DISAS_LAMBDA: {
	Command cmd;
	Tcl_Obj *nsObjPtr;
	Tcl_Namespace *nsPtr;

	/*
	 * Compile (if uncompiled) and disassemble a lambda term.
	 */

	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "lambdaTerm");
	    return TCL_ERROR;
	}

	procPtr = TclGetLambdaFromObj(interp, objv[2], &nsObjPtr);
	if (procPtr == NULL) {
	    return TCL_ERROR;
	}

	memset(&cmd, 0, sizeof(Command));
	result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
	if (result != TCL_OK) {
	    return result;
	}
	cmd.nsPtr = (Namespace *) nsPtr;
	procPtr->cmdPtr = &cmd;
	result = TclPushProcCallFrame(procPtr, interp, objc, objv, 1);
	if (result != TCL_OK) {
	    return result;
	}
	TclPopStackFrame(interp);
	codeObjPtr = procPtr->bodyPtr;
	break;







<

<















<
<
<
<
<
<
<







1382
1383
1384
1385
1386
1387
1388

1389

1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404







1405
1406
1407
1408
1409
1410
1411
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], types, "type", 0, &idx)!=TCL_OK){
	return TCL_ERROR;
    }

    switch (idx) {
    case DISAS_LAMBDA: {

	Tcl_Obj *nsObjPtr;


	/*
	 * Compile (if uncompiled) and disassemble a lambda term.
	 */

	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "lambdaTerm");
	    return TCL_ERROR;
	}

	procPtr = TclGetLambdaFromObj(interp, objv[2], &nsObjPtr);
	if (procPtr == NULL) {
	    return TCL_ERROR;
	}








	result = TclPushProcCallFrame(procPtr, interp, objc, objv, 1);
	if (result != TCL_OK) {
	    return result;
	}
	TclPopStackFrame(interp);
	codeObjPtr = procPtr->bodyPtr;
	break;
Changes to generic/tclGrapheme.c.
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
 * in memory. It does not however help with random access.
 *
 * Note the list is read-only, so writing will cause shimmer to a native list.
 */
typedef struct GraphemeListRep {
    Tcl_Obj *objPtr;		/* The target string */
    Tcl_Size refCount;		/* Shared amongst Tcl_Obj's */
    Tcl_Size graphemeIndex;     /* Cached grapheme index */
    Tcl_Size graphemeOffset;	/* Corresponding Tcl_UniChar offset */
} GraphemeListRep;

static Tcl_DupInternalRepProc	GraphemeListDupProc;
static Tcl_FreeInternalRepProc	GraphemeListFreeProc;
static Tcl_ObjTypeLengthProc	GraphemeListLengthProc;
static Tcl_ObjTypeIndexProc	GraphemeListIndexProc;
const Tcl_ObjType tclGraphemeListType = {
    "graphemeList",
    GraphemeListFreeProc,
    GraphemeListDupProc,
    TclAbstractListUpdateString,
    NULL,			/* SetFromAny */
    TCL_OBJTYPE_V2(
	GraphemeListLengthProc,







|







|







84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
 * in memory. It does not however help with random access.
 *
 * Note the list is read-only, so writing will cause shimmer to a native list.
 */
typedef struct GraphemeListRep {
    Tcl_Obj *objPtr;		/* The target string */
    Tcl_Size refCount;		/* Shared amongst Tcl_Obj's */
    Tcl_Size graphemeIndex;	/* Cached grapheme index */
    Tcl_Size graphemeOffset;	/* Corresponding Tcl_UniChar offset */
} GraphemeListRep;

static Tcl_DupInternalRepProc	GraphemeListDupProc;
static Tcl_FreeInternalRepProc	GraphemeListFreeProc;
static Tcl_ObjTypeLengthProc	GraphemeListLengthProc;
static Tcl_ObjTypeIndexProc	GraphemeListIndexProc;
static const Tcl_ObjType tclGraphemeListType = {
    "graphemeList",
    GraphemeListFreeProc,
    GraphemeListDupProc,
    TclAbstractListUpdateString,
    NULL,			/* SetFromAny */
    TCL_OBJTYPE_V2(
	GraphemeListLengthProc,
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
 *
 * Side effects:
 *	None.
 *
 *------------------------------------------------------------------------
 */
static inline bool
IsPossibleContinuation (
    Tcl_UniChar cp)		/* Unicode code point */
{
    /*
     * https://www.unicode.org/reports/tr29/tr29-47.html
     */
    switch (utf8proc_get_property(cp)->boundclass) {
		/* postcore */







|







127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
 *
 * Side effects:
 *	None.
 *
 *------------------------------------------------------------------------
 */
static inline bool
IsPossibleContinuation(
    Tcl_UniChar cp)		/* Unicode code point */
{
    /*
     * https://www.unicode.org/reports/tr29/tr29-47.html
     */
    switch (utf8proc_get_property(cp)->boundclass) {
		/* postcore */
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
 *
 * Side effects:
 *	None.
 *
 *------------------------------------------------------------------------
 */
static inline bool
IsPossiblePrefix (
    Tcl_UniChar cp)		/* Unicode code point */
{
    const utf8proc_property_t *propPtr;
    propPtr = utf8proc_get_property(cp);
    return propPtr->boundclass == UTF8PROC_BOUNDCLASS_PREPEND
	|| propPtr->boundclass == UTF8PROC_BOUNDCLASS_ZWJ
	|| propPtr->boundclass == UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR
	|| propPtr->category == UTF8PROC_CATEGORY_MN
	|| propPtr->category == UTF8PROC_CATEGORY_MC
	|| propPtr->category == UTF8PROC_CATEGORY_ME;
}







|


|
|







170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
 *
 * Side effects:
 *	None.
 *
 *------------------------------------------------------------------------
 */
static inline bool
IsPossiblePrefix(
    Tcl_UniChar cp)		/* Unicode code point */
{
    const utf8proc_property_t *propPtr = utf8proc_get_property(cp);

    return propPtr->boundclass == UTF8PROC_BOUNDCLASS_PREPEND
	|| propPtr->boundclass == UTF8PROC_BOUNDCLASS_ZWJ
	|| propPtr->boundclass == UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR
	|| propPtr->category == UTF8PROC_CATEGORY_MN
	|| propPtr->category == UTF8PROC_CATEGORY_MC
	|| propPtr->category == UTF8PROC_CATEGORY_ME;
}
249
250
251
252
253
254
255
256

257
258
259
260
261
262
263
264
     * forward is that the backward scan is a conservative heuristic and
     * may go further back than it needs to. Therefore we have to work
     * forward again to skip over the extra scan.
     */
    const Tcl_UniChar *uniStartPtr = uniEndPtr - uniLen;
    const Tcl_UniChar *uniPtr = uniEndPtr - 1;
    while (uniPtr > uniStartPtr
	    && ((*uniPtr == '\n' && uniPtr[-1] == '\r') ||

		IsPossibleContinuation(*uniPtr) || IsPossiblePrefix(uniPtr[-1]))) {
	uniPtr--;
    }

    /* Now scan forward. Note uniPtr may be < uniStartPtr if uniLen was 0 */
    const Tcl_UniChar *grPtr;
    assert(uniEndPtr > uniPtr);
    do {







|
>
|







249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
     * forward is that the backward scan is a conservative heuristic and
     * may go further back than it needs to. Therefore we have to work
     * forward again to skip over the extra scan.
     */
    const Tcl_UniChar *uniStartPtr = uniEndPtr - uniLen;
    const Tcl_UniChar *uniPtr = uniEndPtr - 1;
    while (uniPtr > uniStartPtr
	    && ((*uniPtr == '\n' && uniPtr[-1] == '\r')
		|| IsPossibleContinuation(*uniPtr)
		|| IsPossiblePrefix(uniPtr[-1]))) {
	uniPtr--;
    }

    /* Now scan forward. Note uniPtr may be < uniStartPtr if uniLen was 0 */
    const Tcl_UniChar *grPtr;
    assert(uniEndPtr > uniPtr);
    do {
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
 *
 * Results:
 *	Number of graphemes in the string.
 *
 *------------------------------------------------------------------------
 */
static Tcl_Size
GraphemeLength (
    const Tcl_UniChar *uniPtr,	/* Tcl_UniChar string */
    Tcl_Size uniLen)		/* Number of Tcl_UniChar's in string. -1 if
				 * nul terminated */
{
    if (uniLen < 0) {
	uniLen = Tcl_UniCharLen(uniPtr);
    }







|







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
 *
 * Results:
 *	Number of graphemes in the string.
 *
 *------------------------------------------------------------------------
 */
static Tcl_Size
GraphemeLength(
    const Tcl_UniChar *uniPtr,	/* Tcl_UniChar string */
    Tcl_Size uniLen)		/* Number of Tcl_UniChar's in string. -1 if
				 * nul terminated */
{
    if (uniLen < 0) {
	uniLen = Tcl_UniCharLen(uniPtr);
    }
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
 *
 * Side effects:
 *	Modifies interpreter result and variable passed in objv[2].
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeNextCmd (
    TCL_UNUSED(void *),
    Tcl_Interp *interp,	/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "string strIndex");
	return TCL_ERROR;
    }

    Tcl_Size strIndex = 0;
    Tcl_Size uniLen;
    Tcl_UniChar *uniStartPtr = Tcl_GetUnicodeFromObj(objv[1], &uniLen);
    Tcl_Obj *indexObj = Tcl_ObjGetVar2(interp, objv[2], NULL, 0);







|

|




|







361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
 *
 * Side effects:
 *	Modifies interpreter result and variable passed in objv[2].
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeNextCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "string indexVar");
	return TCL_ERROR;
    }

    Tcl_Size strIndex = 0;
    Tcl_Size uniLen;
    Tcl_UniChar *uniStartPtr = Tcl_GetUnicodeFromObj(objv[1], &uniLen);
    Tcl_Obj *indexObj = Tcl_ObjGetVar2(interp, objv[2], NULL, 0);
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
 *
 * Side effects:
 *	Modifies interpreter result and variable passed in objv[2].
 *
 *------------------------------------------------------------------------
 */
static int
GraphemePrevCmd (
    TCL_UNUSED(void *),
    Tcl_Interp *interp,	/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "string strIndex");
	return TCL_ERROR;
    }

    Tcl_Size uniLen;
    const Tcl_UniChar *uniStartPtr = Tcl_GetUnicodeFromObj(objv[1], &uniLen);
    Tcl_Size strIndex = uniLen;








|

|




|







417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
 *
 * Side effects:
 *	Modifies interpreter result and variable passed in objv[2].
 *
 *------------------------------------------------------------------------
 */
static int
GraphemePrevCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "string indexVar");
	return TCL_ERROR;
    }

    Tcl_Size uniLen;
    const Tcl_UniChar *uniStartPtr = Tcl_GetUnicodeFromObj(objv[1], &uniLen);
    Tcl_Size strIndex = uniLen;

458
459
460
461
462
463
464
465

466
467
468
469
470
471
472
473
     */

    /* Scan backward to a safe starting point for the forward scan */
    const Tcl_UniChar *uniEndPtr = uniStartPtr + strIndex;
    const Tcl_UniChar *uniPtr = uniEndPtr - 1;

    while (uniPtr > uniStartPtr
	    && ((*uniPtr == '\n' && uniPtr[-1] == '\r') ||

		IsPossibleContinuation(*uniPtr) || IsPossiblePrefix(uniPtr[-1]))) {
	uniPtr--;
    }

    /* Now scan forward. Note uniPtr may be < uniStartPtr if uniLen was 0 */
    Tcl_Size grLen = 0;
    if (uniPtr >= uniStartPtr) {
	const Tcl_UniChar *grStartPtr;







|
>
|







459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
     */

    /* Scan backward to a safe starting point for the forward scan */
    const Tcl_UniChar *uniEndPtr = uniStartPtr + strIndex;
    const Tcl_UniChar *uniPtr = uniEndPtr - 1;

    while (uniPtr > uniStartPtr
	    && ((*uniPtr == '\n' && uniPtr[-1] == '\r')
		|| IsPossibleContinuation(*uniPtr)
		|| IsPossiblePrefix(uniPtr[-1]))) {
	uniPtr--;
    }

    /* Now scan forward. Note uniPtr may be < uniStartPtr if uniLen was 0 */
    Tcl_Size grLen = 0;
    if (uniPtr >= uniStartPtr) {
	const Tcl_UniChar *grStartPtr;
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
 *
 * Side effects:
 *	Modifies interpreter result.
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeLengthCmd (
    TCL_UNUSED(void *),
    Tcl_Interp *interp,	/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "string");
	return TCL_ERROR;
    }







|

|







499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
 *
 * Side effects:
 *	Modifies interpreter result.
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeLengthCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "string");
	return TCL_ERROR;
    }
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
 *
 * Side effects:
 *	Modifies interpreter result.
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeIndexCmd (
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "string grIndex");







|







533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
 *
 * Side effects:
 *	Modifies interpreter result.
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeIndexCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "string grIndex");
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
 *
 * Side effects:
 *	Modifies interpreter result.
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeOffsetCmd (
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "string grIndex");







|







579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
 *
 * Side effects:
 *	Modifies interpreter result.
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeOffsetCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "string grIndex");
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
 *
 * Side effects:
 *	Modifies interpreter result.
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeRangeCmd (
    TCL_UNUSED(void *),
    Tcl_Interp *interp,	/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 4) {
	Tcl_WrongNumArgs(interp, 1, objv, "string grFirst grLast");
	return TCL_ERROR;
    }







|

|







626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
 *
 * Side effects:
 *	Modifies interpreter result.
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeRangeCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 4) {
	Tcl_WrongNumArgs(interp, 1, objv, "string grFirst grLast");
	return TCL_ERROR;
    }
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
    rangeFirstPtr = GraphemeIndex(uniPtr, uniLen, grFirst, NULL);
    assert(rangeFirstPtr);
    rangeLastPtr = GraphemeIndex(rangeFirstPtr,
	    uniLen - (rangeFirstPtr - uniPtr), grLast - grFirst, &lastWidth);
    assert(rangeLastPtr);

    resultObj = Tcl_NewUnicodeObj(rangeFirstPtr,
			rangeLastPtr - rangeFirstPtr + lastWidth);
    Tcl_SetObjResult(interp, resultObj);
    return TCL_OK;
}

/*
 *------------------------------------------------------------------------
 *







|







666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
    rangeFirstPtr = GraphemeIndex(uniPtr, uniLen, grFirst, NULL);
    assert(rangeFirstPtr);
    rangeLastPtr = GraphemeIndex(rangeFirstPtr,
	    uniLen - (rangeFirstPtr - uniPtr), grLast - grFirst, &lastWidth);
    assert(rangeLastPtr);

    resultObj = Tcl_NewUnicodeObj(rangeFirstPtr,
	    rangeLastPtr - rangeFirstPtr + lastWidth);
    Tcl_SetObjResult(interp, resultObj);
    return TCL_OK;
}

/*
 *------------------------------------------------------------------------
 *
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
 *
 * Side effects:
 *	Modifies interpreter result.
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeReverseCmd (
    TCL_UNUSED(void *),
    Tcl_Interp *interp,	/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "string");
	return TCL_ERROR;
    }







|

|







688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
 *
 * Side effects:
 *	Modifies interpreter result.
 *
 *------------------------------------------------------------------------
 */
static int
GraphemeReverseCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "string");
	return TCL_ERROR;
    }
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732

    Tcl_Size uniLen;
    const Tcl_UniChar *uniPtr = Tcl_GetUnicodeFromObj(objv[1], &uniLen);
    if (uniLen == 0) {
	return TCL_OK;
    }
    const Tcl_UniChar *uniEndPtr = uniPtr + uniLen;
    Tcl_UniChar *tempBufPtr
	    = (Tcl_UniChar *)Tcl_Alloc(uniLen * sizeof(*tempBufPtr));
    Tcl_UniChar *tempPtr = tempBufPtr + uniLen;
    for (const Tcl_UniChar *grPtr = uniPtr; uniPtr < uniEndPtr; ) {
	Tcl_Size grWidth;
	uniPtr = GraphemeNext(uniPtr, uniEndPtr - uniPtr);
	grWidth = uniPtr - grPtr;
	tempPtr -= grWidth;
	assert(tempPtr >= tempBufPtr);
	memcpy(tempPtr, grPtr, sizeof(Tcl_UniChar) * grWidth);
	grPtr = uniPtr;
    }
    assert(tempPtr == tempBufPtr);
    Tcl_SetObjResult(interp, Tcl_NewUnicodeObj(tempBufPtr, uniLen));







|
|


<

|







714
715
716
717
718
719
720
721
722
723
724

725
726
727
728
729
730
731
732
733

    Tcl_Size uniLen;
    const Tcl_UniChar *uniPtr = Tcl_GetUnicodeFromObj(objv[1], &uniLen);
    if (uniLen == 0) {
	return TCL_OK;
    }
    const Tcl_UniChar *uniEndPtr = uniPtr + uniLen;
    Tcl_UniChar *tempBufPtr = (Tcl_UniChar *)
	    Tcl_Alloc(uniLen * sizeof(*tempBufPtr));
    Tcl_UniChar *tempPtr = tempBufPtr + uniLen;
    for (const Tcl_UniChar *grPtr = uniPtr; uniPtr < uniEndPtr; ) {

	uniPtr = GraphemeNext(uniPtr, uniEndPtr - uniPtr);
	Tcl_Size grWidth = uniPtr - grPtr;
	tempPtr -= grWidth;
	assert(tempPtr >= tempBufPtr);
	memcpy(tempPtr, grPtr, sizeof(Tcl_UniChar) * grWidth);
	grPtr = uniPtr;
    }
    assert(tempPtr == tempBufPtr);
    Tcl_SetObjResult(interp, Tcl_NewUnicodeObj(tempBufPtr, uniLen));
771
772
773
774
775
776
777
778

779
780
781
782
783
784
785
786
787
788
789
790
791
792











































793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
 *
 * Results:
 *	None.
 *
 *------------------------------------------------------------------------
 */
static inline void
GraphemeListRepDecrRefs(GraphemeListRep *glrPtr)

{
    if (glrPtr->refCount <= 1) {
	if (glrPtr->objPtr != NULL) {
	    Tcl_DecrRefCount(glrPtr->objPtr);
	}
	Tcl_Free(glrPtr);
    } else {
	glrPtr->refCount--;
    }
}

/*
 *----------------------------------------------------------------------
 *











































 * GraphemeListFreeProc --
 *
 *      Frees resources associated with a GraphemeList object's
 *      internal representation.
 *
 * Results:
 *	None
 *
 *----------------------------------------------------------------------
 */

static void
GraphemeListFreeProc(
    Tcl_Obj *objPtr)
{
    GraphemeListRepDecrRefs(
	    (GraphemeListRep *)objPtr->internalRep.otherValuePtr);
}

/*
 *----------------------------------------------------------------------
 *
 * GraphemeListDupProc --
 *







|
>














>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


|
|






<




|
<







772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847

848
849
850
851
852

853
854
855
856
857
858
859
 *
 * Results:
 *	None.
 *
 *------------------------------------------------------------------------
 */
static inline void
GraphemeListRepDecrRefs(
    GraphemeListRep *glrPtr)
{
    if (glrPtr->refCount <= 1) {
	if (glrPtr->objPtr != NULL) {
	    Tcl_DecrRefCount(glrPtr->objPtr);
	}
	Tcl_Free(glrPtr);
    } else {
	glrPtr->refCount--;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * GetGraphemeListRep --
 *
 *	Get the internal representation of a grapheme list from a Tcl_Obj.
 *	Assumes that the object is of the right type already.
 *
 * Results:
 *	The internal representation.
 *
 *----------------------------------------------------------------------
 */
static inline GraphemeListRep *
GetGraphemeListRep(
    Tcl_Obj *objPtr)
{
    return (GraphemeListRep *) objPtr->internalRep.otherValuePtr;
}

/*
 *----------------------------------------------------------------------
 *
 * SetGraphemeListRep --
 *
 *	Set the type and internal representation of a Tcl_Obj to a grapheme
 *	list. Doesn't manipulate the reference count of the internal rep or
 *	clear any old internal representation from the Tcl_Obj.
 *
 * Results:
 *	None.
 *
 *----------------------------------------------------------------------
 */
static inline void
SetGraphemeListRep(
    Tcl_Obj *objPtr,
    GraphemeListRep *glrPtr)
{
    objPtr->internalRep.otherValuePtr = glrPtr;
    objPtr->typePtr = &tclGraphemeListType;
}

/*
 *----------------------------------------------------------------------
 *
 * GraphemeListFreeProc --
 *
 *	Frees resources associated with a GraphemeList object's
 *	internal representation.
 *
 * Results:
 *	None
 *
 *----------------------------------------------------------------------
 */

static void
GraphemeListFreeProc(
    Tcl_Obj *objPtr)
{
    GraphemeListRepDecrRefs(GetGraphemeListRep(objPtr));

}

/*
 *----------------------------------------------------------------------
 *
 * GraphemeListDupProc --
 *
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
static void
GraphemeListDupProc(
    Tcl_Obj *srcPtr,		/* Object with internal rep to copy. Must have
				 * an internal rep of type "graphemeList". */
    Tcl_Obj *copyPtr)		/* Object with internal rep to set. Must not
				 * currently have an internal rep.*/
{
    copyPtr->internalRep.otherValuePtr = srcPtr->internalRep.otherValuePtr;
    ((GraphemeListRep *)srcPtr->internalRep.otherValuePtr)->refCount++;
    copyPtr->typePtr = srcPtr->typePtr;
}

/*
 *------------------------------------------------------------------------
 *
 * GraphemeListLengthProc --
 *
 *	Returns the number of elements in a GraphemeList.
 *
 * Results:
 *	Count of graphemes.
 *
 * Side effects:
 *	None.
 *
 *------------------------------------------------------------------------
 */
Tcl_Size
GraphemeListLengthProc (
    Tcl_Obj *objPtr
)
{
    GraphemeListRep *glrPtr = (GraphemeListRep *) objPtr->internalRep.otherValuePtr;
    Tcl_Size uniLen;
    Tcl_UniChar *uniPtr = Tcl_GetUnicodeFromObj(glrPtr->objPtr, &uniLen);
    return GraphemeLength(uniPtr, uniLen);
}

/*
 *------------------------------------------------------------------------







|
|
<

|
















|
|
<

|







872
873
874
875
876
877
878
879
880

881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900

901
902
903
904
905
906
907
908
909
static void
GraphemeListDupProc(
    Tcl_Obj *srcPtr,		/* Object with internal rep to copy. Must have
				 * an internal rep of type "graphemeList". */
    Tcl_Obj *copyPtr)		/* Object with internal rep to set. Must not
				 * currently have an internal rep.*/
{
    SetGraphemeListRep(copyPtr, GetGraphemeListRep(srcPtr));
    GetGraphemeListRep(srcPtr)->refCount++;

}

/*
 *------------------------------------------------------------------------
 *
 * GraphemeListLengthProc --
 *
 *	Returns the number of elements in a GraphemeList.
 *
 * Results:
 *	Count of graphemes.
 *
 * Side effects:
 *	None.
 *
 *------------------------------------------------------------------------
 */
Tcl_Size
GraphemeListLengthProc(
    Tcl_Obj *objPtr)

{
    GraphemeListRep *glrPtr = GetGraphemeListRep(objPtr);
    Tcl_Size uniLen;
    Tcl_UniChar *uniPtr = Tcl_GetUnicodeFromObj(glrPtr->objPtr, &uniLen);
    return GraphemeLength(uniPtr, uniLen);
}

/*
 *------------------------------------------------------------------------
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
 *
 * Side effects:
 *	None.
 *
 *------------------------------------------------------------------------
 */
int
GraphemeListIndexProc (
    TCL_UNUSED(Tcl_Interp *),
    Tcl_Obj *objPtr,		/* Source list */
    Tcl_Size index,		/* Element index */
    Tcl_Obj **elemPtrPtr)	/* Returned element */
{
    GraphemeListRep *glrPtr = (GraphemeListRep *) objPtr->internalRep.otherValuePtr;
    Tcl_Size uniLen;
    const Tcl_UniChar *uniStartPtr = Tcl_GetUnicodeFromObj(glrPtr->objPtr, &uniLen);
    const Tcl_UniChar *grPtr = NULL;
    Tcl_Size grWidth = 0;

    /*
     * We will use the cached index or start from 0 depending on







|





|







917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
 *
 * Side effects:
 *	None.
 *
 *------------------------------------------------------------------------
 */
int
GraphemeListIndexProc(
    TCL_UNUSED(Tcl_Interp *),
    Tcl_Obj *objPtr,		/* Source list */
    Tcl_Size index,		/* Element index */
    Tcl_Obj **elemPtrPtr)	/* Returned element */
{
    GraphemeListRep *glrPtr = GetGraphemeListRep(objPtr);
    Tcl_Size uniLen;
    const Tcl_UniChar *uniStartPtr = Tcl_GetUnicodeFromObj(glrPtr->objPtr, &uniLen);
    const Tcl_UniChar *grPtr = NULL;
    Tcl_Size grWidth = 0;

    /*
     * We will use the cached index or start from 0 depending on
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
 *
 * Side effects:
 *	Interpreter result holds result or error message.
 *
 *------------------------------------------------------------------------
 */
int
GraphemeSplitCmd (
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "string");
	return TCL_ERROR;
    }

    Tcl_Obj *objPtr;
    TclNewObj(objPtr);
    objPtr->typePtr = &tclGraphemeListType;
    GraphemeListRep *glrPtr = GraphemeListRepNew(objv[1]);
    glrPtr->refCount = 1;
    objPtr->internalRep.otherValuePtr = glrPtr;
    Tcl_InvalidateStringRep(objPtr);
    Tcl_SetObjResult(interp, objPtr);
    return TCL_OK;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */







|












<


|




|







996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015

1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
 *
 * Side effects:
 *	Interpreter result holds result or error message.
 *
 *------------------------------------------------------------------------
 */
int
GraphemeSplitCmd(
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    if (objc != 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "string");
	return TCL_ERROR;
    }

    Tcl_Obj *objPtr;
    TclNewObj(objPtr);

    GraphemeListRep *glrPtr = GraphemeListRepNew(objv[1]);
    glrPtr->refCount = 1;
    SetGraphemeListRep(objPtr, glrPtr);
    Tcl_InvalidateStringRep(objPtr);
    Tcl_SetObjResult(interp, objPtr);
    return TCL_OK;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */
Changes to generic/tclInt.h.
1045
1046
1047
1048
1049
1050
1051

1052



1053
1054
1055
1056
1057
1058
1059
				 * compiler-allocated local variables, or NULL
				 * if none. The first numArgs entries in this
				 * list describe the procedure's formal
				 * arguments. */
    CompiledLocal *lastLocalPtr;/* Pointer to the last allocated local
				 * variable or NULL if none. This has frame
				 * index (numCompiledLocals-1). */

} Proc;




/*
 * The type of functions called to process errors found during the execution
 * of a procedure (or lambda term or ...).
 */

typedef void (ProcErrorProc)(Tcl_Interp *interp, Tcl_Obj *procNameObj);







>

>
>
>







1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
				 * compiler-allocated local variables, or NULL
				 * if none. The first numArgs entries in this
				 * list describe the procedure's formal
				 * arguments. */
    CompiledLocal *lastLocalPtr;/* Pointer to the last allocated local
				 * variable or NULL if none. This has frame
				 * index (numCompiledLocals-1). */
    int flags;			/* Miscellaneous bits of proc. */
} Proc;

#define PROC_CMD_OWNED		0x80


/*
 * The type of functions called to process errors found during the execution
 * of a procedure (or lambda term or ...).
 */

typedef void (ProcErrorProc)(Tcl_Interp *interp, Tcl_Obj *procNameObj);
Changes to generic/tclProc.c.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * Variables that are part of the [apply] command implementation and which
 * have to be passed to the other side of the NRE call.
 */

typedef struct {
    Command cmd;
    ExtraFrameInfo efi;
} ApplyExtraData;

/*
 * Prototypes for static functions in this file
 */

static void		DupLambdaInternalRep(Tcl_Obj *objPtr,
			    Tcl_Obj *copyPtr);







|
<
<
<
<
<
<
<
<
<







11
12
13
14
15
16
17
18









19
20
21
22
23
24
25
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tclInt.h"
#include "tclCompile.h"
#include <assert.h>










/*
 * Prototypes for static functions in this file
 */

static void		DupLambdaInternalRep(Tcl_Obj *objPtr,
			    Tcl_Obj *copyPtr);
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
static int		ProcWrongNumArgs(Tcl_Interp *interp, Tcl_Size skip);
static void		MakeProcError(Tcl_Interp *interp,
			    Tcl_Obj *procNameObj);
static void		MakeLambdaError(Tcl_Interp *interp,
			    Tcl_Obj *procNameObj);
static int		SetLambdaFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);

static Tcl_NRPostProc ApplyNR2;
static Tcl_NRPostProc InterpProcNR2;

/*
 * The ProcBodyObjType type
 */

const Tcl_ObjType tclProcBodyType = {







<







34
35
36
37
38
39
40

41
42
43
44
45
46
47
static int		ProcWrongNumArgs(Tcl_Interp *interp, Tcl_Size skip);
static void		MakeProcError(Tcl_Interp *interp,
			    Tcl_Obj *procNameObj);
static void		MakeLambdaError(Tcl_Interp *interp,
			    Tcl_Obj *procNameObj);
static int		SetLambdaFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);


static Tcl_NRPostProc InterpProcNR2;

/*
 * The ProcBodyObjType type
 */

const Tcl_ObjType tclProcBodyType = {
478
479
480
481
482
483
484

485
486
487
488
489
490
491
	procPtr->iPtr = iPtr;
	procPtr->refCount = 1;
	procPtr->bodyPtr = bodyPtr;
	procPtr->numArgs = 0;	/* Actual argument count is set below. */
	procPtr->numCompiledLocals = 0;
	procPtr->firstLocalPtr = NULL;
	procPtr->lastLocalPtr = NULL;

    }

    /*
     * Break up the argument list into argument specifiers, then process each
     * argument specifier. If the body is precompiled, processing is limited
     * to checking that the parsed argument is consistent with the one stored
     * in the Proc.







>







468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
	procPtr->iPtr = iPtr;
	procPtr->refCount = 1;
	procPtr->bodyPtr = bodyPtr;
	procPtr->numArgs = 0;	/* Actual argument count is set below. */
	procPtr->numCompiledLocals = 0;
	procPtr->firstLocalPtr = NULL;
	procPtr->lastLocalPtr = NULL;
	procPtr->flags = 0;
    }

    /*
     * Break up the argument list into argument specifiers, then process each
     * argument specifier. If the body is precompiled, processing is limited
     * to checking that the parsed argument is consistent with the one stored
     * in the Proc.
2191
2192
2193
2194
2195
2196
2197










2198
2199
2200
2201
2202
2203
2204
	if (localPtr->defValuePtr != NULL) {
	    defPtr = localPtr->defValuePtr;
	    Tcl_DecrRefCount(defPtr);
	}
	Tcl_Free(localPtr);
	localPtr = nextPtr;
    }










    Tcl_Free(procPtr);

    /*
     * TIP #280: Release the location data associated with this Proc
     * structure, if any. The interpreter may not exist (For example for
     * procbody structures created by tbcload.
     */







>
>
>
>
>
>
>
>
>
>







2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
	if (localPtr->defValuePtr != NULL) {
	    defPtr = localPtr->defValuePtr;
	    Tcl_DecrRefCount(defPtr);
	}
	Tcl_Free(localPtr);
	localPtr = nextPtr;
    }

    if ( procPtr->cmdPtr && (procPtr->flags & PROC_CMD_OWNED)
      && procPtr->cmdPtr->refCount-- <= 1
    ) {
	/* cmdPtr owned by procPtr (lambda) */
	if (procPtr->cmdPtr->nsPtr) {
	    TclNsDecrRefCount(procPtr->cmdPtr->nsPtr);
	}
	Tcl_Free(procPtr->cmdPtr);
    }
    Tcl_Free(procPtr);

    /*
     * TIP #280: Release the location data associated with this Proc
     * structure, if any. The interpreter may not exist (For example for
     * procbody structures created by tbcload.
     */
2460
2461
2462
2463
2464
2465
2466


2467
2468
2469
2470
2471
2472
2473
    Interp *iPtr = (Interp *) interp;
    const char *name;
    Tcl_Obj *argsPtr, *bodyPtr, *nsObjPtr, **objv;
    int result;
    Tcl_Size objc;
    CmdFrame *cfPtr = NULL;
    Proc *procPtr;



    if (interp == NULL) {
	return TCL_ERROR;
    }

    /*
     * Convert objPtr to list type first; if it cannot be converted, or if its







>
>







2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
    Interp *iPtr = (Interp *) interp;
    const char *name;
    Tcl_Obj *argsPtr, *bodyPtr, *nsObjPtr, **objv;
    int result;
    Tcl_Size objc;
    CmdFrame *cfPtr = NULL;
    Proc *procPtr;
    Tcl_Namespace *nsPtr;
    Command *cmdPtr;

    if (interp == NULL) {
	return TCL_ERROR;
    }

    /*
     * Convert objPtr to list type first; if it cannot be converted, or if its
2486
2487
2488
2489
2490
2491
2492

























2493
2494
2495
2496
2497
2498
2499

2500
2501
2502
2503
2504
2505
2506
2507

2508
2509
2510
2511
2512
2513
2514
2515






2516

2517
2518
2519
2520
2521
2522
2523
    if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"can't interpret \"%s\" as a lambda expression",
		TclGetString(objPtr)));
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "LAMBDA", (char *)NULL);
	return TCL_ERROR;
    }


























    argsPtr = objv[0];
    bodyPtr = objv[1];

    /*
     * Create and initialize the Proc struct. The cmdPtr field is set to NULL
     * to signal that this is an anonymous function.

     */

    name = TclGetString(objPtr);

    if (TclCreateProc(interp, /*ignored nsPtr*/ NULL, name, argsPtr, bodyPtr,
	    &procPtr) != TCL_OK) {
	Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
		"\n    (parsing lambda expression \"%s\")", name));

	return TCL_ERROR;
    }

    /*
     * CAREFUL: TclCreateProc returns refCount==1! [Bug 1578454]
     * procPtr->refCount = 1;
     */







    procPtr->cmdPtr = NULL;


    /*
     * TIP #280: Remember the line the apply body is starting on. In a Byte
     * code context we ask the engine to provide us with the necessary
     * information. This is for the initialization of the byte code compiler
     * when the body is used for the first time.
     *







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|
|
>








>








>
>
>
>
>
>
|
>







2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
    if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		"can't interpret \"%s\" as a lambda expression",
		TclGetString(objPtr)));
	Tcl_SetErrorCode(interp, "TCL", "VALUE", "LAMBDA", (char *)NULL);
	return TCL_ERROR;
    }

    /*
     * Set the namespace for this lambda: given by objv[2] understood as a
     * global reference, or else global per default.
     */

    if (objc == 2) {
	TclNewLiteralStringObj(nsObjPtr, "::");
    } else {
	const char *nsName = TclGetString(objv[2]);

	if ((*nsName != ':') || (*(nsName+1) != ':')) {
	    TclNewLiteralStringObj(nsObjPtr, "::");
	    Tcl_AppendObjToObj(nsObjPtr, objv[2]);
	} else {
	    nsObjPtr = objv[2];
	}
    }
    Tcl_IncrRefCount(nsObjPtr);
    /* Find the namespace where this lambda should run. */
    result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
    if (result != TCL_OK) {
	Tcl_DecrRefCount(nsObjPtr);
	return TCL_ERROR;
    }

    argsPtr = objv[0];
    bodyPtr = objv[1];

    /*
     * Create and initialize the Proc struct. The cmdPtr field is set to
     * artificial command owned by the procPtr with few info, e. g. used
     * in TclInfoFrame.
     */

    name = TclGetString(objPtr);

    if (TclCreateProc(interp, /*ignored nsPtr*/ NULL, name, argsPtr, bodyPtr,
	    &procPtr) != TCL_OK) {
	Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
		"\n    (parsing lambda expression \"%s\")", name));
	Tcl_DecrRefCount(nsObjPtr);
	return TCL_ERROR;
    }

    /*
     * CAREFUL: TclCreateProc returns refCount==1! [Bug 1578454]
     * procPtr->refCount = 1;
     */

    cmdPtr = (Command *)Tcl_Alloc(sizeof(Command));
    memset(cmdPtr, 0, sizeof(*cmdPtr));
    cmdPtr->nsPtr = (Namespace *) nsPtr;
    ((Namespace *)nsPtr)->refCount++;
    cmdPtr->objClientData2 = objPtr;
    cmdPtr->refCount++;
    procPtr->cmdPtr = cmdPtr;
    procPtr->flags = PROC_CMD_OWNED;

    /*
     * TIP #280: Remember the line the apply body is starting on. In a Byte
     * code context we ask the engine to provide us with the necessary
     * information. This is for the initialization of the byte code compiler
     * when the body is used for the first time.
     *
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628

2629
2630
2631
2632
2633
2634
2635
	    Tcl_DecrRefCount(contextPtr->data.eval.path);
	}
	TclStackFree(interp, contextPtr);
    }
    Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->linePBodyPtr, procPtr,
	    NULL), cfPtr);

    /*
     * Set the namespace for this lambda: given by objv[2] understood as a
     * global reference, or else global per default.
     */

    if (objc == 2) {
	TclNewLiteralStringObj(nsObjPtr, "::");
    } else {
	const char *nsName = TclGetString(objv[2]);

	if ((nsName[0] != ':') || (nsName[1] != ':')) {
	    TclNewLiteralStringObj(nsObjPtr, "::");
	    Tcl_AppendObjToObj(nsObjPtr, objv[2]);
	} else {
	    nsObjPtr = objv[2];
	}
    }

    /*
     * Free the list internalrep of objPtr - this will free argsPtr, but
     * bodyPtr retains a reference from the Proc structure. Then finish the
     * conversion to lambdaType.
     */

    LambdaSetInternalRep(objPtr, procPtr, nsObjPtr);

    return TCL_OK;
}

Proc *
TclGetLambdaFromObj(
    Tcl_Interp *interp,
    Tcl_Obj *objPtr,







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







>







2634
2635
2636
2637
2638
2639
2640


















2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
	    Tcl_DecrRefCount(contextPtr->data.eval.path);
	}
	TclStackFree(interp, contextPtr);
    }
    Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->linePBodyPtr, procPtr,
	    NULL), cfPtr);



















    /*
     * Free the list internalrep of objPtr - this will free argsPtr, but
     * bodyPtr retains a reference from the Proc structure. Then finish the
     * conversion to lambdaType.
     */

    LambdaSetInternalRep(objPtr, procPtr, nsObjPtr);
    Tcl_DecrRefCount(nsObjPtr);
    return TCL_OK;
}

Proc *
TclGetLambdaFromObj(
    Tcl_Interp *interp,
    Tcl_Obj *objPtr,
2644
2645
2646
2647
2648
2649
2650

2651









2652



2653
2654
2655
2656
2657
2658
2659
	if (SetLambdaFromAny(interp, objPtr) != TCL_OK) {
	    return NULL;
	}
	LambdaGetInternalRep(objPtr, procPtr, nsObjPtr);
    }

    assert(procPtr != NULL);

    if (procPtr->iPtr != (Interp *)interp) {









	return NULL;



    }

    *nsObjPtrPtr = nsObjPtr;
    return procPtr;
}

/*







>
|
>
>
>
>
>
>
>
>
>
|
>
>
>







2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
	if (SetLambdaFromAny(interp, objPtr) != TCL_OK) {
	    return NULL;
	}
	LambdaGetInternalRep(objPtr, procPtr, nsObjPtr);
    }

    assert(procPtr != NULL);
    assert(procPtr->cmdPtr != NULL);

    if (!procPtr->cmdPtr->nsPtr || procPtr->cmdPtr->nsPtr->flags & NS_DEAD) {
	Command *cmdPtr = procPtr->cmdPtr;
	Tcl_Namespace *nsPtr;
	if (cmdPtr->nsPtr) {
	    TclNsDecrRefCount(cmdPtr->nsPtr);
	    cmdPtr->nsPtr = NULL;
	}
	/* Retry to obtain namespace again... */
	if (TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr) != TCL_OK) {
	    return NULL;
	}
	cmdPtr->nsPtr = (Namespace *) nsPtr;
	((Namespace *)nsPtr)->refCount++;
    }

    *nsObjPtrPtr = nsObjPtr;
    return procPtr;
}

/*
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const *objv)	/* Argument objects. */
{
    Proc *procPtr = NULL;
    Tcl_Obj *lambdaPtr, *nsObjPtr;
    int result;
    Tcl_Namespace *nsPtr;
    ApplyExtraData *extraPtr;

    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "lambdaExpr ?arg ...?");
	return TCL_ERROR;
    }

    /*
     * Set lambdaPtr, convert it to tclLambdaType in the current interp if
     * necessary.
     */

    lambdaPtr = objv[1];
    procPtr = TclGetLambdaFromObj(interp, lambdaPtr, &nsObjPtr);

    if (procPtr == NULL) {
	return TCL_ERROR;
    }

    /*
     * Push a call frame for the lambda namespace.
     * Note that TclObjInterpProc2() will pop it.
     */

    result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
    if (result != TCL_OK) {
	return TCL_ERROR;
    }

    extraPtr = (ApplyExtraData *)TclStackAlloc(interp, sizeof(ApplyExtraData));
    memset(&extraPtr->cmd, 0, sizeof(Command));
    procPtr->cmdPtr = &extraPtr->cmd;
    extraPtr->cmd.nsPtr = (Namespace *) nsPtr;

    /*
     * TIP#280 (semi-)HACK!
     *
     * Using cmd.clientData to tell [info frame] how to render the lambdaPtr.
     * The InfoFrameCmd will detect this case by testing cmd.hPtr for NULL.
     * This condition holds here because of the memset() above, and nowhere
     * else (in the core). Regular commands always have a valid hPtr, and
     * lambda's never.
     */

    extraPtr->efi.length = 1;
    extraPtr->efi.fields[0].name = "lambda";
    extraPtr->efi.fields[0].proc = NULL;
    extraPtr->efi.fields[0].clientData = lambdaPtr;
    extraPtr->cmd.clientData = &extraPtr->efi;

    result = TclPushProcCallFrame(procPtr, interp, objc, objv, 1);
    if (result == TCL_OK) {
	TclNRAddCallback(interp, ApplyNR2, extraPtr, NULL, NULL, NULL);
	result = TclNRInterpProcCore(interp, objv[1], 2, &MakeLambdaError);
    }
    return result;
}

static int
ApplyNR2(
    void *data[],
    Tcl_Interp *interp,
    int result)
{
    ApplyExtraData *extraPtr = (ApplyExtraData *)data[0];

    TclStackFree(interp, extraPtr);
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * MakeLambdaError --
 *
 *	Function called by TclObjInterpProc2 to create the stack information







<
<



















|
|

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


<




<
<
<
<
<
<
<
<
<
<
<
<







2722
2723
2724
2725
2726
2727
2728


2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750



























2751
2752

2753
2754
2755
2756












2757
2758
2759
2760
2761
2762
2763
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Size objc,		/* Number of arguments. */
    Tcl_Obj *const *objv)	/* Argument objects. */
{
    Proc *procPtr = NULL;
    Tcl_Obj *lambdaPtr, *nsObjPtr;
    int result;



    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "lambdaExpr ?arg ...?");
	return TCL_ERROR;
    }

    /*
     * Set lambdaPtr, convert it to tclLambdaType in the current interp if
     * necessary.
     */

    lambdaPtr = objv[1];
    procPtr = TclGetLambdaFromObj(interp, lambdaPtr, &nsObjPtr);

    if (procPtr == NULL) {
	return TCL_ERROR;
    }

    /*
     * Push a call frame for that procPtr. Note that TclNRInterpProcCore()
     * will pop it (NRE-based).
     */



























    result = TclPushProcCallFrame(procPtr, interp, objc, objv, 1);
    if (result == TCL_OK) {

	result = TclNRInterpProcCore(interp, objv[1], 2, &MakeLambdaError);
    }
    return result;
}













/*
 *----------------------------------------------------------------------
 *
 * MakeLambdaError --
 *
 *	Function called by TclObjInterpProc2 to create the stack information
2915
2916
2917
2918
2919
2920
2921

2922
2923
2924
2925
2926
2927
2928
    newProc->iPtr = iPtr;
    newProc->refCount = 1;
    newProc->bodyPtr = bodyPtr;
    newProc->numArgs = origProc->numArgs;
    newProc->numCompiledLocals = origProc->numArgs;
    newProc->firstLocalPtr = NULL;
    newProc->lastLocalPtr = NULL;


    // Work through the original arguments, duplicating them.
    const CompiledLocal *origLocal = origProc->firstLocalPtr;
    for (Tcl_Size i = 0; i < newProc->numArgs; i++) {
	if (DuplicateArgument(newProc, origLocal, i) != TCL_OK) {
	    // Don't set the interp result here. Since a malloc just failed,
	    // first clean up some memory before doing that */







>







2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
    newProc->iPtr = iPtr;
    newProc->refCount = 1;
    newProc->bodyPtr = bodyPtr;
    newProc->numArgs = origProc->numArgs;
    newProc->numCompiledLocals = origProc->numArgs;
    newProc->firstLocalPtr = NULL;
    newProc->lastLocalPtr = NULL;
    newProc->flags = 0;

    // Work through the original arguments, duplicating them.
    const CompiledLocal *origLocal = origProc->firstLocalPtr;
    for (Tcl_Size i = 0; i < newProc->numArgs; i++) {
	if (DuplicateArgument(newProc, origLocal, i) != TCL_OK) {
	    // Don't set the interp result here. Since a malloc just failed,
	    // first clean up some memory before doing that */
Changes to tests/apply.test.
80
81
82
83
84
85
86













87
88
89
90
91
92
93
test apply-3.2 {non-existing namespace} -body {
    namespace eval ::NONEXIST::FOR::SURE {}
    set lambda [list x {set x 1} ::NONEXIST::FOR::SURE]
    apply $lambda x
    namespace delete ::NONEXIST
    apply $lambda x
} -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found}













test apply-3.3 {non-existing namespace} -body {
    apply [list x {set x 1} NONEXIST::FOR::SURE] x
} -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found}
test apply-3.4 {non-existing namespace} -body {
    namespace eval ::NONEXIST::FOR::SURE {}
    set lambda [list x {set x 1} NONEXIST::FOR::SURE]
    apply $lambda x







>
>
>
>
>
>
>
>
>
>
>
>
>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
test apply-3.2 {non-existing namespace} -body {
    namespace eval ::NONEXIST::FOR::SURE {}
    set lambda [list x {set x 1} ::NONEXIST::FOR::SURE]
    apply $lambda x
    namespace delete ::NONEXIST
    apply $lambda x
} -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found}
test apply-3.2.2 {non-existing namespace (recreated between apply-calls)} -body {
    set res {}
    namespace eval ::NONEXIST::FOR::SURE {}
    set lambda {{step} {variable x; lappend x $step} ::NONEXIST::FOR::SURE}
    lappend res [catch { apply $lambda A} x] $x
    namespace delete ::NONEXIST
    lappend res [catch { apply $lambda B} x] $x
    namespace eval ::NONEXIST::FOR::SURE {}
    lappend res [catch { apply $lambda C} x] $x
    set res
} -cleanup {
    namespace delete ::NONEXIST
} -result {0 A 1 {namespace "::NONEXIST::FOR::SURE" not found} 0 C}
test apply-3.3 {non-existing namespace} -body {
    apply [list x {set x 1} NONEXIST::FOR::SURE] x
} -returnCodes error -result {namespace "::NONEXIST::FOR::SURE" not found}
test apply-3.4 {non-existing namespace} -body {
    namespace eval ::NONEXIST::FOR::SURE {}
    set lambda [list x {set x 1} NONEXIST::FOR::SURE]
    apply $lambda x
305
306
307
308
309
310
311









312
313
314
315
316
317
318
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $tmp}]
} -cleanup {
    rename getbytes {}
    unset -nocomplain end i x tmp leakedBytes
} -result 0










# Tests for specific bugs
test apply-10.1 {Test for precompiled bytecode body} -constraints {
    applylambda
} -body {
    testapplylambda
} -result 42







>
>
>
>
>
>
>
>
>







318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
	set end [getbytes]
    }
    set leakedBytes [expr {$end - $tmp}]
} -cleanup {
    rename getbytes {}
    unset -nocomplain end i x tmp leakedBytes
} -result 0
test apply-9.4 {lambda representation may shimmer during invocation} -setup {
    set ::t {apply {n {
	expr {[llength [lindex $::t 1 1 1]] + $n}
    }} _}
} -body {
    {*}[lset ::t end 123]
} -cleanup {
    unset -nocomplain ::t
} -result {131}

# Tests for specific bugs
test apply-10.1 {Test for precompiled bytecode body} -constraints {
    applylambda
} -body {
    testapplylambda
} -result 42
Changes to tests/grapheme.test.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

    # The -ucd- tests all run off the test vectors from the Unicode Character
    # Database. The test numbering is based on the corresponding line from
    # the GraphemeBreakTest.txt file and may therefore be unstable.

    ### grapheme next

    tcltests::testnumargs "grapheme next" "string strIndex" ""

    foreach testCase [list [list 0 "empty string" ""] {*}[getGraphemeData]] {
	lassign $testCase testNum comment graphemes
	test grapheme-next-ucd-$testNum.0 $comment -body {
	    set text [join $graphemes ""]
	    set l {}
	    set i 0
	    while {[set grapheme [grapheme next $text i]] ne ""} {
		lappend l $grapheme
	    }
	    set l
	} -result $graphemes
    }

    ### grapheme prev

    tcltests::testnumargs "grapheme prev" "string strIndex" ""

    foreach testCase [list [list 0 "empty string" ""] {*}[getGraphemeData]] {
	lassign $testCase testNum comment graphemes
	test grapheme-prev-ucd-$testNum.0 $comment -body {
	    set text [join $graphemes ""]
	    set l {}
	    set i end







|
















|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

    # The -ucd- tests all run off the test vectors from the Unicode Character
    # Database. The test numbering is based on the corresponding line from
    # the GraphemeBreakTest.txt file and may therefore be unstable.

    ### grapheme next

    tcltests::testnumargs "grapheme next" "string indexVar" ""

    foreach testCase [list [list 0 "empty string" ""] {*}[getGraphemeData]] {
	lassign $testCase testNum comment graphemes
	test grapheme-next-ucd-$testNum.0 $comment -body {
	    set text [join $graphemes ""]
	    set l {}
	    set i 0
	    while {[set grapheme [grapheme next $text i]] ne ""} {
		lappend l $grapheme
	    }
	    set l
	} -result $graphemes
    }

    ### grapheme prev

    tcltests::testnumargs "grapheme prev" "string indexVar" ""

    foreach testCase [list [list 0 "empty string" ""] {*}[getGraphemeData]] {
	lassign $testCase testNum comment graphemes
	test grapheme-prev-ucd-$testNum.0 $comment -body {
	    set text [join $graphemes ""]
	    set l {}
	    set i end
Changes to tests/info.test.
2602
2603
2604
2605
2606
2607
2608













2609
2610
2611
2612
2613
2614
2615
    demo
} -cleanup {
    unset -nocomplain body
    rename demo {}
    rename probe {}
} -result 3














test info-41.0 {Bug 0de6c1d79c crash} -setup {
    interp create child
    child hide info
} -body {
    list [child invokehidden info frame] \
	[child invokehidden info frame 0] \
	[child invokehidden info frame 1] \







>
>
>
>
>
>
>
>
>
>
>
>
>







2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
    demo
} -cleanup {
    unset -nocomplain body
    rename demo {}
    rename probe {}
} -result 3

test info-39.3 {Bug [e533296a92d89044]: no segfault, nested lambda invocation doesn't remove info from stack} -setup {
    set ::res {}
    proc probe {s} {
	lappend ::res [dict filter [info frame -1] key {[cl]*m*d*}]
	catch {apply {{s} {eval $s}} $s}
    }
} -body {
    probe {catch {probe {error X}}; probe {}}
    set ::res
} -cleanup {
    unset -nocomplain ::res
} -result {{cmd {probe {catch {probe {error X}}; probe {}}}} {cmd {probe {error X}} lambda {{s} {eval $s}}} {cmd {probe {}} lambda {{s} {eval $s}}}}

test info-41.0 {Bug 0de6c1d79c crash} -setup {
    interp create child
    child hide info
} -body {
    list [child invokehidden info frame] \
	[child invokehidden info frame 0] \
	[child invokehidden info frame 1] \