package interp

import (
	
	
	
	
	
	
	
	
	
	
)

// nkind defines the kind of AST, i.e. the grammar category.
type nkind uint

// Node kinds for the go language.
const (
	undefNode nkind = iota
	addressExpr
	arrayType
	assignStmt
	assignXStmt
	basicLit
	binaryExpr
	blockStmt
	branchStmt
	breakStmt
	callExpr
	caseBody
	caseClause
	chanType
	chanTypeSend
	chanTypeRecv
	commClause
	commClauseDefault
	compositeLitExpr
	constDecl
	continueStmt
	declStmt
	deferStmt
	defineStmt
	defineXStmt
	ellipsisExpr
	exprStmt
	fallthroughtStmt
	fieldExpr
	fieldList
	fileStmt
	forStmt0     // for {}
	forStmt1     // for init; ; {}
	forStmt2     // for cond {}
	forStmt3     // for init; cond; {}
	forStmt4     // for ; ; post {}
	forStmt5     // for ; cond; post {}
	forStmt6     // for init; ; post {}
	forStmt7     // for init; cond; post {}
	forRangeStmt // for range {}
	funcDecl
	funcLit
	funcType
	goStmt
	gotoStmt
	identExpr
	ifStmt0 // if cond {}
	ifStmt1 // if cond {} else {}
	ifStmt2 // if init; cond {}
	ifStmt3 // if init; cond {} else {}
	importDecl
	importSpec
	incDecStmt
	indexExpr
	indexListExpr
	interfaceType
	keyValueExpr
	labeledStmt
	landExpr
	lorExpr
	mapType
	parenExpr
	rangeStmt
	returnStmt
	selectStmt
	selectorExpr
	selectorImport
	sendStmt
	sliceExpr
	starExpr
	structType
	switchStmt
	switchIfStmt
	typeAssertExpr
	typeDecl
	typeSpec       // type A int
	typeSpecAssign // type A = int
	typeSwitch
	unaryExpr
	valueSpec
	varDecl
)

var kinds = [...]string{
	undefNode:         "undefNode",
	addressExpr:       "addressExpr",
	arrayType:         "arrayType",
	assignStmt:        "assignStmt",
	assignXStmt:       "assignXStmt",
	basicLit:          "basicLit",
	binaryExpr:        "binaryExpr",
	blockStmt:         "blockStmt",
	branchStmt:        "branchStmt",
	breakStmt:         "breakStmt",
	callExpr:          "callExpr",
	caseBody:          "caseBody",
	caseClause:        "caseClause",
	chanType:          "chanType",
	chanTypeSend:      "chanTypeSend",
	chanTypeRecv:      "chanTypeRecv",
	commClause:        "commClause",
	commClauseDefault: "commClauseDefault",
	compositeLitExpr:  "compositeLitExpr",
	constDecl:         "constDecl",
	continueStmt:      "continueStmt",
	declStmt:          "declStmt",
	deferStmt:         "deferStmt",
	defineStmt:        "defineStmt",
	defineXStmt:       "defineXStmt",
	ellipsisExpr:      "ellipsisExpr",
	exprStmt:          "exprStmt",
	fallthroughtStmt:  "fallthroughStmt",
	fieldExpr:         "fieldExpr",
	fieldList:         "fieldList",
	fileStmt:          "fileStmt",
	forStmt0:          "forStmt0",
	forStmt1:          "forStmt1",
	forStmt2:          "forStmt2",
	forStmt3:          "forStmt3",
	forStmt4:          "forStmt4",
	forStmt5:          "forStmt5",
	forStmt6:          "forStmt6",
	forStmt7:          "forStmt7",
	forRangeStmt:      "forRangeStmt",
	funcDecl:          "funcDecl",
	funcType:          "funcType",
	funcLit:           "funcLit",
	goStmt:            "goStmt",
	gotoStmt:          "gotoStmt",
	identExpr:         "identExpr",
	ifStmt0:           "ifStmt0",
	ifStmt1:           "ifStmt1",
	ifStmt2:           "ifStmt2",
	ifStmt3:           "ifStmt3",
	importDecl:        "importDecl",
	importSpec:        "importSpec",
	incDecStmt:        "incDecStmt",
	indexExpr:         "indexExpr",
	indexListExpr:     "indexListExpr",
	interfaceType:     "interfaceType",
	keyValueExpr:      "keyValueExpr",
	labeledStmt:       "labeledStmt",
	landExpr:          "landExpr",
	lorExpr:           "lorExpr",
	mapType:           "mapType",
	parenExpr:         "parenExpr",
	rangeStmt:         "rangeStmt",
	returnStmt:        "returnStmt",
	selectStmt:        "selectStmt",
	selectorExpr:      "selectorExpr",
	selectorImport:    "selectorImport",
	sendStmt:          "sendStmt",
	sliceExpr:         "sliceExpr",
	starExpr:          "starExpr",
	structType:        "structType",
	switchStmt:        "switchStmt",
	switchIfStmt:      "switchIfStmt",
	typeAssertExpr:    "typeAssertExpr",
	typeDecl:          "typeDecl",
	typeSpec:          "typeSpec",
	typeSpecAssign:    "typeSpecAssign",
	typeSwitch:        "typeSwitch",
	unaryExpr:         "unaryExpr",
	valueSpec:         "valueSpec",
	varDecl:           "varDecl",
}

