protected internal virtual Node VisitLet(bool createWith, Node parent, Node previous, Node scopeNode)
{
Node vars = scopeNode.GetFirstChild();
Node body = vars.GetNext();
scopeNode.RemoveChild(vars);
scopeNode.RemoveChild(body);
bool isExpression = scopeNode.GetType() == Token.LETEXPR;
Node result;
Node newVars;
if (createWith)
{
result = new Node(isExpression ? Token.WITHEXPR : Token.BLOCK);
result = ReplaceCurrent(parent, previous, scopeNode, result);
List<object> list = new List<object>();
Node objectLiteral = new Node(Token.OBJECTLIT);
for (Node v = vars.GetFirstChild(); v != null; v = v.GetNext())
{
Node current = v;
if (current.GetType() == Token.LETEXPR)
{
// destructuring in let expr, e.g. let ([x, y] = [3, 4]) {}
IList<object> destructuringNames = (IList<object>)current.GetProp(Node.DESTRUCTURING_NAMES);
Node c = current.GetFirstChild();
if (c.GetType() != Token.LET)
{
throw Kit.CodeBug();
}
// Add initialization code to front of body
if (isExpression)
{
body = new Node(Token.COMMA, c.GetNext(), body);
}
else
{
body = new Node(Token.BLOCK, new Node(Token.EXPR_VOID, c.GetNext()), body);
}
// Update "list" and "objectLiteral" for the variables
// defined in the destructuring assignment
if (destructuringNames != null)
{
Sharpen.Collections.AddAll(list, destructuringNames);
for (int i = 0; i < destructuringNames.Count; i++)
{
objectLiteral.AddChildToBack(new Node(Token.VOID, Node.NewNumber(0.0)));
}
}
current = c.GetFirstChild();
}
// should be a NAME, checked below
if (current.GetType() != Token.NAME)
{
throw Kit.CodeBug();
}
list.Add(ScriptRuntime.GetIndexObject(current.GetString()));
Node init = current.GetFirstChild();
if (init == null)
{
init = new Node(Token.VOID, Node.NewNumber(0.0));
}
objectLiteral.AddChildToBack(init);
}
objectLiteral.PutProp(Node.OBJECT_IDS_PROP, Sharpen.Collections.ToArray(list));
newVars = new Node(Token.ENTERWITH, objectLiteral);
result.AddChildToBack(newVars);
result.AddChildToBack(new Node(Token.WITH, body));
result.AddChildToBack(new Node(Token.LEAVEWITH));
}
else
{
result = new Node(isExpression ? Token.COMMA : Token.BLOCK);
result = ReplaceCurrent(parent, previous, scopeNode, result);
newVars = new Node(Token.COMMA);
for (Node v = vars.GetFirstChild(); v != null; v = v.GetNext())
{
Node current = v;
if (current.GetType() == Token.LETEXPR)
{
// destructuring in let expr, e.g. let ([x, y] = [3, 4]) {}
Node c = current.GetFirstChild();
if (c.GetType() != Token.LET)
{
throw Kit.CodeBug();
}
// Add initialization code to front of body
if (isExpression)
{
body = new Node(Token.COMMA, c.GetNext(), body);
}
else
{
body = new Node(Token.BLOCK, new Node(Token.EXPR_VOID, c.GetNext()), body);
}
// We're removing the LETEXPR, so move the symbols
Scope.JoinScopes((Scope)current, (Scope)scopeNode);
current = c.GetFirstChild();
}
// should be a NAME, checked below
if (current.GetType() != Token.NAME)
{
throw Kit.CodeBug();
}
Node stringNode = Node.NewString(current.GetString());
stringNode.SetScope((Scope)scopeNode);
Node init = current.GetFirstChild();
if (init == null)
{
init = new Node(Token.VOID, Node.NewNumber(0.0));
}
newVars.AddChildToBack(new Node(Token.SETVAR, stringNode, init));
}
if (isExpression)
{
result.AddChildToBack(newVars);
scopeNode.SetType(Token.COMMA);
result.AddChildToBack(scopeNode);
scopeNode.AddChildToBack(body);
if (body is Scope)
{
Scope scopeParent = ((Scope)body).GetParentScope();
((Scope)body).SetParentScope((Scope)scopeNode);
((Scope)scopeNode).SetParentScope(scopeParent);
}
}
else
{
result.AddChildToBack(new Node(Token.EXPR_VOID, newVars));
scopeNode.SetType(Token.BLOCK);
result.AddChildToBack(scopeNode);
scopeNode.AddChildrenToBack(body);
if (body is Scope)
{
Scope scopeParent = ((Scope)body).GetParentScope();
((Scope)body).SetParentScope((Scope)scopeNode);
((Scope)scopeNode).SetParentScope(scopeParent);
}
}
}
return result;
}