escargot/src/parser/ScriptParser.cpp
Junyoung Cho 0faef8219f - Apply strict within eval from outside strict context
- Fix octal bug in parser
2016-12-23 10:19:51 +09:00

174 lines
7.5 KiB
C++

#include "Escargot.h"
#include "ScriptParser.h"
#include "runtime/Context.h"
#include "interpreter/ByteCode.h"
#include "parser/esprima_cpp/esprima.h"
#include "parser/ast/AST.h"
#include "parser/CodeBlock.h"
namespace Escargot {
ScriptParser::ScriptParser(Context* c)
: m_context(c)
{
}
CodeBlock* ScriptParser::generateCodeBlockTreeFromASTWalker(Context* ctx, StringView source, Script* script, ASTScopeContext* scopeCtx, CodeBlock* parentCodeBlock)
{
CodeBlock* codeBlock;
if (parentCodeBlock == nullptr) {
// globalBlock
codeBlock = new CodeBlock(ctx, script, source, scopeCtx->m_isStrict, scopeCtx->m_locStart, scopeCtx->m_names,
(CodeBlock::CodeBlockInitFlag)((scopeCtx->m_hasEval ? CodeBlock::CodeBlockHasEval : 0)
| (scopeCtx->m_hasWith ? CodeBlock::CodeBlockHasWith : 0)
| (scopeCtx->m_hasCatch ? CodeBlock::CodeBlockHasCatch : 0)
| (scopeCtx->m_hasYield ? CodeBlock::CodeBlockHasYield : 0)));
} else {
codeBlock = new CodeBlock(ctx, script, StringView(source, scopeCtx->m_locStart.index, scopeCtx->m_locEnd.index),
scopeCtx->m_locStart,
scopeCtx->m_isStrict, scopeCtx->m_nodeStartIndex,
scopeCtx->m_functionName, scopeCtx->m_parameters, scopeCtx->m_names, parentCodeBlock,
(CodeBlock::CodeBlockInitFlag)((scopeCtx->m_hasEval ? CodeBlock::CodeBlockHasEval : 0)
| (scopeCtx->m_hasWith ? CodeBlock::CodeBlockHasWith : 0)
| (scopeCtx->m_hasCatch ? CodeBlock::CodeBlockHasCatch : 0)
| (scopeCtx->m_hasYield ? CodeBlock::CodeBlockHasYield : 0)
| (scopeCtx->m_associateNode->type() == FunctionExpression ? CodeBlock::CodeBlockIsFunctionExpression : 0)
| (scopeCtx->m_associateNode->type() == FunctionDeclaration ? CodeBlock::CodeBlockIsFunctionDeclaration : 0)));
}
#ifndef NDEBUG
codeBlock->m_locStart = scopeCtx->m_locStart;
codeBlock->m_locEnd = scopeCtx->m_locEnd;
codeBlock->m_scopeContext = scopeCtx;
#endif
if (parentCodeBlock) {
if (codeBlock->hasEvalWithCatchYield()) {
CodeBlock* c = codeBlock;
while (c) {
c->notifySelfOrChildHasEvalWithCatchYield();
c = c->parentCodeBlock();
}
}
for (size_t i = 0; i < scopeCtx->m_usingNames.size(); i++) {
AtomicString uname = scopeCtx->m_usingNames[i];
if (!codeBlock->hasName(uname)) {
CodeBlock* c = codeBlock->parentCodeBlock();
while (c) {
if (c->tryCaptureIdentifiersFromChildCodeBlock(uname))
break;
c = c->parentCodeBlock();
}
}
}
}
for (size_t i = 0; i < scopeCtx->m_childScopes.size(); i++) {
codeBlock->appendChildBlock(generateCodeBlockTreeFromASTWalker(ctx, source, script, scopeCtx->m_childScopes[i], codeBlock));
}
if (parentCodeBlock) {
codeBlock->computeVariables();
}
return codeBlock;
}
// generate code blocks from AST
CodeBlock* ScriptParser::generateCodeBlockTreeFromAST(Context* ctx, StringView source, Script* script, ProgramNode* program)
{
return generateCodeBlockTreeFromASTWalker(ctx, source, script, program->scopeContext(), nullptr);
}
ScriptParser::ScriptParserResult ScriptParser::parse(StringView scriptSource, String* fileName, CodeBlock* parentCodeBlock, bool strictFromOutside)
{
Script* script = nullptr;
ScriptParseError* error = nullptr;
try {
ProgramNode* program = esprima::parseProgram(m_context, scriptSource, nullptr, strictFromOutside);
script = new Script(fileName);
CodeBlock* topCodeBlock;
if (parentCodeBlock) {
program->scopeContext()->m_hasEval = parentCodeBlock->hasEval();
program->scopeContext()->m_hasWith = parentCodeBlock->hasWith();
program->scopeContext()->m_hasCatch = parentCodeBlock->hasCatch();
program->scopeContext()->m_hasYield = parentCodeBlock->hasYield();
topCodeBlock = generateCodeBlockTreeFromASTWalker(m_context, scriptSource, script, program->scopeContext(), parentCodeBlock);
} else {
topCodeBlock = generateCodeBlockTreeFromAST(m_context, scriptSource, script, program);
}
topCodeBlock->m_cachedASTNode = program;
script->m_topCodeBlock = topCodeBlock;
// dump Code Block
#ifndef NDEBUG
if (getenv("DUMP_CODEBLOCK_TREE") && strlen(getenv("DUMP_CODEBLOCK_TREE"))) {
std::function<void(CodeBlock*, size_t depth)> fn = [&fn](CodeBlock* cb, size_t depth) {
#define PRINT_TAB() \
for (size_t i = 0; i < depth; i++) { \
printf(" "); \
}
PRINT_TAB()
printf("CodeBlock %s (%d:%d -> %d:%d)(%s, %s) (E:%d, W:%d, C:%d, Y:%d)\n", cb->m_functionName.string()->toUTF8StringData().data(),
(int)cb->m_locStart.line,
(int)cb->m_locStart.column,
(int)cb->m_locEnd.line,
(int)cb->m_locEnd.column,
cb->m_canAllocateEnvironmentOnStack ? "Stack" : "Heap",
cb->m_canUseIndexedVariableStorage ? "Indexed" : "Named",
(int)cb->m_hasEval, (int)cb->m_hasWith, (int)cb->m_hasCatch, (int)cb->m_hasYield);
PRINT_TAB()
printf("Names: ");
for (size_t i = 0; i < cb->m_identifierInfos.size(); i++) {
printf("%s(%s, %d), ", cb->m_identifierInfos[i].m_name.string()->toUTF8StringData().data(),
cb->m_identifierInfos[i].m_needToAllocateOnStack ? "Stack" : "Heap", (int)cb->m_identifierInfos[i].m_indexForIndexedStorage);
}
puts("");
PRINT_TAB()
printf("Using Names: ");
for (size_t i = 0; i < cb->m_scopeContext->m_usingNames.size(); i++) {
printf("%s, ", cb->m_scopeContext->m_usingNames[i].string()->toUTF8StringData().data());
}
puts("");
for (size_t i = 0; i < cb->m_childBlocks.size(); i++) {
fn(cb->m_childBlocks[i], depth + 1);
}
};
fn(topCodeBlock, 0);
}
#endif
} catch (esprima::Error* orgError) {
script = nullptr;
error = new ScriptParseError();
error->column = orgError->column;
error->description = orgError->description;
error->index = orgError->index;
error->lineNumber = orgError->lineNumber;
error->message = orgError->message;
error->name = orgError->name;
}
ScriptParser::ScriptParserResult result(script, error);
return result;
}
Node* ScriptParser::parseFunction(CodeBlock* codeBlock)
{
try {
Node* body = esprima::parseSingleFunction(m_context, codeBlock);
return body;
} catch (esprima::Error* orgError) {
//
RELEASE_ASSERT_NOT_REACHED();
}
}
}