All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
vm.cc
Go to the documentation of this file.
1 #include <iostream>
2 #include <cassert>
3 
4 #include "vm.h"
5 #include "common.h"
6 #include "compile.h"
7 
9  ip = 0;
10  SetChunk(chunk);
11  return Run();
12 }
13 
15  ip = 0;
16  Chunk chunk;
17  if (!uscript::Compiler::Compile(source, &chunk)) {
19  }
20 
21  SetChunk(&chunk);
22 
23  return Run();
24 }
25 
26 
28  ip(0)
29  {}
30 
31 void uscript::VM::SetChunk(const Chunk *_chunk) {
32  chunk = _chunk;
33  ip = 0;
34 }
35 
37  stack.clear();
38 }
39 
41  return chunk->code[ip++];
42 }
43 
45  return chunk->constants[ReadInstruction()];
46 }
47 
49  if (a.val != b.val) return false;
50 
51  switch (a.val) {
52  case uscript::VAL_BOOL: return AS_BOOL(a) == AS_BOOL(b);
53  case uscript::VAL_NIL: return true;
54  case uscript::VAL_NUMBER: return AS_NUMBER(a) == AS_NUMBER(b);
55  case uscript::VAL_INTEGER: return AS_INTEGER(a) == AS_INTEGER(b);
57  return AS_CSTRING(a) == AS_CSTRING(b);
58  }
59  default:
60  return false;
61  }
62 
63 }
64 
66 #define BINARY_OP(op) \
67  do { \
68  if (IS_NUMBER(Peek(0)) && IS_NUMBER(Peek(1))) { \
69  double b = AS_NUMBER(Pop()); \
70  double a = AS_NUMBER(Pop()); \
71  Push(NUMBER_VAL(a op b)); \
72  } \
73  else if (IS_INTEGER(Peek(0)) && IS_INTEGER(Peek(1))) { \
74  int b = AS_INTEGER(Pop()); \
75  int a = AS_INTEGER(Pop()); \
76  Push(INTEGER_VAL(a op b)); \
77  } \
78  else { \
79  RuntimeError("Operands must be both integers or both numbers."); \
80  return uscript::INTERPRET_RUNTIME_ERROR; \
81  } \
82  } while (false)
83 
84 #define COMP_OP(op) \
85  do { \
86  if (IS_NUMBER(Peek(0)) && IS_NUMBER(Peek(1))) { \
87  double b = AS_NUMBER(Pop()); \
88  double a = AS_NUMBER(Pop()); \
89  Push(BOOL_VAL(a op b)); \
90  } \
91  else if (IS_INTEGER(Peek(0)) && IS_INTEGER(Peek(1))) { \
92  int b = AS_INTEGER(Pop()); \
93  int a = AS_INTEGER(Pop()); \
94  Push(BOOL_VAL(a op b)); \
95  } \
96  else { \
97  RuntimeError("Operands must be both integers or both numbers."); \
98  return uscript::INTERPRET_RUNTIME_ERROR; \
99  } \
100  } while (false)
101 
102  while (1) {
103 
104 #define READ_STRING() AS_CSTRING(ReadConstant())
105 #define READ_SHORT() (ip += 2, (uint16_t)((chunk->code[ip-2] << 8) | chunk->code[ip-1]))
106 
107 #ifdef DEBUG_TRACE_EXECUTION
108  std::cout << " ";
109  for (const uscript::Value &val: stack) {
110  std::cout << "[ ";
111  val.Print();
112  std::cout << " ]";
113  }
114  std::cout << std::endl;
115  chunk->DisassembleInstruction(ip);
116 #endif
117  uint8_t instruction = ReadInstruction();
118  switch (instruction) {
120  Value instance = Pop();
121  const char *name = READ_STRING();
122  Value result;
123  if (!AccessValue(instance, name, &result)) {
125  }
126  Push(result);
127  break;
128  }
129  case uscript::OP_INDEX: {
130  Value index = Pop();
131  if (!IS_INTEGER(index)) {
132  RuntimeError("Cannot index with non-integer.");
134  }
135  int ind = AS_INTEGER(index);
136  Value callee = Pop();
137  if (!IndexValue(callee, ind)) {
139  }
140  break;
141  }
142  case uscript::OP_CALL: {
143  int argCount = ReadInstruction();
144  if (!CallValue(Peek(argCount), argCount)) {
146  }
147  break;
148  }
149  case uscript::OP_LOOP: {
150  uint16_t offset = READ_SHORT();
151  ip -= offset;
152  break;
153  }
154  case uscript::OP_JUMP: {
155  uint16_t offset = READ_SHORT();
156  ip += offset;
157  break;
158  }
160  uint16_t offset = READ_SHORT();
161  if (!Peek(0)) ip += offset;
162  break;
163  }
164  case uscript::OP_RETURN: {
165  if (ret) *ret = Pop();
166  return uscript::INTERPRET_OK;
167  }
168  case uscript::OP_PRINT: {
169  Pop().Print();
170  std::cout << std::endl;
171  break;
172  }
173  case uscript::OP_LENGTH: {
174  Value val = Pop();
175  if (IS_TINSTANCE(val)) {
176  ObjTInstance inst = AS_TINSTANCE(val);
177  Value length = INTEGER_VAL(inst.data.len);
178  Push(length);
179  break;
180  }
181  else {
182  RuntimeError("Cannot access length of non-tinstance.");
184  }
185  }
186  case uscript::OP_FIELDS: {
187  Value val = Pop();
188  if (IS_TINSTANCE(val)) {
189  ObjTInstance inst = AS_TINSTANCE(val);
190  if (inst.data.info) {
191  TClassInfo *info = inst.data.info;
192  for (auto const &field: info->fields) {
193  std::cout << field.first << std::endl;
194  }
195  }
196 
197  int length = inst.data.len;
198  if (length >= 0) {
199  std::cout << "Indexable with length: " << length << std::endl;
200  }
201  break;
202  }
203  else {
204  RuntimeError("Cannot access fields of non-tinstance.");
206  }
207  }
208  case uscript::OP_ADD: BINARY_OP(+); break;
209  case uscript::OP_SUBTRACT: BINARY_OP(-); break;
210  case uscript::OP_MULTIPLY: BINARY_OP(*); break;
211  case uscript::OP_DIVIDE: BINARY_OP(/); break;
212  case uscript::OP_CONSTANT: {
213  Value constant = ReadConstant();
214  Push(constant);
215  break;
216  }
217  case uscript::OP_NOT: Push(BOOL_VAL(!Pop())); break;
218  case uscript::OP_NIL: Push(NIL_VAL); break;
219  case uscript::OP_TRUE: Push(BOOL_VAL(true)); break;
220  case uscript::OP_FALSE: Push(BOOL_VAL(false)); break;
221  case uscript::OP_POP: Pop(); break;
222  case uscript::OP_GET_LOCAL: {
223  uint8_t slot = ReadInstruction();
224  Push(stack[slot]);
225  break;
226  }
227  case uscript::OP_SET_LOCAL: {
228  uint8_t slot = ReadInstruction();
229  stack[slot] = Peek();
230  break;
231  }
232  case uscript::OP_GET_GLOBAL: {
233  const char *name = READ_STRING();
234  if (globals.count(name)) {
235  Push(globals.at(name));
236  }
237  else {
238  RuntimeError("Undefined variable '%s'", name);
240  }
241  break;
242  }
243  case uscript::OP_SET_GLOBAL: {
244  const char *name = READ_STRING();
245  if (!globals.count(name)) {
246  RuntimeError("Undefined variable '%s'", name);
248  }
249  globals[name] = Peek();
250  break;
251  }
253  globals[READ_STRING()] = Pop();
254  break;
255  }
256  case uscript::OP_EQUAL: {
257  uscript::Value b = Pop();
258  uscript::Value a = Pop();
259  Push(BOOL_VAL(valuesEqual(a, b)));
260  break;
261  }
262  case uscript::OP_GREATER: COMP_OP(>); break;
263  case uscript::OP_LESS: COMP_OP(<); break;
264  case uscript::OP_NEGATE: {
265  if (IS_NUMBER(Peek())) {
266  Push(NUMBER_VAL(-AS_NUMBER(Pop())));
267  }
268  else if (IS_INTEGER(Peek())) {
269  Push(INTEGER_VAL(-AS_INTEGER(Pop())));
270  }
271  else {
272  RuntimeError("Operand must be a number.");
274  }
275  break;
276  }
277  }
278  }
279 #undef READ_STRING
280 #undef READ_SHORT
281 #undef BINARY_OP
282 #undef COMP_OP
283 }
284 
285 bool uscript::VM::IndexValue(Value callee, int index) {
286  if (IS_TINSTANCE(callee)) {
287  uscript::ObjTInstance inst = AS_TINSTANCE(callee);
288  if (index >= 0 && index < inst.data.len) {
289  // indexed value itself has no length and is not a vector
290  TData field_data = inst.data;
291  field_data.len = -1;
292  Value ret = GetTValue(inst.loc + index * inst.data.Size(), field_data);
293  Push(ret);
294  return true;
295  }
296  else {
297  RuntimeError("Cannot index with value (%i) into instance of size (%i)", index, inst.data.len);
298  return false;
299  }
300  }
301  return false;
302 }
303 
304 bool uscript::VM::CallValue(Value callee, int argCount) {
305  RuntimeError("Functions are not implemented.");
306  return false;
307 }
308 
310  // case where this is a vector
311  if (data.info != NULL && data.info->is_vec) {
312  // go to the location of the start of the vector
313  // FIXME: this is probably implementation defined -- needs to be fixed
314 
315  // get the contents of the vector
316  uint8_t **vec = (uint8_t**)loc;
317  uint8_t *start = vec[0];
318  uint8_t *end = vec[1];
319 
320  // the data is now what the vector was pointing to
321  data = data.info->vec_data;
322 
323  // update the size
324  data.len = (end - start) / data.Size();
325 
326  // update the loc
327  loc = start;
328  }
329  // all non-zero size Tdata's are instances
330  if (data.len >= 0 || data.type == uscript::FIELD_TINSTANCE) {
331  ObjTInstance inst;
332  inst.loc = loc;
333  inst.data = data;
334  return TINSTANCE_VAL(inst);
335  }
336  Value ret;
337  switch(data.type) {
338  case uscript::FIELD_BOOL:
339  ret = BOOL_VAL((bool)*loc);
340  break;
341  case uscript::FIELD_INT:
342  ret = INTEGER_VAL(*((int*)loc));
343  break;
344  case uscript::FIELD_ENUM:
345  ret = INTEGER_VAL((int)*((uint32_t*)loc));
346  break;
348  ret = INTEGER_VAL((int)*((unsigned*)loc));
349  break;
351  ret = NUMBER_VAL((double)*((float*)loc));
352  break;
354  ret = NUMBER_VAL(*((double*)loc));
355  break;
357  break; // unreachable
358  }
359  return ret;
360 }
361 
362 bool uscript::VM::AccessValue(Value instance, const char *name, Value *result) {
363  if (IS_TINSTANCE(instance)) {
364  bool success = GetTField(AS_TINSTANCE(instance), name, result);
365  if (!success) {
366  uscript::ObjTInstance &inst = AS_TINSTANCE(instance);
367  uscript::TClassInfo *classinfo = inst.data.info;
368  RuntimeError("Could not find value %s.", name);
369  //RuntimeError("Could not find value %s in class %s.", name, classinfo->name.c_str());
370  }
371  return success;
372  }
373  RuntimeError("Cannot access on non-TInstance.");
374  return false;
375 
376 }
377 
379  if (!instance.loc) return false; // shouldn't happen
380  if (!instance.data.info) return false; // possible for list of built-in type (e.g. vector<int> or double[4])
381 
382  // if this is a list, then you have to index it before accessing a value
383  if (instance.data.len >= 0) return false;
384 
385  uscript::TClassInfo *classinfo = instance.data.info;
386  if (classinfo->fields.count(name)) {
387  uscript::TField field = classinfo->fields.at(name);
388  *ret = GetTValue(instance.loc + field.offset, field.data);
389  return true;
390  }
391 
392  return false;
393 
394 }
395 
396 void uscript::VM::DoAddGlobal(const char *classname, const char *name, uint8_t *loc) {
398  ObjTInstance inst;
399  inst.loc = loc;
400  inst.data.info = classinfo;
401  inst.data.info = classinfo;
402  inst.data.len = -1;
404  // intern the name
405  name = uscript::Compiler::Intern(name);
406  globals[name] = TINSTANCE_VAL(inst);
407 }
408 
409 void uscript::VM::RuntimeError(const char *format, ...) {
410  va_list args;
411  va_start(args, format);
412  vfprintf(stderr, format, args);
413  va_end(args);
414  fprintf(stderr, "\nIn source: %s\n", chunk->source.c_str());
415 
416  Reset();
417 }
418 
419 template<>
420 void uscript::VM::AddGlobal<int>(const char *name, const int *obj) {
422  globals[name] = INTEGER_VAL(*obj);
423 }
424 
425 template<>
426 void uscript::VM::AddGlobal<unsigned>(const char *name, const unsigned *obj) {
428  globals[name] = INTEGER_VAL((int)*obj);
429 }
430 
431 template<>
432 void uscript::VM::AddGlobal<float>(const char *name, const float *obj) {
434  globals[name] = NUMBER_VAL(*obj);
435 }
436 
437 template<>
438 void uscript::VM::AddGlobal<double>(const char *name, const double *obj) {
440  globals[name] = NUMBER_VAL(*obj);
441 }
442 
443 template<>
444 void uscript::VM::AddGlobal<bool>(const char *name, const bool *obj) {
446  globals[name] = BOOL_VAL(*obj);
447 }
448 
449 void uscript::VM::AddGlobal(const char *name) {
450  name = uscript::Compiler::Intern(name);
451  globals[name] = NIL_VAL;
452 }
453 
#define IS_INTEGER(value)
Definition: value.h:62
void SetChunk(const Chunk *_chunk)
Definition: vm.cc:31
BEGIN_PROLOG TPC Trig offset(g4 rise time) ProjectToHeight
Definition: CORSIKAGen.fcl:7
void RuntimeError(const char *format,...)
Definition: vm.cc:409
TData data
Definition: tclass.h:33
#define AS_TINSTANCE(value)
Definition: value.h:57
#define BINARY_OP(op)
uint8_t * loc
Definition: value.h:25
static std::string format(PyObject *obj, unsigned int pos, unsigned int indent, unsigned int maxlen, unsigned int depth)
Definition: fclmodule.cxx:374
do source
#define BOOL_VAL(value)
Definition: value.h:45
VM()
Definition: vm.cc:27
#define IS_TINSTANCE(value)
Definition: value.h:64
const std::string instance
#define AS_BOOL(value)
Definition: value.h:52
std::map< const char *, TField > fields
Definition: tclass.h:37
#define READ_STRING()
process_name gaushit a
void Reset()
Definition: vm.cc:36
bool AccessValue(Value instance, const char *name, Value *result)
Definition: vm.cc:362
void DoAddGlobal(const char *classname, const char *name, uint8_t *data)
Definition: vm.cc:396
#define AS_NUMBER(value)
Definition: value.h:53
#define IS_NUMBER(value)
Definition: value.h:61
#define COMP_OP(op)
InterpretResult Interpret(const char *source)
Definition: vm.cc:14
bool GetTField(ObjTInstance instance, const char *name, Value *ret)
Definition: vm.cc:378
#define AS_CSTRING(value)
Definition: value.h:56
static bool valuesEqual(uscript::Value a, uscript::Value b)
Definition: vm.cc:48
#define NIL_VAL
Definition: value.h:46
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
then echo echo For and will not be changed by echo further linking echo echo B echo The symbol is in the uninitialized data multiple common symbols may appear with the echo same name If the symbol is defined the common echo symbols are treated as undefined references For more echo details on common see the discussion of warn common echo in *Note Linker see the discussion of warn common echo in *Note Linker such as a global int variable echo as opposed to a large global array echo echo I echo The symbol is an indirect reference to another symbol This echo is a GNU extension to the a out object file format which is echo rarely used echo echo N echo The symbol is a debugging symbol echo echo R echo The symbol is in a read only data section echo echo S echo The symbol is in an uninitialized data section for small echo objects echo echo T echo The symbol is in the the normal defined echo symbol is used with no error When a weak undefined symbol echo is linked and the symbol is not the value of the echo weak symbol becomes zero with no error echo echo W echo The symbol is a weak symbol that has not been specifically echo tagged as a weak object symbol When a weak defined symbol echo is linked with a normal defined the normal defined echo symbol is used with no error When a weak undefined symbol echo is linked and the symbol is not the value of the echo weak symbol becomes zero with no error echo echo echo The symbol is a stabs symbol in an a out object file In echo this the next values printed are the stabs other field
ValueType val
Definition: value.h:30
int Size() const
Definition: tclass.cc:153
InterpretResult Run(Value *ret=NULL)
Definition: vm.cc:65
TClassInfo * info
Definition: tclass.h:24
#define NUMBER_VAL(value)
Definition: value.h:47
#define INTEGER_VAL(value)
Definition: value.h:48
InterpretResult
Definition: vm.h:14
#define AS_INTEGER(value)
Definition: value.h:54
static const char * Intern(const std::string &str)
Definition: compile.h:138
TFieldType type
Definition: tclass.h:25
void AddGlobal(const char *name, const TObj *object)
Definition: vm.h:51
static TClassInfo * GetClassInfo(const char *classname)
Definition: compile.h:142
uint8_t ReadInstruction()
Definition: vm.cc:40
then echo fcl name
unsigned ip
Definition: vm.h:22
Value GetTValue(uint8_t *loc, TData data)
Definition: vm.cc:309
static bool Compile(const char *source, Chunk *chunk)
Definition: compile.h:140
bool CallValue(Value callee, int argCount)
Definition: vm.cc:304
Value ReadConstant()
Definition: vm.cc:44
#define TINSTANCE_VAL(value)
Definition: value.h:50
#define READ_SHORT()
BEGIN_PROLOG could also be cout
bool IndexValue(Value callee, int index)
Definition: vm.cc:285