353 linhas
13 KiB
C++
353 linhas
13 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifndef incl_HPHP_COMPILER_PARSER_H_
|
|
#define incl_HPHP_COMPILER_PARSER_H_
|
|
|
|
#include "runtime/base/util/exceptions.h"
|
|
#include "util/parser/parser.h"
|
|
#include "compiler/construct.h"
|
|
#include "compiler/option.h"
|
|
#include "compiler/type_annotation.h"
|
|
#include "compiler/expression/scalar_expression.h"
|
|
|
|
#ifdef HPHP_PARSER_NS
|
|
#undef HPHP_PARSER_NS
|
|
#endif
|
|
#define HPHP_PARSER_NS Compiler
|
|
|
|
#ifdef HPHP_PARSER_ERROR
|
|
#undef HPHP_PARSER_ERROR
|
|
#endif
|
|
#define HPHP_PARSER_ERROR(fmt, p, args...) \
|
|
do { \
|
|
if (HPHP::Option::WholeProgram) { \
|
|
HPHP::Logger::Error(fmt " %s", ##args, (p)->getMessage(true).c_str()); \
|
|
} \
|
|
throw HPHP::ParseTimeFatalException((p)->file(), (p)->line1(), \
|
|
fmt, ##args); \
|
|
} while (0)
|
|
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
DECLARE_BOOST_TYPES(Expression);
|
|
DECLARE_BOOST_TYPES(Statement);
|
|
DECLARE_BOOST_TYPES(StatementList);
|
|
DECLARE_BOOST_TYPES(Location);
|
|
DECLARE_BOOST_TYPES(AnalysisResult);
|
|
DECLARE_BOOST_TYPES(BlockScope);
|
|
DECLARE_BOOST_TYPES(TypeAnnotation);
|
|
|
|
namespace Compiler {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// scanner
|
|
|
|
class Token : public ScannerToken {
|
|
public:
|
|
ExpressionPtr exp;
|
|
StatementPtr stmt;
|
|
TypeAnnotationPtr typeAnnotation;
|
|
|
|
Token &operator+(const char *str) {
|
|
m_text += str;
|
|
return *this;
|
|
}
|
|
Token &operator+(const Token &token) {
|
|
m_num += token.m_num;
|
|
m_text += token.m_text;
|
|
return *this;
|
|
}
|
|
Token *operator->() {
|
|
return this;
|
|
}
|
|
void operator=(int num) {
|
|
m_num = num;
|
|
}
|
|
void operator=(Token &other) {
|
|
ScannerToken::operator=(other);
|
|
exp = other.exp;
|
|
stmt = other.stmt;
|
|
typeAnnotation = other.typeAnnotation;
|
|
}
|
|
void reset() {
|
|
exp.reset();
|
|
stmt.reset();
|
|
typeAnnotation.reset();
|
|
ScannerToken::reset();
|
|
}
|
|
const std::string typeAnnotationName() {
|
|
return (typeAnnotation) ? typeAnnotation->fullName() : "";
|
|
}
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
DECLARE_BOOST_TYPES(Parser);
|
|
class Parser : public ParserBase {
|
|
public:
|
|
static StatementListPtr ParseString(CStrRef input, AnalysisResultPtr ar,
|
|
const char *fileName = nullptr,
|
|
bool lambdaMode = false);
|
|
|
|
public:
|
|
Parser(Scanner &scanner, const char *fileName,
|
|
AnalysisResultPtr ar, int fileSize = 0);
|
|
|
|
// implementing ParserBase
|
|
virtual bool parseImpl();
|
|
bool parse();
|
|
virtual void error(const char* fmt, ...);
|
|
virtual bool enableXHP();
|
|
virtual bool enableFinallyStatement();
|
|
IMPLEMENT_XHP_ATTRIBUTES;
|
|
|
|
virtual void fatal(Location *loc, const char *msg);
|
|
std::string errString();
|
|
|
|
// result
|
|
StatementListPtr getTree() const { return m_tree;}
|
|
|
|
// parser handlers
|
|
void initParseTree();
|
|
void finiParseTree();
|
|
void onHaltCompiler();
|
|
void onName(Token &out, Token &name, NameKind kind);
|
|
void onVariable(Token &out, Token *exprs, Token &var, Token *value,
|
|
bool constant = false,
|
|
const std::string &docComment = "");
|
|
void onStaticVariable(Token &out, Token *exprs, Token &var, Token *value);
|
|
void onClassVariableModifer(Token &mod) {}
|
|
void onClassVariableStart(Token &out, Token *modifiers, Token &decl,
|
|
Token *type);
|
|
void onClassVariable(Token &out, Token *exprs, Token &var, Token *value);
|
|
void onClassConstant(Token &out, Token *exprs, Token &var, Token &value);
|
|
void onSimpleVariable(Token &out, Token &var);
|
|
void onSynthesizedVariable(Token &out, Token &var) {
|
|
onSimpleVariable(out, var);
|
|
}
|
|
void onDynamicVariable(Token &out, Token &expr, bool encap);
|
|
void onIndirectRef(Token &out, Token &refCount, Token &var);
|
|
void onStaticMember(Token &out, Token &cls, Token &name);
|
|
void onRefDim(Token &out, Token &var, Token &offset);
|
|
void onCallParam(Token &out, Token *params, Token &expr, bool ref);
|
|
void onCall(Token &out, bool dynamic, Token &name, Token ¶ms,
|
|
Token *cls, bool fromCompiler = false);
|
|
void onEncapsList(Token &out, int type, Token &list);
|
|
void addEncap(Token &out, Token *list, Token &expr, int type);
|
|
void encapRefDim(Token &out, Token &var, Token &offset);
|
|
void encapObjProp(Token &out, Token &var, Token &name);
|
|
void encapArray(Token &out, Token &var, Token &expr);
|
|
void onConstantValue(Token &out, Token &constant);
|
|
void onScalar(Token &out, int type, Token &scalar);
|
|
void onExprListElem(Token &out, Token *exprs, Token &expr);
|
|
|
|
void onObjectProperty(Token &out, Token &base, Token &prop);
|
|
void onObjectMethodCall(Token &out, Token &base, Token &prop, Token ¶ms);
|
|
|
|
void onListAssignment(Token &out, Token &vars, Token *expr,
|
|
bool rhsFirst = false);
|
|
void onAListVar(Token &out, Token *list, Token *var);
|
|
void onAListSub(Token &out, Token *list, Token &sublist);
|
|
void onAssign(Token &out, Token &var, Token &expr, bool ref,
|
|
bool rhsFirst = false);
|
|
void onAssignNew(Token &out, Token &var, Token &name, Token &args);
|
|
void onNewObject(Token &out, Token &name, Token &args);
|
|
void onUnaryOpExp(Token &out, Token &operand, int op, bool front);
|
|
void onBinaryOpExp(Token &out, Token &operand1, Token &operand2, int op);
|
|
void onQOp(Token &out, Token &exprCond, Token *expYes, Token &expNo);
|
|
void onArray(Token &out, Token &pairs, int op = T_ARRAY);
|
|
void onArrayPair(Token &out, Token *pairs, Token *name, Token &value,
|
|
bool ref);
|
|
void onEmptyCollection(Token &out);
|
|
void onCollectionPair(Token &out, Token *pairs, Token *name, Token &value);
|
|
void onUserAttribute(Token &out, Token *attrList, Token &name, Token &value);
|
|
void onClassConst(Token &out, Token &cls, Token &name, bool text);
|
|
void fixStaticVars();
|
|
void onFunctionStart(Token &name, bool doPushComment = true);
|
|
void onFunction(Token &out, Token *modifier, Token &ret, Token &ref,
|
|
Token &name, Token ¶ms, Token &stmt, Token *attr);
|
|
void onParam(Token &out, Token *params, Token &type, Token &var,
|
|
bool ref, Token *defValue, Token *attr);
|
|
void onClassStart(int type, Token &name);
|
|
void onClass(Token &out, int type, Token &name, Token &base,
|
|
Token &baseInterface, Token &stmt, Token *attr);
|
|
void onInterface(Token &out, Token &name, Token &base, Token &stmt,
|
|
Token *attr);
|
|
void onInterfaceName(Token &out, Token *names, Token &name);
|
|
void onTraitUse(Token &out, Token &traits, Token &rules);
|
|
void onTraitName(Token &out, Token *names, Token &name);
|
|
void onTraitRule(Token &out, Token &stmtList, Token &newStmt);
|
|
void onTraitPrecRule(Token &out, Token &className, Token &methodName,
|
|
Token &otherClasses);
|
|
void onTraitAliasRuleStart(Token &out, Token &className, Token &methodName);
|
|
void onTraitAliasRuleModify(Token &out, Token &rule, Token &accessModifiers,
|
|
Token &newMethodName);
|
|
void onMethodStart(Token &name, Token &mods, bool doPushComment = true);
|
|
void onMethod(Token &out, Token &modifiers, Token &ret, Token &ref,
|
|
Token &name, Token ¶ms, Token &stmt, Token *attr,
|
|
bool reloc = true);
|
|
void onMemberModifier(Token &out, Token *modifiers, Token &modifier);
|
|
void onStatementListStart(Token &out);
|
|
void addStatement(Token &out, Token &stmts, Token &new_stmt);
|
|
void addTopStatement(Token &new_stmt);
|
|
void onClassStatement(Token &out, Token &stmts, Token &new_stmt) {
|
|
addStatement(out, stmts, new_stmt);
|
|
}
|
|
void finishStatement(Token &out, Token &stmts);
|
|
void onBlock(Token &out, Token &stmts);
|
|
void onIf(Token &out, Token &cond, Token &stmt, Token &elseifs,
|
|
Token &elseStmt);
|
|
void onElseIf(Token &out, Token &elseifs, Token &cond, Token &stmt);
|
|
void onWhile(Token &out, Token &cond, Token &stmt);
|
|
void onDo(Token &out, Token &stmt, Token &cond);
|
|
void onFor(Token &out, Token &expr1, Token &expr2, Token &expr3,
|
|
Token &stmt);
|
|
void onSwitch(Token &out, Token &expr, Token &cases);
|
|
void onCase(Token &out, Token &cases, Token *cond, Token &stmt);
|
|
void onBreak(Token &out, Token *expr);
|
|
void onContinue(Token &out, Token *expr);
|
|
void onReturn(Token &out, Token *expr);
|
|
void onYield(Token &out, Token &expr);
|
|
void onYieldBreak(Token &out);
|
|
void onGlobal(Token &out, Token &expr);
|
|
void onGlobalVar(Token &out, Token *exprs, Token &expr);
|
|
void onStatic(Token &out, Token &expr);
|
|
void onEcho(Token &out, Token &expr, bool html);
|
|
void onUnset(Token &out, Token &expr);
|
|
void onExpStatement(Token &out, Token &expr);
|
|
void onForEachStart();
|
|
void onForEach(Token &out, Token &arr, Token &name, Token &value,
|
|
Token &stmt);
|
|
void onTry(Token &out, Token &tryStmt, Token &className, Token &var,
|
|
Token &catchStmt, Token &catches, Token &finallyStmt);
|
|
void onTry(Token &out, Token &tryStmt, Token &finallyStmt);
|
|
void onCatch(Token &out, Token &catches, Token &className, Token &var,
|
|
Token &stmt);
|
|
void onFinally(Token &out, Token &stmt);
|
|
void onThrow(Token &out, Token &expr);
|
|
|
|
void onClosureStart(Token &name);
|
|
void onClosure(Token &out, Token &ret, Token &ref, Token ¶ms,
|
|
Token &cparams, Token &stmts, bool is_static);
|
|
void onClosureParam(Token &out, Token *params, Token ¶m, bool ref);
|
|
void onLabel(Token &out, Token &label);
|
|
void onGoto(Token &out, Token &label, bool limited);
|
|
void onTypedef(Token& out, const Token& name, const Token& type);
|
|
|
|
void onTypeAnnotation(Token& out, const Token& name, const Token& typeArgs);
|
|
void onTypeList(Token& type1, const Token& type2);
|
|
void onTypeSpecialization(Token& type, char specialization);
|
|
|
|
// for namespace support
|
|
void onNamespaceStart(const std::string &ns, bool file_scope = false);
|
|
void onNamespaceEnd();
|
|
void onUse(const std::string &ns, const std::string &as);
|
|
void nns(int token = 0);
|
|
std::string nsDecl(const std::string &name);
|
|
std::string resolve(const std::string &ns, bool cls);
|
|
|
|
virtual void invalidateGoto(TStatementPtr stmt, GotoError error);
|
|
virtual void invalidateLabel(TStatementPtr stmt);
|
|
|
|
virtual TStatementPtr extractStatement(ScannerToken *stmt);
|
|
|
|
FileScopePtr getFileScope() { return m_file; }
|
|
|
|
private:
|
|
struct FunctionContext {
|
|
FunctionContext()
|
|
: isNotGenerator(false)
|
|
, isGenerator(false)
|
|
{}
|
|
|
|
// mark this function as generator; returns true on success
|
|
bool setIsGenerator() {
|
|
if (!isNotGenerator) isGenerator = true;
|
|
return !isNotGenerator;
|
|
}
|
|
|
|
// mark this function as non-generator; returns true on success
|
|
bool setIsNotGenerator() {
|
|
if (!isGenerator) isNotGenerator = true;
|
|
return !isGenerator;
|
|
}
|
|
|
|
void checkFinalAssertions() {
|
|
assert(!isGenerator || !isNotGenerator);
|
|
}
|
|
|
|
bool isNotGenerator; // function determined to not be a generator
|
|
bool isGenerator; // function determined to be a generator
|
|
};
|
|
|
|
AnalysisResultPtr m_ar;
|
|
FileScopePtr m_file;
|
|
std::vector<std::string> m_comments; // for docComment stack
|
|
std::vector<BlockScopePtrVec> m_scopes;
|
|
std::vector<FunctionContext> m_funcContexts;
|
|
std::vector<std::vector<StatementPtr> > m_prependingStatements;
|
|
std::vector<ScalarExpressionPtr> m_compilerHaltOffsetVec;
|
|
std::string m_clsName; // for T_CLASS_C inside a closure
|
|
std::string m_funcName;
|
|
bool m_inTrait;
|
|
|
|
// parser output
|
|
StatementListPtr m_tree;
|
|
std::string m_error;
|
|
|
|
std::vector<bool> m_hasCallToGetArgs;
|
|
std::vector<StringToExpressionPtrVecMap> m_staticVars;
|
|
bool m_lambdaMode;
|
|
bool m_closureGenerator;
|
|
|
|
void pushComment();
|
|
void pushComment(const std::string& s);
|
|
std::string popComment();
|
|
|
|
void newScope();
|
|
void completeScope(BlockScopePtr inner);
|
|
|
|
bool setIsGenerator();
|
|
|
|
ExpressionPtr getDynamicVariable(ExpressionPtr exp, bool encap);
|
|
ExpressionPtr createDynamicVariable(ExpressionPtr exp);
|
|
|
|
bool hasType(Token &type);
|
|
|
|
void checkAssignThis(Token &var);
|
|
|
|
void addStatement(StatementPtr stmt, StatementPtr new_stmt);
|
|
|
|
// for namespace support
|
|
enum NamespaceState {
|
|
SeenNothing,
|
|
SeenNonNamespaceStatement,
|
|
SeenNamespaceStatement,
|
|
InsideNamespace,
|
|
};
|
|
NamespaceState m_nsState;
|
|
bool m_nsFileScope;
|
|
std::string m_namespace; // current namespace
|
|
hphp_string_imap<std::string> m_aliases;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}}
|
|
|
|
#endif
|