| // Copyright 2015 Google Inc. All rights reserved |
| // |
| // 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. |
| |
| #ifndef EVAL_H_ |
| #define EVAL_H_ |
| |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <unordered_map> |
| #include <unordered_set> |
| #include <vector> |
| |
| #include "loc.h" |
| #include "stmt.h" |
| #include "string_piece.h" |
| #include "symtab.h" |
| |
| using namespace std; |
| |
| class Makefile; |
| class Rule; |
| class Var; |
| class Vars; |
| |
| class IncludeGraph; |
| |
| enum RulesAllowed { RULES_ALLOWED = 0, RULES_WARNING = 1, RULES_ERROR = 2 }; |
| |
| enum FrameType { |
| ROOT, // Root node. Exactly one of this exists. |
| PHASE, // Markers for various phases of the execution. |
| PARSE, // Initial evaluation pass: include, := variables, etc. |
| CALL, // Evaluating the result of a function call |
| FUNCALL, // Evaluating a function call (not its result) |
| STATEMENT, // Denotes individual statements for better location reporting |
| DEPENDENCY, // Dependency analysis. += requires variable expansion here. |
| EXEC, // Execution phase. Expansoin of = and rule-specific variables. |
| NINJA, // Ninja file generation |
| }; |
| |
| class Frame { |
| public: |
| // for the top-level Makefile |
| Frame(FrameType type, Frame* parent, Loc loc, const std::string& name); |
| |
| ~Frame(); |
| |
| FrameType Type() const { return type_; } |
| Frame* Parent() const { return parent_; } |
| const string& Name() const { return name_; } |
| const Loc& Location() const { return location_; } |
| const std::vector<std::unique_ptr<Frame>>& Children() const { |
| return children_; |
| } |
| |
| void PrintJSONTrace(FILE* f, int indent) const; |
| |
| void Add(std::unique_ptr<Frame> child); |
| |
| private: |
| FrameType type_; |
| Frame* parent_; |
| std::string name_; |
| Loc location_; |
| std::vector<std::unique_ptr<Frame>> children_; |
| }; |
| |
| class ScopedFrame { |
| public: |
| ScopedFrame(Evaluator* ev, Frame* frame); |
| // We only allow moving; copying would double stack frames |
| ScopedFrame(const ScopedFrame& other) = delete; |
| ScopedFrame& operator=(const ScopedFrame&) = delete; |
| ScopedFrame(ScopedFrame&& other); |
| ~ScopedFrame(); |
| |
| Frame* Current() const { return frame_; } |
| |
| private: |
| Evaluator* ev_; |
| Frame* frame_; |
| }; |
| |
| class IncludeGraphNode { |
| friend IncludeGraph; |
| |
| public: |
| IncludeGraphNode(const Frame* frame); |
| ~IncludeGraphNode(); |
| |
| private: |
| std::string filename_; |
| std::set<std::string> includes_; |
| }; |
| |
| class IncludeGraph { |
| public: |
| IncludeGraph(); |
| ~IncludeGraph(); |
| |
| void DumpJSON(FILE* output); |
| void MergeTreeNode(const Frame* frame); |
| |
| private: |
| std::map<std::string, std::unique_ptr<IncludeGraphNode>> nodes_; |
| std::vector<const Frame*> include_stack_; |
| }; |
| |
| class Evaluator { |
| friend ScopedFrame; |
| |
| public: |
| Evaluator(); |
| ~Evaluator(); |
| |
| bool Start(); |
| void Finish(); |
| |
| void EvalAssign(const AssignStmt* stmt); |
| void EvalRule(const RuleStmt* stmt); |
| void EvalCommand(const CommandStmt* stmt); |
| void EvalIf(const IfStmt* stmt); |
| void EvalInclude(const IncludeStmt* stmt); |
| void EvalExport(const ExportStmt* stmt); |
| |
| Var* LookupVarForEval(Symbol name); |
| Var* LookupVar(Symbol name); |
| // For target specific variables. |
| Var* LookupVarInCurrentScope(Symbol name); |
| void VarEvalComplete(Symbol name); |
| |
| // Equivalent to LookupVar, but doesn't mark as used. |
| Var* PeekVar(Symbol name); |
| |
| string EvalVar(Symbol name); |
| |
| const Loc& loc() const { return loc_; } |
| void set_loc(const Loc& loc) { loc_ = loc; } |
| |
| const vector<const Rule*>& rules() const { return rules_; } |
| const unordered_map<Symbol, Vars*>& rule_vars() const { return rule_vars_; } |
| const unordered_map<Symbol, bool>& exports() const { return exports_; } |
| |
| void PrintIncludeStack(); |
| void Error(const string& msg); |
| |
| void in_bootstrap(); |
| void in_command_line(); |
| void in_toplevel_makefile(); |
| |
| void set_current_scope(Vars* v) { current_scope_ = v; } |
| |
| bool avoid_io() const { return avoid_io_; } |
| void set_avoid_io(bool a) { avoid_io_ = a; } |
| |
| const vector<string>& delayed_output_commands() const { |
| return delayed_output_commands_; |
| } |
| void add_delayed_output_command(const string& c) { |
| delayed_output_commands_.push_back(c); |
| } |
| void clear_delayed_output_commands() { delayed_output_commands_.clear(); } |
| |
| static const SymbolSet& used_undefined_vars() { return used_undefined_vars_; } |
| |
| int eval_depth() const { return eval_depth_; } |
| void IncrementEvalDepth() { eval_depth_++; } |
| void DecrementEvalDepth() { eval_depth_--; } |
| |
| ScopedFrame Enter(FrameType frame_type, const string& name, Loc loc); |
| Frame* CurrentFrame() const { |
| return stack_.empty() ? nullptr : stack_.back(); |
| }; |
| |
| string GetShell(); |
| string GetShellFlag(); |
| string GetShellAndFlag(); |
| |
| // Parse the current value of .KATI_ALLOW_RULES |
| RulesAllowed GetAllowRules(); |
| |
| void CheckStack() { |
| void* addr = __builtin_frame_address(0); |
| if (__builtin_expect(addr < lowest_stack_ && addr >= stack_addr_, 0)) { |
| lowest_stack_ = addr; |
| lowest_loc_ = loc_; |
| } |
| } |
| |
| void DumpStackStats() const; |
| void DumpIncludeJSON(const string& filename) const; |
| |
| bool ExportDeprecated() const { return export_message_ && !export_error_; }; |
| bool ExportObsolete() const { return export_error_; }; |
| void SetExportDeprecated(StringPiece msg) { |
| export_message_.reset(new string(msg.as_string())); |
| } |
| void SetExportObsolete(StringPiece msg) { |
| export_message_.reset(new string(msg.as_string())); |
| export_error_ = true; |
| } |
| |
| void ProfileMakefile(StringPiece mk) { |
| profiled_files_.emplace_back(mk.as_string()); |
| } |
| |
| private: |
| Var* EvalRHS(Symbol lhs, |
| Value* rhs, |
| StringPiece orig_rhs, |
| AssignOp op, |
| bool is_override, |
| bool* needs_assign); |
| void DoInclude(const string& fname); |
| |
| void TraceVariableLookup(const char* operation, Symbol name, Var* var); |
| Var* LookupVarGlobal(Symbol name); |
| |
| // Equivalent to LookupVarInCurrentScope, but doesn't mark as used. |
| Var* PeekVarInCurrentScope(Symbol name); |
| |
| void MarkVarsReadonly(Value* var_list); |
| |
| void EvalRuleSpecificAssign(const vector<Symbol>& targets, |
| const RuleStmt* stmt, |
| const StringPiece& lhs_string, |
| size_t separator_pos); |
| |
| unordered_map<Symbol, Vars*> rule_vars_; |
| vector<const Rule*> rules_; |
| unordered_map<Symbol, bool> exports_; |
| std::set<Symbol> symbols_for_eval_; |
| |
| Rule* last_rule_; |
| Vars* current_scope_; |
| |
| Loc loc_; |
| bool is_bootstrap_; |
| bool is_commandline_; |
| |
| bool trace_; |
| std::vector<Frame*> stack_; |
| FILE* assignment_tracefile_; |
| long int assignment_count_; |
| |
| std::vector<Loc> include_stack_; |
| |
| bool avoid_io_; |
| // This value tracks the nest level of make expressions. For |
| // example, $(YYY) in $(XXX $(YYY)) is evaluated with depth==2. |
| // This will be used to disallow $(shell) in other make constructs. |
| int eval_depth_; |
| // Commands which should run at ninja-time (i.e., info, warning, and |
| // error). |
| vector<string> delayed_output_commands_; |
| |
| Symbol posix_sym_; |
| bool is_posix_; |
| |
| void* stack_addr_; |
| size_t stack_size_; |
| void* lowest_stack_; |
| Loc lowest_loc_; |
| |
| unique_ptr<string> export_message_; |
| bool export_error_; |
| |
| vector<string> profiled_files_; |
| |
| static SymbolSet used_undefined_vars_; |
| }; |
| |
| #endif // EVAL_H_ |