goscript 0.0.41 → 0.0.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler/analysis.go +173 -2
- package/compiler/compiler.go +13 -3
- package/compiler/stmt.go +118 -17
- package/package.json +1 -1
package/compiler/analysis.go
CHANGED
|
@@ -43,6 +43,14 @@ type VariableUsageInfo struct {
|
|
|
43
43
|
Destinations []AssignmentInfo
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
// ShadowingInfo tracks variable shadowing in if statement initializations
|
|
47
|
+
type ShadowingInfo struct {
|
|
48
|
+
// ShadowedVariables maps shadowed variable names to their outer scope objects
|
|
49
|
+
ShadowedVariables map[string]types.Object
|
|
50
|
+
// TempVariables maps shadowed variable names to temporary variable names
|
|
51
|
+
TempVariables map[string]string
|
|
52
|
+
}
|
|
53
|
+
|
|
46
54
|
// FunctionTypeInfo represents Go function type information for reflection
|
|
47
55
|
type FunctionTypeInfo struct {
|
|
48
56
|
Params []types.Type // Parameter types
|
|
@@ -69,8 +77,9 @@ type NodeInfo struct {
|
|
|
69
77
|
IsBareReturn bool
|
|
70
78
|
EnclosingFuncDecl *ast.FuncDecl
|
|
71
79
|
EnclosingFuncLit *ast.FuncLit
|
|
72
|
-
IsInsideFunction bool
|
|
73
|
-
IsMethodValue bool
|
|
80
|
+
IsInsideFunction bool // true if this declaration is inside a function body
|
|
81
|
+
IsMethodValue bool // true if this SelectorExpr is a method value that needs binding
|
|
82
|
+
ShadowingInfo *ShadowingInfo // variable shadowing information for if statements
|
|
74
83
|
}
|
|
75
84
|
|
|
76
85
|
// Analysis holds information gathered during the analysis phase of the Go code compilation.
|
|
@@ -270,6 +279,30 @@ func (a *Analysis) IsMethodValue(node *ast.SelectorExpr) bool {
|
|
|
270
279
|
return nodeInfo.IsMethodValue
|
|
271
280
|
}
|
|
272
281
|
|
|
282
|
+
// HasVariableShadowing returns whether the given node has variable shadowing issues
|
|
283
|
+
func (a *Analysis) HasVariableShadowing(node ast.Node) bool {
|
|
284
|
+
if node == nil {
|
|
285
|
+
return false
|
|
286
|
+
}
|
|
287
|
+
nodeInfo := a.NodeData[node]
|
|
288
|
+
if nodeInfo == nil {
|
|
289
|
+
return false
|
|
290
|
+
}
|
|
291
|
+
return nodeInfo.ShadowingInfo != nil
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// GetShadowingInfo returns the variable shadowing information for the given node
|
|
295
|
+
func (a *Analysis) GetShadowingInfo(node ast.Node) *ShadowingInfo {
|
|
296
|
+
if node == nil {
|
|
297
|
+
return nil
|
|
298
|
+
}
|
|
299
|
+
nodeInfo := a.NodeData[node]
|
|
300
|
+
if nodeInfo == nil {
|
|
301
|
+
return nil
|
|
302
|
+
}
|
|
303
|
+
return nodeInfo.ShadowingInfo
|
|
304
|
+
}
|
|
305
|
+
|
|
273
306
|
// analysisVisitor implements ast.Visitor and is used to traverse the AST during analysis.
|
|
274
307
|
type analysisVisitor struct {
|
|
275
308
|
// analysis stores information gathered during the traversal
|
|
@@ -631,6 +664,19 @@ func (v *analysisVisitor) Visit(node ast.Node) ast.Visitor {
|
|
|
631
664
|
return v // Continue traversal
|
|
632
665
|
|
|
633
666
|
case *ast.AssignStmt:
|
|
667
|
+
// Detect variable shadowing in any := assignment
|
|
668
|
+
if n.Tok == token.DEFINE {
|
|
669
|
+
shadowingInfo := v.detectVariableShadowing(n)
|
|
670
|
+
if shadowingInfo != nil {
|
|
671
|
+
// Store shadowing info on the assignment statement itself
|
|
672
|
+
if v.analysis.NodeData[n] == nil {
|
|
673
|
+
v.analysis.NodeData[n] = &NodeInfo{}
|
|
674
|
+
}
|
|
675
|
+
v.analysis.NodeData[n].ShadowingInfo = shadowingInfo
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Continue with the existing assignment analysis logic
|
|
634
680
|
for i, currentLHSExpr := range n.Lhs {
|
|
635
681
|
if i >= len(n.Rhs) {
|
|
636
682
|
break // Should not happen in valid Go
|
|
@@ -779,6 +825,22 @@ func (v *analysisVisitor) Visit(node ast.Node) ast.Visitor {
|
|
|
779
825
|
}
|
|
780
826
|
}
|
|
781
827
|
return v // Continue traversal
|
|
828
|
+
|
|
829
|
+
case *ast.IfStmt:
|
|
830
|
+
// Detect variable shadowing in if statement initializations
|
|
831
|
+
if n.Init != nil {
|
|
832
|
+
if assignStmt, ok := n.Init.(*ast.AssignStmt); ok && assignStmt.Tok == token.DEFINE {
|
|
833
|
+
shadowingInfo := v.detectVariableShadowing(assignStmt)
|
|
834
|
+
if shadowingInfo != nil {
|
|
835
|
+
// Initialize NodeData for this if statement
|
|
836
|
+
if v.analysis.NodeData[n] == nil {
|
|
837
|
+
v.analysis.NodeData[n] = &NodeInfo{}
|
|
838
|
+
}
|
|
839
|
+
v.analysis.NodeData[n].ShadowingInfo = shadowingInfo
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
return v // Continue traversal
|
|
782
844
|
}
|
|
783
845
|
|
|
784
846
|
// For all other nodes, continue traversal
|
|
@@ -1225,3 +1287,112 @@ func (v *analysisVisitor) markFunctionVariable(ident *ast.Ident, funcType *types
|
|
|
1225
1287
|
v.analysis.MarkFunctionForReflection(funcNode, funcType)
|
|
1226
1288
|
}
|
|
1227
1289
|
}
|
|
1290
|
+
|
|
1291
|
+
// detectVariableShadowing detects variable shadowing in any := assignment
|
|
1292
|
+
func (v *analysisVisitor) detectVariableShadowing(assignStmt *ast.AssignStmt) *ShadowingInfo {
|
|
1293
|
+
shadowingInfo := &ShadowingInfo{
|
|
1294
|
+
ShadowedVariables: make(map[string]types.Object),
|
|
1295
|
+
TempVariables: make(map[string]string),
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
hasShadowing := false
|
|
1299
|
+
|
|
1300
|
+
// First, collect all LHS variable names that are being declared
|
|
1301
|
+
lhsVarNames := make(map[string]*ast.Ident)
|
|
1302
|
+
for _, lhsExpr := range assignStmt.Lhs {
|
|
1303
|
+
if lhsIdent, ok := lhsExpr.(*ast.Ident); ok && lhsIdent.Name != "_" {
|
|
1304
|
+
lhsVarNames[lhsIdent.Name] = lhsIdent
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
// Next, check all RHS expressions for usage of variables that are also being declared on LHS
|
|
1309
|
+
for _, rhsExpr := range assignStmt.Rhs {
|
|
1310
|
+
v.findVariableUsageInExpr(rhsExpr, lhsVarNames, shadowingInfo, &hasShadowing)
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
if hasShadowing {
|
|
1314
|
+
return shadowingInfo
|
|
1315
|
+
}
|
|
1316
|
+
return nil
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// findVariableUsageInExpr recursively searches for variable usage in an expression
|
|
1320
|
+
func (v *analysisVisitor) findVariableUsageInExpr(expr ast.Expr, lhsVarNames map[string]*ast.Ident, shadowingInfo *ShadowingInfo, hasShadowing *bool) {
|
|
1321
|
+
if expr == nil {
|
|
1322
|
+
return
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
switch e := expr.(type) {
|
|
1326
|
+
case *ast.Ident:
|
|
1327
|
+
// Check if this identifier is being shadowed
|
|
1328
|
+
if lhsIdent, exists := lhsVarNames[e.Name]; exists {
|
|
1329
|
+
// This variable is being used on RHS but also declared on LHS - this is shadowing!
|
|
1330
|
+
|
|
1331
|
+
// Get the outer scope object for this variable
|
|
1332
|
+
if outerObj := v.pkg.TypesInfo.Uses[e]; outerObj != nil {
|
|
1333
|
+
// Make sure this isn't the same object as the LHS (which would mean no shadowing)
|
|
1334
|
+
if lhsObj := v.pkg.TypesInfo.Defs[lhsIdent]; lhsObj != outerObj {
|
|
1335
|
+
shadowingInfo.ShadowedVariables[e.Name] = outerObj
|
|
1336
|
+
shadowingInfo.TempVariables[e.Name] = "_temp_" + e.Name
|
|
1337
|
+
*hasShadowing = true
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
case *ast.CallExpr:
|
|
1343
|
+
// Check function arguments
|
|
1344
|
+
for _, arg := range e.Args {
|
|
1345
|
+
v.findVariableUsageInExpr(arg, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1346
|
+
}
|
|
1347
|
+
// Check function expression itself
|
|
1348
|
+
v.findVariableUsageInExpr(e.Fun, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1349
|
+
|
|
1350
|
+
case *ast.SelectorExpr:
|
|
1351
|
+
// Check the base expression (e.g., x in x.Method())
|
|
1352
|
+
v.findVariableUsageInExpr(e.X, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1353
|
+
|
|
1354
|
+
case *ast.IndexExpr:
|
|
1355
|
+
// Check both the expression and index (e.g., arr[i])
|
|
1356
|
+
v.findVariableUsageInExpr(e.X, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1357
|
+
v.findVariableUsageInExpr(e.Index, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1358
|
+
|
|
1359
|
+
case *ast.SliceExpr:
|
|
1360
|
+
// Check the expression and slice bounds
|
|
1361
|
+
v.findVariableUsageInExpr(e.X, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1362
|
+
if e.Low != nil {
|
|
1363
|
+
v.findVariableUsageInExpr(e.Low, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1364
|
+
}
|
|
1365
|
+
if e.High != nil {
|
|
1366
|
+
v.findVariableUsageInExpr(e.High, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1367
|
+
}
|
|
1368
|
+
if e.Max != nil {
|
|
1369
|
+
v.findVariableUsageInExpr(e.Max, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
case *ast.UnaryExpr:
|
|
1373
|
+
// Check the operand (e.g., &x, -x, !x)
|
|
1374
|
+
v.findVariableUsageInExpr(e.X, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1375
|
+
|
|
1376
|
+
case *ast.BinaryExpr:
|
|
1377
|
+
// Check both operands (e.g., x + y)
|
|
1378
|
+
v.findVariableUsageInExpr(e.X, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1379
|
+
v.findVariableUsageInExpr(e.Y, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1380
|
+
|
|
1381
|
+
case *ast.ParenExpr:
|
|
1382
|
+
// Check the parenthesized expression
|
|
1383
|
+
v.findVariableUsageInExpr(e.X, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1384
|
+
|
|
1385
|
+
case *ast.TypeAssertExpr:
|
|
1386
|
+
// Check the expression being type-asserted
|
|
1387
|
+
v.findVariableUsageInExpr(e.X, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1388
|
+
|
|
1389
|
+
case *ast.StarExpr:
|
|
1390
|
+
// Check the expression being dereferenced
|
|
1391
|
+
v.findVariableUsageInExpr(e.X, lhsVarNames, shadowingInfo, hasShadowing)
|
|
1392
|
+
|
|
1393
|
+
// Add more expression types as needed
|
|
1394
|
+
default:
|
|
1395
|
+
// For other expression types, we might need to add specific handling
|
|
1396
|
+
// For now, we'll ignore them as they're less common in shadowing scenarios
|
|
1397
|
+
}
|
|
1398
|
+
}
|
package/compiler/compiler.go
CHANGED
|
@@ -639,6 +639,9 @@ type GoToTSCompiler struct {
|
|
|
639
639
|
pkg *packages.Package
|
|
640
640
|
|
|
641
641
|
analysis *Analysis
|
|
642
|
+
|
|
643
|
+
// shadowingContext tracks temporary variable mappings when we're in a shadowing context
|
|
644
|
+
shadowingContext map[string]string
|
|
642
645
|
}
|
|
643
646
|
|
|
644
647
|
// It initializes the compiler with a `TSCodeWriter` for output,
|
|
@@ -646,9 +649,10 @@ type GoToTSCompiler struct {
|
|
|
646
649
|
// analysis results (`Analysis`) to guide the translation process.
|
|
647
650
|
func NewGoToTSCompiler(tsw *TSCodeWriter, pkg *packages.Package, analysis *Analysis) *GoToTSCompiler {
|
|
648
651
|
return &GoToTSCompiler{
|
|
649
|
-
tsw:
|
|
650
|
-
pkg:
|
|
651
|
-
analysis:
|
|
652
|
+
tsw: tsw,
|
|
653
|
+
pkg: pkg,
|
|
654
|
+
analysis: analysis,
|
|
655
|
+
shadowingContext: make(map[string]string),
|
|
652
656
|
}
|
|
653
657
|
}
|
|
654
658
|
|
|
@@ -670,6 +674,12 @@ func (c *GoToTSCompiler) WriteIdent(exp *ast.Ident, accessVarRefedValue bool) {
|
|
|
670
674
|
return
|
|
671
675
|
}
|
|
672
676
|
|
|
677
|
+
// Check if we're in a shadowing context and should use a temporary variable
|
|
678
|
+
if tempVarName, exists := c.shadowingContext[exp.Name]; exists {
|
|
679
|
+
c.tsw.WriteLiterally(c.sanitizeIdentifier(tempVarName))
|
|
680
|
+
return
|
|
681
|
+
}
|
|
682
|
+
|
|
673
683
|
// Use TypesInfo to find the object associated with the identifier
|
|
674
684
|
var obj types.Object
|
|
675
685
|
obj = c.pkg.TypesInfo.Uses[exp]
|
package/compiler/stmt.go
CHANGED
|
@@ -444,53 +444,90 @@ func (c *GoToTSCompiler) WriteStmtSend(exp *ast.SendStmt) error {
|
|
|
444
444
|
// recursively calling `WriteStmtIf`.
|
|
445
445
|
//
|
|
446
446
|
// The function aims to produce idiomatic TypeScript `if/else if/else` structures.
|
|
447
|
-
func (
|
|
447
|
+
func (c *GoToTSCompiler) WriteStmtIf(exp *ast.IfStmt) error {
|
|
448
448
|
if exp.Init != nil {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
449
|
+
// Check if we need to handle variable shadowing BEFORE creating the block
|
|
450
|
+
var shadowingInfo *ShadowingInfo
|
|
451
|
+
if assignStmt, ok := exp.Init.(*ast.AssignStmt); ok {
|
|
452
|
+
shadowingInfo = c.analysis.GetShadowingInfo(assignStmt)
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Generate temporary variables OUTSIDE the block to avoid temporal dead zone
|
|
456
|
+
if shadowingInfo != nil {
|
|
457
|
+
for varName, tempVarName := range shadowingInfo.TempVariables {
|
|
458
|
+
c.tsw.WriteLiterally("let ")
|
|
459
|
+
c.tsw.WriteLiterally(tempVarName)
|
|
460
|
+
c.tsw.WriteLiterally(" = ")
|
|
461
|
+
c.tsw.WriteLiterally(c.sanitizeIdentifier(varName))
|
|
462
|
+
c.tsw.WriteLine("")
|
|
463
|
+
}
|
|
464
|
+
}
|
|
452
465
|
|
|
453
|
-
|
|
454
|
-
|
|
466
|
+
c.tsw.WriteLiterally("{") // Write opening brace
|
|
467
|
+
c.tsw.WriteLine("") // Add newline immediately after opening brace
|
|
468
|
+
c.tsw.Indent(1) // Indent for the initializer
|
|
469
|
+
|
|
470
|
+
// Check if we need to handle variable shadowing
|
|
471
|
+
if assignStmt, ok := exp.Init.(*ast.AssignStmt); ok {
|
|
472
|
+
if shadowingInfo != nil {
|
|
473
|
+
// Write the assignment statement with special handling for shadowing
|
|
474
|
+
if err := c.writeShadowedAssignment(assignStmt, shadowingInfo); err != nil {
|
|
475
|
+
return err
|
|
476
|
+
}
|
|
477
|
+
} else {
|
|
478
|
+
// No shadowing, write normally
|
|
479
|
+
if err := c.WriteStmt(exp.Init); err != nil {
|
|
480
|
+
return err
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
} else {
|
|
484
|
+
// Not an assignment statement, write normally
|
|
485
|
+
if err := c.WriteStmt(exp.Init); err != nil {
|
|
486
|
+
return err
|
|
487
|
+
}
|
|
455
488
|
}
|
|
456
489
|
|
|
457
490
|
// This defer handles closing the synthetic block for the initializer
|
|
458
491
|
defer func() {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
492
|
+
c.tsw.Indent(-1)
|
|
493
|
+
c.tsw.WriteLiterally("}") // Write the closing brace at the now-correct indent level
|
|
494
|
+
c.tsw.WriteLine("") // Ensure a newline *after* this '}', critical for preventing '}}'
|
|
462
495
|
}()
|
|
463
496
|
}
|
|
464
497
|
|
|
465
|
-
|
|
466
|
-
|
|
498
|
+
// Ensure shadowing context is clear before writing condition
|
|
499
|
+
// (condition should refer to new local variables, not temp variables)
|
|
500
|
+
c.shadowingContext = make(map[string]string)
|
|
501
|
+
|
|
502
|
+
c.tsw.WriteLiterally("if (")
|
|
503
|
+
if err := c.WriteValueExpr(exp.Cond); err != nil { // Condition is a value
|
|
467
504
|
return err
|
|
468
505
|
}
|
|
469
|
-
|
|
506
|
+
c.tsw.WriteLiterally(") ")
|
|
470
507
|
|
|
471
508
|
if exp.Body != nil {
|
|
472
|
-
if err :=
|
|
509
|
+
if err := c.WriteStmtBlock(exp.Body, exp.Else != nil); err != nil {
|
|
473
510
|
return fmt.Errorf("failed to write if body block statement: %w", err)
|
|
474
511
|
}
|
|
475
512
|
} else {
|
|
476
513
|
// Handle nil body case using WriteStmtBlock with an empty block
|
|
477
|
-
if err :=
|
|
514
|
+
if err := c.WriteStmtBlock(&ast.BlockStmt{}, exp.Else != nil); err != nil {
|
|
478
515
|
return fmt.Errorf("failed to write empty block statement in if statement: %w", err)
|
|
479
516
|
}
|
|
480
517
|
}
|
|
481
518
|
|
|
482
519
|
// handle else branch
|
|
483
520
|
if exp.Else != nil {
|
|
484
|
-
|
|
521
|
+
c.tsw.WriteLiterally(" else ")
|
|
485
522
|
switch elseStmt := exp.Else.(type) {
|
|
486
523
|
case *ast.BlockStmt:
|
|
487
524
|
// Always pass false for suppressNewline here
|
|
488
|
-
if err :=
|
|
525
|
+
if err := c.WriteStmtBlock(elseStmt, false); err != nil {
|
|
489
526
|
return fmt.Errorf("failed to write else block statement in if statement: %w", err)
|
|
490
527
|
}
|
|
491
528
|
case *ast.IfStmt:
|
|
492
529
|
// Recursive call handles its own block formatting
|
|
493
|
-
if err :=
|
|
530
|
+
if err := c.WriteStmtIf(elseStmt); err != nil {
|
|
494
531
|
return fmt.Errorf("failed to write else if statement in if statement: %w", err)
|
|
495
532
|
}
|
|
496
533
|
}
|
|
@@ -897,3 +934,67 @@ func (c *GoToTSCompiler) WriteStmtLabeled(stmt *ast.LabeledStmt) error {
|
|
|
897
934
|
|
|
898
935
|
return nil
|
|
899
936
|
}
|
|
937
|
+
|
|
938
|
+
// writeShadowedAssignment writes an assignment statement that has variable shadowing,
|
|
939
|
+
// applying the shadowing context only to RHS expressions.
|
|
940
|
+
func (c *GoToTSCompiler) writeShadowedAssignment(stmt *ast.AssignStmt, shadowingInfo *ShadowingInfo) error {
|
|
941
|
+
// Write the LHS variables (these are new declarations, don't use temp variables)
|
|
942
|
+
for i, lhsExpr := range stmt.Lhs {
|
|
943
|
+
if i > 0 {
|
|
944
|
+
c.tsw.WriteLiterally(", ")
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
if ident, ok := lhsExpr.(*ast.Ident); ok {
|
|
948
|
+
if ident.Name == "_" {
|
|
949
|
+
c.tsw.WriteLiterally("_")
|
|
950
|
+
} else {
|
|
951
|
+
c.tsw.WriteLiterally("let ")
|
|
952
|
+
c.WriteIdent(ident, false) // Don't use temp variable for LHS
|
|
953
|
+
}
|
|
954
|
+
} else {
|
|
955
|
+
// For non-identifier LHS (shouldn't happen in := assignments), write normally
|
|
956
|
+
if err := c.WriteValueExpr(lhsExpr); err != nil {
|
|
957
|
+
return err
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
c.tsw.WriteLiterally(" = ")
|
|
963
|
+
|
|
964
|
+
// Set up shadowing context for RHS expressions only
|
|
965
|
+
originalContext := make(map[string]string)
|
|
966
|
+
for varName, tempVarName := range shadowingInfo.TempVariables {
|
|
967
|
+
originalContext[varName] = c.shadowingContext[varName] // backup original
|
|
968
|
+
c.shadowingContext[varName] = tempVarName
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// Write RHS expressions with shadowing context
|
|
972
|
+
for i, rhsExpr := range stmt.Rhs {
|
|
973
|
+
if i > 0 {
|
|
974
|
+
c.tsw.WriteLiterally(", ")
|
|
975
|
+
}
|
|
976
|
+
if err := c.WriteValueExpr(rhsExpr); err != nil {
|
|
977
|
+
// Restore context on error
|
|
978
|
+
for varName := range shadowingInfo.TempVariables {
|
|
979
|
+
if original, existed := originalContext[varName]; existed {
|
|
980
|
+
c.shadowingContext[varName] = original
|
|
981
|
+
} else {
|
|
982
|
+
delete(c.shadowingContext, varName)
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return err
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// Restore original context after writing RHS
|
|
990
|
+
for varName := range shadowingInfo.TempVariables {
|
|
991
|
+
if original, existed := originalContext[varName]; existed {
|
|
992
|
+
c.shadowingContext[varName] = original
|
|
993
|
+
} else {
|
|
994
|
+
delete(c.shadowingContext, varName)
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
c.tsw.WriteLine("")
|
|
999
|
+
return nil
|
|
1000
|
+
}
|