func ( nkind) () string {
	if  < nkind(len(kinds)) {
		return kinds[]
	}
	return "nKind(" + strconv.Itoa(int()) + ")"
}

// astError represents an error during AST build stage.
type astError error

// action defines the node action to perform at execution.
type action uint

// Node actions for the go language.
// It is important for type checking that *Assign directly
// follows it non-assign counterpart.
const (
	aNop action = iota
	aAddr
	aAssign
	aAssignX
	aAdd
	aAddAssign
	aAnd
	aAndAssign
	aAndNot
	aAndNotAssign
	aBitNot
	aBranch
	aCall
	aCallSlice
	aCase
	aCompositeLit
	aConvert
	aDec
	aEqual
	aGreater
	aGreaterEqual
	aGetFunc
	aGetIndex
	aGetMethod
	aGetSym
	aInc
	aLand
	aLor
	aLower
	aLowerEqual
	aMethod
	aMul
	aMulAssign
	aNeg
	aNot
	aNotEqual
	aOr
	aOrAssign
	aPos
	aQuo
	aQuoAssign
	aRange
	aRecv
	aRem
	aRemAssign
	aReturn
	aSend
	aShl
	aShlAssign
	aShr
	aShrAssign
	aSlice
	aSlice0
	aStar
	aSub
	aSubAssign
	aTypeAssert
	aXor
	aXorAssign
)

var actions = [...]string{
	aNop:          "nop",
	aAddr:         "&",
	aAssign:       "=",
	aAssignX:      "X=",
	aAdd:          "+",
	aAddAssign:    "+=",
	aAnd:          "&",
	aAndAssign:    "&=",
	aAndNot:       "&^",
	aAndNotAssign: "&^=",
	aBitNot:       "^",
	aBranch:       "branch",
	aCall:         "call",
	aCallSlice:    "callSlice",
	aCase:         "case",
	aCompositeLit: "compositeLit",
	aConvert:      "convert",
	aDec:          "--",
	aEqual:        "==",
	aGreater:      ">",
	aGreaterEqual: ">=",
	aGetFunc:      "getFunc",
	aGetIndex:     "getIndex",
	aGetMethod:    "getMethod",
	aGetSym:       ".",
	aInc:          "++",
	aLand:         "&&",
	aLor:          "||",
	aLower:        "<",
	aLowerEqual:   "<=",
	aMethod:       "Method",
	aMul:          "*",
	aMulAssign:    "*=",
	aNeg:          "-",
	aNot:          "!",
	aNotEqual:     "!=",
	aOr:           "|",
	aOrAssign:     "|=",
	aPos:          "+",
	aQuo:          "/",
	aQuoAssign:    "/=",
	aRange:        "range",
	aRecv:         "<-",
	aRem:          "%",
	aRemAssign:    "%=",
	aReturn:       "return",
	aSend:         "<~",
	aShl:          "<<",
	aShlAssign:    "<<=",
	aShr:          ">>",
	aShrAssign:    ">>=",
	aSlice:        "slice",
	aSlice0:       "slice0",
	aStar:         "*",
	aSub:          "-",
	aSubAssign:    "-=",
	aTypeAssert:   "TypeAssert",
	aXor:          "^",
	aXorAssign:    "^=",
}

func ( action) () string {
	if  < action(len(actions)) {
		return actions[]
	}
	return "Action(" + strconv.Itoa(int()) + ")"
}

