/**
* Copyright 2013 Douglas Campos, and individual contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dynjs.parser.ast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.dynjs.parser.CodeVisitor;
import org.dynjs.parser.Statement;
import org.dynjs.parser.js.Position;
import org.dynjs.runtime.Completion;
import org.dynjs.runtime.ExecutionContext;
import org.dynjs.runtime.Types;
public class BlockStatement extends AbstractStatement {
private final List<Statement> blockContent;
private List<FunctionDeclaration> functionDeclarations = null;
private List<VariableDeclaration> variableDeclarations = null;
public BlockStatement(final List<Statement> blockContent) {
this.blockContent = blockContent;
}
public Position getPosition() {
if ( blockContent.isEmpty() ) {
return null;
}
return blockContent.get(0).getPosition();
}
public List<Statement> getBlockContent() {
return this.blockContent;
}
public List<BlockStatement> getAsChunks(int chunkSize) {
if (this.blockContent.size() <= chunkSize) {
return Collections.singletonList(this);
}
List<BlockStatement> chunks = new ArrayList<>();
int chunkStart = 0;
int totalStatements = this.blockContent.size();
while (chunkStart < totalStatements) {
int chunkEnd = chunkStart + chunkSize;
if (chunkEnd > totalStatements) {
chunkEnd = totalStatements;
}
chunks.add(new BlockStatement(this.blockContent.subList(chunkStart, chunkEnd)));
chunkStart = chunkEnd;
}
return chunks;
}
public List<FunctionDeclaration> getFunctionDeclarations() {
if (this.functionDeclarations != null) {
return this.functionDeclarations;
}
if (this.blockContent == null) {
return Collections.emptyList();
}
List<FunctionDeclaration> decls = new ArrayList<>();
for (Statement each : this.blockContent) {
if (each instanceof FunctionDeclaration) {
decls.add((FunctionDeclaration) each);
}
decls.addAll(each.getFunctionDeclarations());
}
this.functionDeclarations = decls;
return decls;
}
public List<VariableDeclaration> getVariableDeclarations() {
if (this.variableDeclarations != null) {
return this.variableDeclarations;
}
List<VariableDeclaration> decls = new ArrayList<>();
for (Statement each : this.blockContent) {
if (each instanceof VariableStatement) {
VariableStatement statement = (VariableStatement) each;
decls.addAll(statement.getVariableDeclarations());
} else if (!(each instanceof FunctionDeclaration)) {
decls.addAll(each.getVariableDeclarations());
}
}
this.variableDeclarations = decls;
return decls;
}
public Object accept(Object context, CodeVisitor visitor, boolean strict) {
return visitor.visit(context, this, strict);
}
public String dump(String indent) {
StringBuilder buffer = new StringBuilder();
buffer.append(super.dump(indent));
for (Statement each : this.blockContent) {
buffer.append(each.dump(indent + " "));
}
return buffer.toString();
}
public int getSizeMetric() {
return 3;
}
@Override
public Completion interpret(ExecutionContext context, boolean debug) {
List<Statement> content = getBlockContent();
Object completionValue = Types.UNDEFINED;
Statement previousStatement = null;
for (Statement each : content) {
Position position = each.getPosition();
if (position != null) {
context.setLineNumber(position.getLine());
context.setColumnNumber(position.getColumn());
}
if ( ! ( each instanceof FunctionDeclaration ) ) {
context.debug( each, previousStatement );
}
Completion completion = (Completion) each.interpret(context, debug);
if ( ! ( each instanceof FunctionDeclaration ) ) {
previousStatement = each;
}
if (completion.type == Completion.Type.NORMAL) {
completionValue = completion.value;
continue;
}
if (completion.type == Completion.Type.CONTINUE) {
return(completion);
}
if (completion.type == Completion.Type.RETURN) {
return(completion);
}
if (completion.type == Completion.Type.BREAK) {
completion.value = completionValue;
if (completion.target != null && getLabels().contains(completion.target)) {
return(Completion.createNormal(completionValue));
} else {
return(completion);
}
}
}
return(Completion.createNormal(completionValue));
}
public String toIndentedString(String indent) {
StringBuilder buffer = new StringBuilder();
for (Statement each : this.blockContent) {
if (each != null) {
buffer.append(each.toIndentedString(indent));
buffer.append("\n");
}
}
return buffer.toString();
}
}