Gorgon Game Engine
Scope.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string>
4 #include <vector>
5 #include <memory>
6 
7 #include "../String.h"
8 #include "../Scripting.h"
9 #include "Instruction.h"
10 #include "Input.h"
11 #include "Compilers.h"
12 #include "Runtime.h"
13 
14 namespace Gorgon { namespace Scripting {
15 
18  class Line {
19  public:
20  Instruction instruction;
21 
22  long physical;
23  };
25 
26  class CompilerBase;
27 
30  class SourceMarker {
31  friend class ScopeInstance;
32  public:
34  SourceMarker(const SourceMarker &)=default;
35 
36  SourceMarker &operator=(const SourceMarker &)=default;
37 
38  bool operator <(const SourceMarker &other) {
39  return (source == other.source ? line<other.line : source<other.source);
40  }
41 
42  bool IsValid() const { return source!=0; }
43 
44  uintptr_t GetSource() const { return source; }
45 
46  unsigned long GetLine() const { return line; }
47 
48  private:
49  SourceMarker(unsigned long line, uintptr_t source) : line(line), source(source) {}
50 
51  unsigned long line = 0;
52  uintptr_t source = 0;
53  };
54 
55  class ScopeInstance;
56 
62  class Scope {
63  friend class ScopeInstance;
64  public:
66  Scope(InputProvider &provider, const std::string &name, bool terminal=false);
67 
71  Scope(Scope &parent, const std::string &name, bool terminal=false);
72 
74  const Instruction *ReadInstruction(unsigned long line);
75 
77  long GetPhysicalLine(unsigned long line) {
78  if(ReadInstruction(line)) {
79  return lines[line].physical;
80  }
81  else {
82  return -1;
83  }
84  }
85 
87  bool IsInteractive() const {
88  if(!provider) return false;
89 
90  return provider->IsInteractive();
91  }
92 
94  unsigned ReadyInstructionCount() const {
95  return (unsigned)lines.size();
96  }
97 
99  std::string GetName() const { return name; }
100 
102  void SaveInstruction(Instruction inst, long pline) {
103  lines.push_back({inst, pline});
104  }
105 
107  void SaveInstructions(const std::vector<Instruction> &insts) {
108  long pline=0;
109  for(auto &inst : insts) {
110  lines.push_back({inst, pline});
111  }
112  }
113 
116  bool IsTerminal() const {
117  return terminal;
118  }
119 
120  std::shared_ptr<ScopeInstance> Instantiate();
121 
122  std::shared_ptr<ScopeInstance> Instantiate(ScopeInstance &current);
123 
124  bool HasInstance() const {
125  return instances.GetCount()!=0;
126  }
127 
129  ASSERT(instances.GetCount(), "There are no instances available");
130 
131  return *instances.Last();
132  }
133 
134  bool HasParent() const {
135  return parent!=nullptr;
136  }
137 
138  Scope &GetParent() const {
139  return *parent;
140  }
141 
142  Variable *GetVariable(const std::string &name) {
143  auto var=variables.find(name);
144 
145  if( var !=variables.end() )
146  return &var->second;
147  else
148  return nullptr;
149  }
150 
151  void SetVariable(const std::string &name, const Data &data) {
152  variables[name]={name, data};
153  }
154 
155  bool UnsetVariable(const std::string &name) {
156  auto var=variables.find(name);
157 
158  if( var !=variables.end() ) {
159  variables.erase(var);
160  return true;
161  }
162  else
163  return false;
164  }
165 
168  void Unload() {
169  using std::swap;
170 
171  std::vector<Line> temp;
172  swap(temp, lines);
173 
174  provider->Reset();
175  }
176 
179  void SetName(const std::string &name) {
180  this->name=name;
181  }
182 
183  private:
184  std::string name;
185 
186  int nextid=1;
187 
188  long pline=0;
189 
190  InputProvider *provider = nullptr;
191 
192  Compilers::Base *parser =nullptr;
193 
194  Scope *parent=nullptr;
195 
196  bool terminal;
197 
199 
200  //-unordered map
201  std::map<std::string, Variable, String::CaseInsensitiveLess> variables;
202 
205  std::vector<Line> lines;
206  };
207 
209  class Return {
210  public:
212  const Type *type;
213 
216  bool constant;
217 
219  bool reference;
220  };
221 
223  class ScopeInstance {
224  friend class Scope;
225  friend class VirtualMachine;
226 
227  using variablestoragetype=std::map<std::string, Variable, String::CaseInsensitiveLess>;
228  using symbolstoragetype =std::map<std::string, const StaticMember*, String::CaseInsensitiveLess>;
229  public:
230 
232  scope.instances.Remove(this);
233  }
234 
236  void Jumpto(unsigned long line) {
237  current=line;
238  }
239 
241  unsigned long GetLineNumber() const {
242  return current-1;
243  }
244 
248  return {current, reinterpret_cast<uintptr_t>(this)};
249  }
250 
254  return {current-1, reinterpret_cast<uintptr_t>(this)};
255  }
256 
258  const Instruction *Get() {
259  auto ret=scope.ReadInstruction(current);
260  current++;
261 
262  return ret;
263  }
264 
265  std::string GetName() const {
266  return name;
267  }
268 
269  Variable *GetLocalVariable(const std::string &name) {
270  auto varit=variables.find(name);
271  if( varit !=variables.end() )
272  return &varit->second;
273  else
274  return nullptr;
275  }
276 
277  const std::map<std::string, Variable, String::CaseInsensitiveLess> &GetLocalVariables() {
278  return variables;
279  }
280 
281  Variable *GetVariable(const std::string &name) {
282  auto varit=variables.find(name);
283  if( varit !=variables.end() )
284  return &varit->second;
285 
286  auto var=scope.GetVariable(name);
287  if(var)
288  return var;
289 
290  if(scope.HasParent() && scope.GetParent().HasInstance() && !scope.IsTerminal())
291  var=scope.GetParent().LastInstance().GetVariable(name);
292 
293  return var;
294  }
295 
296  void SetVariable(const std::string &name, const Data &data) {
297  variables[name]={name, data};
298  }
299 
300  bool UnsetVariable(const std::string &name) {
301  auto var=variables.find(name);
302 
303  if( var !=variables.end() ) {
304  variables.erase(var);
305  return true;
306  }
307 
308  auto done=scope.UnsetVariable(name);
309  if(done)
310  return true;
311 
312  if(scope.HasParent() && scope.GetParent().HasInstance() && !scope.IsTerminal())
313  done=scope.GetParent().LastInstance().UnsetVariable(name);
314 
315  return done;
316  }
317 
319  void Compile() {
320  int c=current;
321  while(scope.ReadInstruction(c++)) ;
322  }
323 
325  const Instruction *Peek() {
326  return scope.ReadInstruction(current);
327  }
328 
330  const Instruction *Peek(unsigned long line) {
331  return scope.ReadInstruction(line);
332  }
333 
334  void MoveToEnd() {
335  current=scope.ReadyInstructionCount();
336  }
337 
339  return scope.GetPhysicalLine(current-1);
340  }
341 
343  Scope &GetScope() const { return scope; }
344 
346  void SetReturn(Return returns) { this->returns=returns; }
347 
349  void AddSymbol(const StaticMember &symbol) {
350  if(symbols.count(symbol.GetName())!=0) {
351  ambiguoussymbols.insert(std::make_pair(symbol.GetName(), symbols[symbol.GetName()]->GetQualifiedName()));
352  symbols.erase(symbol.GetName());
353  ambiguoussymbols[symbol.GetName()]+=", "+symbol.GetQualifiedName();
354  }
355  else if(ambiguoussymbols.count(symbol.GetName())!=0) {
356  ambiguoussymbols[symbol.GetName()]+=", "+symbol.GetQualifiedName();
357  }
358  else {
359  symbols.insert(std::make_pair(symbol.GetName(), &symbol));
360  }
361  }
362 
364  Data FindSymbol(const std::string &name, bool reference) {
365  //check local vars first
366  variablestoragetype::iterator it;
367  if( (it=variables.find(name)) != variables.end() ) {
368  Variable &var=it->second;
369  if(reference)
370  return var.GetReference();
371  else
372  return var;
373  }
374 
375  //check statics too
376  auto var=scope.GetVariable(name);
377  if(var)
378  return *var;
379 
380 
381  //check ambiguity
382  if(ambiguoussymbols.count(name)!=0) {
383  throw AmbiguousSymbolException(name, SymbolType::Identifier, "Could be one of: "+ambiguoussymbols[name]);
384  }
385 
386  //check local symbols
387  symbolstoragetype::iterator sym;
388  if( (sym=symbols.find(name)) != symbols.end() ) {
389  return sym->second->Get(); //all static member symbols are reference
390  }
391 
392  //if we have a parent, try that
393  if(scope.HasParent() && scope.GetParent().HasInstance() && !scope.IsTerminal())
394  return scope.GetParent().LastInstance().FindSymbol(name, reference);
395  else
396  return Data::Invalid();
397  }
398 
401 
402  private:
404  std::set<std::string> UsedNamespaces;
405 
407  std::map<std::string, const StaticMember*, String::CaseInsensitiveLess> symbols;
408  std::map<std::string, std::string, String::CaseInsensitiveLess> ambiguoussymbols;
409 
411  ScopeInstance(Scope &scope, ScopeInstance *parent) : scope(scope), parent(parent) {
412  name=scope.GetName()+" #"+String::From(scope.nextid++);
413  }
414 
415  Return returns = Return({nullptr, false, false});
416  int tempbase;
417 
418  //-unordered map
419  std::map<std::string, Variable, String::CaseInsensitiveLess> variables;
420 
421  ScopeInstance *parent = nullptr;
422 
423  std::string name;
424 
425  Scope &scope;
426 
428  unsigned long current = 0;
429  };
430 
431 } }
Gorgon::Scripting::Scope::SetVariable
void SetVariable(const std::string &name, const Data &data)
Definition: Scope.h:151
Gorgon::Scripting::ScopeInstance::GetPhysicalLine
long GetPhysicalLine()
Definition: Scope.h:338
Gorgon::Scripting::InputProvider::Reset
virtual void Reset()=0
Resets the input to the beginning.
Gorgon::swap
void swap(Event< Source_, Args_... > &l, Event< Source_, Args_... > &r)
Swaps two events.
Definition: Event.h:351
Scope.h
Gorgon::Scripting::InputProvider::ReadLine
virtual bool ReadLine(std::string &, bool newline)=0
This method should read a single physical line from the source.
Gorgon::String::From
std::enable_if< decltype(gorgon__enum_tr_loc(T_()))::isupgradedenum, std::string >::type From(const T_ &e)
Definition: Enum.h:303
Gorgon::Scripting::Compilers::Base::Finalize
virtual void Finalize()=0
Finalizes the compilation.
Gorgon::Scripting::ScopeInstance::Peek
const Instruction * Peek(unsigned long line)
Returns the code at the given line without changing current line.
Definition: Scope.h:330
Gorgon::Scripting::Scope::LastInstance
ScopeInstance & LastInstance() const
Definition: Scope.h:128
Gorgon::Scripting::Scope::Unload
void Unload()
Unloads an input source by erasing all current data.
Definition: Scope.h:168
Gorgon::Scripting::Scope::ReadInstruction
const Instruction * ReadInstruction(unsigned long line)
Reads the instruction in the given line.
Definition: Scope.cpp:5
Gorgon::Scripting::ScopeInstance
This is an instantiation of a scope.
Definition: Scope.h:223
Gorgon::Scripting::ScopeInstance::Peek
const Instruction * Peek()
Returns the code at the current line without incrementing it.
Definition: Scope.h:325
Gorgon::Scripting::ScopeInstance::GetMarkerForNext
SourceMarker GetMarkerForNext() const
Returns a unique identifier for the next line in source code.
Definition: Scope.h:247
Gorgon::Scripting::Compilers::Programming
Programming dialect compiler.
Definition: Compilers.h:89
Gorgon::Scripting::ScopeInstance::MoveToEnd
void MoveToEnd()
Definition: Scope.h:334
Gorgon::Scripting::Scope::GetName
std::string GetName() const
Returns the name of this scope.
Definition: Scope.h:99
Gorgon::Scripting::ScopeInstance::SetReturn
void SetReturn(Return returns)
Sets the return type of this scope instance.
Definition: Scope.h:346
Gorgon::Scripting::Scope
A new scope is created automatically when a new input source or a function like construct is created.
Definition: Scope.h:62
Gorgon::Scripting::Scope::ScopeInstance
friend class ScopeInstance
Definition: Scope.h:63
Gorgon::Scripting::ScopeInstance::~ScopeInstance
~ScopeInstance()
Definition: Scope.h:231
Gorgon::Scripting::InputProvider::GetDialect
Dialect GetDialect() const
Returns the current dialect of the input.
Definition: Input.h:25
Gorgon::Scripting::Compilers::Base::Compile
virtual unsigned Compile(const std::string &input, unsigned long pline)=0
Asks the compiler to compile the given input.
Gorgon::Scripting::Scope::HasParent
bool HasParent() const
Definition: Scope.h:134
Gorgon::Scripting::Data
Data describes a piece of data.
Definition: Data.h:22
Gorgon::Scripting::SourceMarker::GetSource
uintptr_t GetSource() const
Definition: Scope.h:44
Gorgon::Scripting::ScopeInstance::SetVariable
void SetVariable(const std::string &name, const Data &data)
Definition: Scope.h:296
Gorgon::Scripting::InputProvider::IsInteractive
virtual bool IsInteractive() const
Returns if this input provider allows interaction.
Definition: Input.h:45
Gorgon::Resource::GID::Line
constexpr Type Line
Definition: GID.h:234
Gorgon::Scripting::Scope::SaveInstruction
void SaveInstruction(Instruction inst, long pline)
Saves an instruction to the scope.
Definition: Scope.h:102
Gorgon::Scripting::Scope::Scope
Scope(InputProvider &provider, const std::string &name, bool terminal=false)
Constructor requires an input provider and a name to define this input source.
Definition: Scope.cpp:62
Gorgon::Scripting::Compilers::Base
The base class for compilers.
Definition: Compilers.h:21
Gorgon::Scripting::Scope::Instantiate
std::shared_ptr< ScopeInstance > Instantiate()
Definition: Scope.cpp:80
Compilers.h
Gorgon::Scripting::SourceMarker::SourceMarker
SourceMarker()
Definition: Scope.h:33
Gorgon::Scripting::Scope::IsInteractive
bool IsInteractive() const
Returns if this scope is interactive (i.e. code is entered by user)
Definition: Scope.h:87
Gorgon::Scripting::Scope::GetVariable
Variable * GetVariable(const std::string &name)
Definition: Scope.h:142
Gorgon::Scripting::Return::reference
bool reference
Marks this return as a reference.
Definition: Scope.h:219
Gorgon::Utils::ASSERT_FALSE
void ASSERT_FALSE(const std::string &message, int skip=1, int depth=4)
Definition: Assert.h:192
Gorgon::Scripting::ScopeInstance::GetMarkerForCurrent
SourceMarker GetMarkerForCurrent() const
Returns a unique identifier for the next line in source code.
Definition: Scope.h:253
Gorgon::Scripting::SourceMarker
This class uniquely represents a source code line.
Definition: Scope.h:30
Gorgon::Scripting::Scope::SetName
void SetName(const std::string &name)
In rare cases where scope name cannot be determined at the construction, this function can be used to...
Definition: Scope.h:179
Gorgon::Scripting::ScopeInstance::Scope
friend class Scope
Definition: Scope.h:224
Gorgon::Scripting::Type
This class stores information about types.
Definition: Reflection.h:1165
Gorgon
Root namespace for Gorgon Game Engine.
Definition: Any.h:19
Gorgon::Scripting::Data::GetReference
Data GetReference()
Definition: Data.cpp:148
Gorgon::Scripting::ScopeInstance::Jumpto
void Jumpto(unsigned long line)
Jumps to the given line, line numbers start at zero.
Definition: Scope.h:236
Gorgon::Scripting::ScopeInstance::ReturnValue
Data ReturnValue
Current return value of the scope. This value can be modified before actually returning from the scop...
Definition: Scope.h:400
Gorgon::Scripting::ScopeInstance::GetLineNumber
unsigned long GetLineNumber() const
Returns the current executing logical line number.
Definition: Scope.h:241
Gorgon::Scripting::StaticMember
This is the base class for all static members.
Definition: Reflection.h:365
ASSERT
#define ASSERT(expression, message,...)
Replaces regular assert to allow messages and backtrace.
Definition: Assert.h:161
Gorgon::Scripting::Data::Invalid
static Data Invalid()
Constructs an invalid data object.
Definition: Data.h:27
Gorgon::Scripting::InputProvider::SetDialect
void SetDialect(Dialect dialect)
Changes the current dialect of the input.
Definition: Input.h:30
Gorgon::Containers::Collection
Collection is a container for reference typed objects.
Definition: Collection.h:21
Gorgon::Scripting::InputProvider
Definition: Input.h:13
Gorgon::Scripting::InputProvider::Console
@ Console
Definition: Input.h:16
Gorgon::Scripting::Scope::ReadyInstructionCount
unsigned ReadyInstructionCount() const
Current number of instructions that are prepared.
Definition: Scope.h:94
Gorgon::Scripting::InputProvider::Programming
@ Programming
Definition: Input.h:17
Gorgon::Scripting::Return::type
const Type * type
Return type, nullptr means anything.
Definition: Scope.h:212
Gorgon::Scripting::ScopeInstance::AddSymbol
void AddSymbol(const StaticMember &symbol)
Adds a symbol to the symbol table of this scope.
Definition: Scope.h:349
Gorgon::Scripting::ScopeInstance::FindSymbol
Data FindSymbol(const std::string &name, bool reference)
Tries to find the given symbol (including variables)
Definition: Scope.h:364
Gorgon::Scripting::Scope::IsTerminal
bool IsTerminal() const
Returns if this scope is terminal scope.
Definition: Scope.h:116
Gorgon::Scripting::ScopeInstance::Compile
void Compile()
Forces the compilation of entire scope.
Definition: Scope.h:319
Gorgon::Scripting::Compilers::Intermediate
Intermediate language complier.
Definition: Compilers.h:59
Gorgon::Scripting::Scope::SaveInstructions
void SaveInstructions(const std::vector< Instruction > &insts)
Saves a list of instructions to this scope.
Definition: Scope.h:107
Input.h
Gorgon::Scripting::Scope::UnsetVariable
bool UnsetVariable(const std::string &name)
Definition: Scope.h:155
Gorgon::Scripting::Scope::HasInstance
bool HasInstance() const
Definition: Scope.h:124
Gorgon::Scripting::ScopeInstance::GetVariable
Variable * GetVariable(const std::string &name)
Definition: Scope.h:281
Gorgon::Scripting::ScopeInstance::Get
const Instruction * Get()
Returns the code at the current line and increments the current line.
Definition: Scope.h:258
Gorgon::Scripting::SourceMarker::operator<
bool operator<(const SourceMarker &other)
Definition: Scope.h:38
Gorgon::Scripting::SourceMarker::GetLine
unsigned long GetLine() const
Definition: Scope.h:46
Runtime.h
This file contains classes that stores runtime and end programmer defined objects.
Gorgon::Scripting::ScopeInstance::GetScope
Scope & GetScope() const
Returns the scope of this scope instance.
Definition: Scope.h:343
Gorgon::Scripting::Compilers::Base::List
std::vector< Instruction > List
The instructions that are compiled.
Definition: Compilers.h:51
Gorgon::Scripting::ScopeInstance::GetName
std::string GetName() const
Definition: Scope.h:265
Gorgon::Scripting::ScopeInstance::GetLocalVariables
const std::map< std::string, Variable, String::CaseInsensitiveLess > & GetLocalVariables()
Definition: Scope.h:277
Gorgon::Scripting::SourceMarker::operator=
SourceMarker & operator=(const SourceMarker &)=default
Gorgon::Scripting::Member::GetQualifiedName
std::string GetQualifiedName() const
Returns the namespace qualified name of this member.
Definition: Reflection.h:338
Gorgon::Scripting::SourceMarker::SourceMarker
SourceMarker(const SourceMarker &)=default
Gorgon::Scripting::InputProvider::Intermediate
@ Intermediate
Definition: Input.h:18
Gorgon::Scripting::SourceMarker::IsValid
bool IsValid() const
Definition: Scope.h:42
Instruction.h
Gorgon::Scripting::Return
Represents what could be returned from a scope instance.
Definition: Scope.h:209
Gorgon::Scripting::Return::constant
bool constant
Marked scope can return a constant.
Definition: Scope.h:216
Gorgon::Scripting::Instruction
A single instruction.
Definition: Instruction.h:150
Gorgon::Scripting::ScopeInstance::UnsetVariable
bool UnsetVariable(const std::string &name)
Definition: Scope.h:300
Gorgon::Scripting::ScopeInstance::GetLocalVariable
Variable * GetLocalVariable(const std::string &name)
Definition: Scope.h:269
Gorgon::Scripting::VirtualMachine
This class defines a virtual environment for scripts to run.
Definition: VirtualMachine.h:45
Gorgon::Scripting::Scope::GetParent
Scope & GetParent() const
Definition: Scope.h:138
Gorgon::Scripting::Scope::GetPhysicalLine
long GetPhysicalLine(unsigned long line)
Current physical line.
Definition: Scope.h:77
Gorgon::Scripting::Variable
This class represents a variable. It contains the data and the name of the variable.
Definition: Runtime.h:146
Gorgon::Scripting::Member::GetName
std::string GetName() const
Returns the name of this member.
Definition: Reflection.h:325