func isAssignAction( action) bool {
	switch  {
	case aAddAssign, aAndAssign, aAndNotAssign, aMulAssign, aOrAssign,
		aQuoAssign, aRemAssign, aShlAssign, aShrAssign, aSubAssign, aXorAssign:
		return true
	}
	return false
}

func ( *Interpreter) ( string) token.Token {
	var  scanner.Scanner
	 := .fset.AddFile("", .fset.Base(), len())
	.Init(, []byte(), nil, 0)

	, ,  := .Scan()
	return 
}

func ignoreError( error,  string) bool {
	,  := .(scanner.ErrorList)
	if ! {
		return false
	}
	if len() == 0 {
		return false
	}
	return ignoreScannerError([0], )
}

func wrapInMain( string) string {
	return fmt.Sprintf("package main; func main() {%s\n}", )
}

func ( *Interpreter) (,  string,  bool) ( ast.Node,  error) {
	 := parser.DeclarationErrors

	// Allow incremental parsing of declarations or statements, by inserting
	// them in a pseudo file package or function. Those statements or
	// declarations will be always evaluated in the global scope.
	var  token.Token
	var  bool
	if  {
		 = .firstToken()
		switch  {
		case token.PACKAGE:
			// nothing to do.
		case token.CONST, token.FUNC, token.IMPORT, token.TYPE, token.VAR:
			 = "package main;" + 
		default:
			 = true
			 = wrapInMain()
		}
		// Parse comments in REPL mode, to allow tag setting.
		 |= parser.ParseComments
	}

	if ,  := .buildOk(&.context, , ); ! ||  != nil {
		return nil,  // skip source not matching build constraints
	}

	,  := parser.ParseFile(.fset, , , )
	if  != nil {
		// only retry if we're on an expression/statement about a func
		if ! ||  != token.FUNC {
			return nil, 
		}
		// do not bother retrying if we know it's an error we're going to ignore later on.
		if ignoreError(, ) {
			return nil, 
		}
		// do not lose initial error, in case retrying fails.
		 := 
		// retry with default source code "wrapping", in the main function scope.
		 := wrapInMain(strings.TrimPrefix(, "package main;"))
		,  = parser.ParseFile(.fset, , , )
		if  != nil {
			return nil, 
		}
	}

	if  {
		// return the body of the wrapper main function
		return .Decls[0].(*ast.FuncDecl).Body, nil
	}

	setYaegiTags(&.context, .Comments)
	return , nil
}

// Note: no type analysis is performed at this stage, it is done in pre-order
// processing of CFG, in order to accommodate forward type declarations.

// ast parses src string containing Go code and generates the corresponding AST.
// The package name and the AST root node are returned.
// The given name is used to set the filename of the relevant source file in the
// interpreter's FileSet.
func ( *Interpreter) ( ast.Node) (string, *node, error) {
	var  error
	var  *node
	var  astNode
	var  nodestack
	 := "main"

	 := func( **node,  astNode,  token.Pos,  nkind,  action) *node {
		var  interface{}
		 := atomic.AddInt64(&.nindex, 1)
		 := &node{anc: .node, interp: , index: , pos: , kind: , action: , val: &, gen: builtin[]}
		.start = 
		if .node == nil {
			* = 
		} else {
			.node.child = append(.node.child, )
			if .node.action == aCase {
				 := .ast.(*ast.CaseClause)
				if len(.List)+len(.Body) == len(.node.child) {
					// All case clause children are collected.
					// Split children in condition and body nodes to desambiguify the AST.
					 = atomic.AddInt64(&.nindex, 1)
					 := &node{anc: .node, interp: , index: , pos: , kind: caseBody, action: aNop, val: &, gen: nop}

					if  := .node.anc.anc; .kind == typeSwitch && .child[1].action == aAssign {
						// In type switch clause, if a switch guard is assigned, duplicate the switch guard symbol
						// in each clause body, so a different guard type can be set in each clause
						 := .child[1].child[0].ident
						 = atomic.AddInt64(&.nindex, 1)
						 := &node{anc: , interp: , ident: , index: , pos: , kind: identExpr, action: aNop, val: &, gen: nop}
						.child = append(.child, )
					}

					// Add regular body children
					.child = append(.child, .node.child[len(.List):]...)
					for  := range .child {
						.child[].anc = 
					}
					.node.child = append(.node.child[:len(.List)], )
				}
			}
		}
		return 
	}

	// Populate our own private AST from Go parser AST.
	// A stack of ancestor nodes is used to keep track of current ancestor for each depth level
	ast.Inspect(, func( ast.Node) bool {
		 = .top()
		var  token.Pos
		if  != nil {
			 = .Pos()
		}
		switch a := .(type) {
		case nil:
			 = .pop()

		case *ast.ArrayType:
			.push((&, , , arrayType, aNop), )

		case *ast.AssignStmt:
			var  action
			var  nkind
			if len(.Lhs) > 1 && len(.Rhs) == 1 {
				if .Tok == token.DEFINE {
					 = defineXStmt
				} else {
					 = assignXStmt
				}
				 = aAssignX
			} else {
				 = assignStmt
				switch .Tok {
				case token.ASSIGN:
					 = aAssign
				case token.ADD_ASSIGN:
					 = aAddAssign
				case token.AND_ASSIGN:
					 = aAndAssign
				case token.AND_NOT_ASSIGN:
					 = aAndNotAssign
				case token.DEFINE:
					 = defineStmt
					 = aAssign
				case token.SHL_ASSIGN:
					 = aShlAssign
				case token.SHR_ASSIGN:
					 = aShrAssign
				case token.MUL_ASSIGN:
					 = aMulAssign
				case token.OR_ASSIGN:
					 = aOrAssign
				case token.QUO_ASSIGN:
					 = aQuoAssign
				case token.REM_ASSIGN:
					 = aRemAssign
				case token.SUB_ASSIGN:
					 = aSubAssign
				case token.XOR_ASSIGN:
					 = aXorAssign
				}
			}
			 := (&, , , , )
			.nleft = len(.Lhs)
			.nright = len(.Rhs)
			.push(, )

		case *ast.BasicLit:
			 := (&, , , basicLit, aNop)
			.ident = .Value
			switch .Kind {
			case token.CHAR:
				// Char cannot be converted to a const here as we cannot tell the type.
				, , ,  := strconv.UnquoteChar(.Value[1:len(.Value)-1], '\'')
				.rval = reflect.ValueOf()
			case token.FLOAT, token.IMAG, token.INT, token.STRING:
				 := constant.MakeFromLiteral(.Value, .Kind, 0)
				.rval = reflect.ValueOf()
			}
			.push(, )

		case *ast.BinaryExpr:
			 := binaryExpr
			 := aNop
			switch .Op {
			case token.ADD:
				 = aAdd
			case token.AND:
				 = aAnd
			case token.AND_NOT:
				 = aAndNot
			case token.EQL:
				 = aEqual
			case token.GEQ:
				 = aGreaterEqual
			case token.GTR:
				 = aGreater
			case token.LAND:
				 = landExpr
				 = aLand
			case token.LOR:
				 = lorExpr
				 = aLor
			case token.LEQ:
				 = aLowerEqual
			case token.LSS:
				 = aLower
			case token.MUL:
				 = aMul
			case token.NEQ:
				 = aNotEqual
			case token.OR:
				 = aOr
			case token.REM:
				 = aRem
			case token.SUB:
				 = aSub
			case token.SHL:
				 = aShl
			case token.SHR:
				 = aShr
			case token.QUO:
				 = aQuo
			case token.XOR:
				 = aXor
			}
			.push((&, , , , ), )

		case *ast.BlockStmt:
			.push((&, , , blockStmt, aNop), )

		case *ast.BranchStmt:
			var  nkind
			switch .Tok {
			case token.BREAK:
				 = breakStmt
			case token.CONTINUE:
				 = continueStmt
			case token.FALLTHROUGH:
				 = fallthroughtStmt
			case token.GOTO:
				 = gotoStmt
			}
			.push((&, , , , aNop), )

		case *ast.CallExpr:
			 := aCall
			if .Ellipsis != token.NoPos {
				 = aCallSlice
			}

			.push((&, , , callExpr, ), )

		case *ast.CaseClause:
			.push((&, , , caseClause, aCase), )

		case *ast.ChanType:
			switch .Dir {
			case ast.SEND | ast.RECV:
				.push((&, , , chanType, aNop), )
			case ast.SEND:
				.push((&, , , chanTypeSend, aNop), )
			case ast.RECV:
				.push((&, , , chanTypeRecv, aNop), )
			}

		case *ast.CommClause:
			 := commClause
			if .Comm == nil {
				 = commClauseDefault
			}
			.push((&, , , , aNop), )

		case *ast.CommentGroup, *ast.EmptyStmt:
			return false

		case *ast.CompositeLit:
			.push((&, , , compositeLitExpr, aCompositeLit), )

		case *ast.DeclStmt:
			.push((&, , , declStmt, aNop), )

		case *ast.DeferStmt:
			.push((&, , , deferStmt, aNop), )

		case *ast.Ellipsis:
			.push((&, , , ellipsisExpr, aNop), )

		case *ast.ExprStmt:
			.push((&, , , exprStmt, aNop), )

		case *ast.Field:
			.push((&, , , fieldExpr, aNop), )

		case *ast.FieldList:
			.push((&, , , fieldList, aNop), )

		case *ast.File:
			 = .Name.Name
			.push((&, , , fileStmt, aNop), )

		case *ast.ForStmt:
			// Disambiguate variants of FOR statements with a node kind per variant
			var  nkind
			switch {
			case .Cond == nil && .Init == nil && .Post == nil:
				 = forStmt0
			case .Cond == nil && .Init != nil && .Post == nil:
				 = forStmt1
			case .Cond != nil && .Init == nil && .Post == nil:
				 = forStmt2
			case .Cond != nil && .Init != nil && .Post == nil:
				 = forStmt3
			case .Cond == nil && .Init == nil && .Post != nil:
				 = forStmt4
			case .Cond != nil && .Init == nil && .Post != nil:
				 = forStmt5
			case .Cond == nil && .Init != nil && .Post != nil:
				 = forStmt6
			case .Cond != nil && .Init != nil && .Post != nil:
				 = forStmt7
			}
			.push((&, , , , aNop), )

		case *ast.FuncDecl:
			 := (&, , , funcDecl, aNop)
			.val = 
			if .Recv == nil {
				// Function is not a method, create an empty receiver list.
				(&, astNode{, }, , fieldList, aNop)
			}
			.push(, )

		case *ast.FuncLit:
			 := (&, , , funcLit, aGetFunc)
			(&, astNode{, }, , fieldList, aNop)
			(&, astNode{, }, , undefNode, aNop)
			.push(, )

		case *ast.FuncType:
			 := (&, , , funcType, aNop)
			.val = 
			if .TypeParams == nil {
				// Function has no type parameters, create an empty fied list.
				(&, astNode{, }, , fieldList, aNop)
			}
			.push(, )

		case *ast.GenDecl:
			var  nkind
			switch .Tok {
			case token.CONST:
				 = constDecl
			case token.IMPORT:
				 = importDecl
			case token.TYPE:
				 = typeDecl
			case token.VAR:
				 = varDecl
			}
			.push((&, , , , aNop), )

		case *ast.GoStmt:
			.push((&, , , goStmt, aNop), )

		case *ast.Ident:
			 := (&, , , identExpr, aNop)
			.ident = .Name
			.push(, )
			if .anc.kind == defineStmt && .anc.anc.kind == constDecl && .anc.nright == 0 {
				// Implicit assign expression (in a ConstDecl block).
				// Clone assign source and type from previous
				 := .anc
				 := .anc.child[childPos()-1]

				if len(.child) > .nleft+.nright {
					// duplicate previous type spec
					.child = append(.child, .dup(.child[.nleft], ))
				}

				// duplicate previous assign right hand side
				.child = append(.child, .dup(.lastChild(), ))
				.nright++
			}

		case *ast.IfStmt:
			// Disambiguate variants of IF statements with a node kind per variant
			var  nkind
			switch {
			case .Init == nil && .Else == nil:
				 = ifStmt0
			case .Init == nil && .Else != nil:
				 = ifStmt1
			case .Else == nil:
				 = ifStmt2
			default:
				 = ifStmt3
			}
			.push((&, , , , aNop), )

		case *ast.ImportSpec:
			.push((&, , , importSpec, aNop), )

		case *ast.IncDecStmt:
			var  action
			switch .Tok {
			case token.INC:
				 = aInc
			case token.DEC:
				 = aDec
			}
			.push((&, , , incDecStmt, ), )

		case *ast.IndexExpr:
			.push((&, , , indexExpr, aGetIndex), )

		case *ast.IndexListExpr:
			.push((&, , , indexListExpr, aNop), )

		case *ast.InterfaceType:
			.push((&, , , interfaceType, aNop), )

		case *ast.KeyValueExpr:
			.push((&, , , keyValueExpr, aNop), )

		case *ast.LabeledStmt:
			.push((&, , , labeledStmt, aNop), )

		case *ast.MapType:
			.push((&, , , mapType, aNop), )

		case *ast.ParenExpr:
			.push((&, , , parenExpr, aNop), )

		case *ast.RangeStmt:
			// Insert a missing ForRangeStmt for AST correctness
			 := (&, , , forRangeStmt, aNop)
			 := (&, astNode{, }, , rangeStmt, aRange)
			.push(, )
			if .Key == nil {
				// range not in an assign expression: insert a "_" key variable to store iteration index
				 := (&, astNode{, }, , identExpr, aNop)
				.ident = "_"
			}

		case *ast.ReturnStmt:
			.push((&, , , returnStmt, aReturn), )

		case *ast.SelectStmt:
			.push((&, , , selectStmt, aNop), )

		case *ast.SelectorExpr:
			.push((&, , , selectorExpr, aGetIndex), )

		case *ast.SendStmt:
			.push((&, , , sendStmt, aSend), )

		case *ast.SliceExpr:
			if .Low == nil {
				.push((&, , , sliceExpr, aSlice0), )
			} else {
				.push((&, , , sliceExpr, aSlice), )
			}

		case *ast.StarExpr:
			.push((&, , , starExpr, aStar), )

		case *ast.StructType:
			.push((&, , , structType, aNop), )

		case *ast.SwitchStmt:
			if .Tag == nil {
				.push((&, , , switchIfStmt, aNop), )
			} else {
				.push((&, , , switchStmt, aNop), )
			}

		case *ast.TypeAssertExpr:
			.push((&, , , typeAssertExpr, aTypeAssert), )

		case *ast.TypeSpec:
			if .Assign.IsValid() {
				.push((&, , , typeSpecAssign, aNop), )
				break
			}
			.push((&, , , typeSpec, aNop), )

		case *ast.TypeSwitchStmt:
			 := (&, , , typeSwitch, aNop)
			.push(, )
			if .Init == nil {
				// add an empty init node to disambiguate AST
				(&, astNode{, nil}, , fieldList, aNop)
			}

		case *ast.UnaryExpr:
			 := unaryExpr
			var  action
			switch .Op {
			case token.ADD:
				 = aPos
			case token.AND:
				 = addressExpr
				 = aAddr
			case token.ARROW:
				 = aRecv
			case token.NOT:
				 = aNot
			case token.SUB:
				 = aNeg
			case token.XOR:
				 = aBitNot
			}
			.push((&, , , , ), )

		case *ast.ValueSpec:
			 := valueSpec
			 := aNop
			switch {
			case .Values != nil:
				if len(.Names) > 1 && len(.Values) == 1 {
					if .node.kind == constDecl || .node.kind == varDecl {
						 = defineXStmt
					} else {
						 = assignXStmt
					}
					 = aAssignX
				} else {
					if .node.kind == constDecl || .node.kind == varDecl {
						 = defineStmt
					} else {
						 = assignStmt
					}
					 = aAssign
				}
			case .node.kind == constDecl:
				,  = defineStmt, aAssign
			case .node.kind == varDecl && .node.anc.kind != fileStmt:
				,  = defineStmt, aAssign
			}
			 := (&, , , , )
			.nleft = len(.Names)
			.nright = len(.Values)
			.push(, )

		default:
			 = astError(fmt.Errorf("ast: %T not implemented, line %s", , .fset.Position()))
			return false
		}
		return true
	})

	.roots = append(.roots, )
	return , , 
}

type astNode struct {
	node *node
	ast  ast.Node
}

type nodestack []astNode

func ( *nodestack) ( *node,  ast.Node) {
	* = append(*, astNode{, })
}

func ( *nodestack) () astNode {
	 := len(*) - 1
	 := (*)[]
	* = (*)[:]
	return 
}

func ( *nodestack) () astNode {
	 := len(*)
	if  > 0 {
		return (*)[-1]
	}
	return astNode{}
}

// dup returns a duplicated node subtree.
func ( *Interpreter) (,  *node) *node {
	 := atomic.AddInt64(&.nindex, 1)
	 := *
	.index = 
	.anc = 
	.start = &
	.pos = .pos
	.child = nil
	for ,  := range .child {
		.child = append(.child, .(, &))
	}
	return &
}