1 module orelang.Engine;
2 
3 /**
4  * Premitive Interfaces and Value Classes
5  */
6 import orelang.expression.ImmediateValue, orelang.expression.CallOperator,
7   orelang.expression.IExpression, orelang.expression.ClassType,
8   orelang.operator.IOperator, orelang.Closure, orelang.Value;
9 
10 /**
11  * variables
12  */
13 import orelang.operator.DatetimeOperators, orelang.operator.IsHashMapOperator,
14   orelang.operator.TranspileOperator, orelang.operator.DefmacroOperator,
15   orelang.operator.HashMapOperators, orelang.operator
16   .DigestOperators, orelang.operator.DynamicOperator,
17   orelang.operator.ForeachOperator, orelang.operator.RandomOperators,
18   orelang.operator.StringOperators, orelang.operator.ArrayOperators,
19   orelang.operator.AssertOperator, orelang.operator.ClassOperators,
20   orelang.operator.DebugOperators, orelang.operator.DeffunOperator,
21   orelang.operator.DefineOperator, orelang.operator.DefvarOperator,
22   orelang.operator.FilterOperator, orelang.operator.GetfunOperator,
23   orelang.operator.IsListOperator, orelang.operator.IsNullOperator,
24   orelang.operator.LambdaOperator, orelang.operator.LengthOperator,
25   orelang.operator.RemoveOperator, orelang.operator.SetIdxOperator,
26   orelang.operator.StdioOperators, orelang.operator.SystemOperator,
27   orelang.operator.AliasOperator, orelang.operator.ConvOperators,
28   orelang.operator.CurlOperators, orelang.operator.EqualOperator,
29   orelang.operator.FileOperators, orelang.operator.LogicOperator,
30   orelang.operator.PathOperators, orelang.operator.PrintOperator,
31   orelang.operator.TimesOperator, orelang.operator.UntilOperator,
32   orelang.operator.UUIDOperators, orelang.operator.WhileOperator,
33   orelang.operator.AsIVOperator, orelang.operator.CondOperator,
34   orelang.operator.ConsOperator, orelang.operator.EvalOperator,
35   orelang.operator.FoldOperator, orelang.operator.LoadOperator,
36   orelang.operator.SortOperator, orelang.operator.StepOperator,
37   orelang.operator.TypeOperator, orelang.operator.UriOperators,
38   orelang.operator.WhenOperator, orelang.operator.AddOperator,
39   orelang.operator.CarOperator, orelang.operator.CdrOperator,
40   orelang.operator.DivOperator,
41   orelang.operator.GetOperator, orelang.operator.LetOperator,
42   orelang.operator.MapOperator, orelang.operator.MulOperator,
43   orelang.operator.ModOperator, orelang.operator.NopOperator,
44   orelang.operator.SetOperator, orelang.operator.SeqOperator,
45   orelang.operator.SubOperator, orelang.operator.IfOperator;
46 import orelang.operator.RegexClass, orelang.operator.FileClass;
47 
48 version (WithFFI) {
49 import orelang.operator.DllOperator;
50 }
51 
52 import std.exception, std.format;
53 
54 /**
55  * Lazed Associative Array
56  *
57  * For instance;
58  *   assocArray["key"] = new ValueType
59  *  The above code create a new instance of ValueType with some consts(memory amount and time).
60  * However it likely to be a bobottleneck if the value isn't needed.
61  * Then this class provides lazed associative array, this class willn't create an instance until the value become needed.
62  * In other words, this is sort of lazy evaluation for performance.
63  */
64 class LazedAssocArray(T) {
65   /**
66    * Flags, indicates whether the instance of the key is already created  
67    */
68   bool[string] called;
69   /**
70    * This variable holds the instance as a value of hashmap.
71    */
72   T[string] storage;
73   /**
74    * This variable holds the constructor calling delegate to make the instance which will be called when the isntance become needed.
75    */
76   T delegate()[string] constructors;
77   bool[string] alwaysNew;
78 
79   alias storage this;
80 
81   /**
82    * This function works like:
83    *  // laa is an instance of LazedAssocArray
84    *  laa["key"] = new T;
85    * with following way:
86    *  laa.insert!("key", "new T");
87    *
88    * This function uses string-mixin for handling "new T", becase D can't allow make an alias of the expr liek `new T`
89    */
90   void insert(string key, string value, bool always = false)() {
91     constructors[key] = mixin("delegate T () { return " ~ value ~ ";}");
92     called[key] = false;
93 
94     if (always) {
95       alwaysNew[key] = true;
96     }
97   }
98 
99   void insert(string key, T delegate() value, bool always = false)() {
100     constructors[key] = value;
101     called[key] = false;
102 
103     if (always) {
104       alwaysNew[key] = true;
105     }
106   }
107 
108   void insert(string key, T function() value, bool always = false)() {
109     constructors[key] = () => value();
110     called[key] = false;
111 
112     if (always) {
113       alwaysNew[key] = true;
114     }
115   }
116 
117   void insert(string key, T delegate() value, bool always = false) {
118     constructors[key] = value;
119     called[key] = false;
120 
121     if (always) {
122       alwaysNew[key] = true;
123     }
124   }
125 
126   void insert(string key, T function() value, bool always = false) {
127     constructors[key] = () => value();
128     called[key] = false;
129 
130     if (always) {
131       alwaysNew[key] = true;
132     }
133   }
134 
135   /**
136    * Set the value with the key.
137    * This function works like:
138    *  laa["key"] = value;
139    * with
140    * laa.set("key", value) 
141    */
142   void set(string key, T value) {
143     storage[key] = value;
144     called[key] = true;
145   }
146 
147   /**
148    * Make an alias of the key
149    */
150   void link(string alternative, string key) {
151     const flag = called[key];
152     called[alternative] = flag;
153 
154     if (flag) {
155       storage[alternative] = storage[key];
156     } else {
157       constructors[alternative] = constructors[key];
158     }
159   }
160 
161   /**
162    * An overloaded function of opIndexAssing
163    * This function hooks: laa["key"] = value; event but this function might be no use
164    */
165   T opIndexAssing(T value, string key) {
166     storage[key] = value;
167     called[key] = true;
168 
169     return value;
170   }
171 
172   /**
173    * An overloaded function of opIndex
174    * This function hooks: laa["key"] event.
175    */
176   T opIndex(string key) {
177     if (key in called && key in alwaysNew) {
178       return constructors[key]();
179     }
180 
181     if (!called[key]) {
182       T newT = constructors[key]();
183 
184       storage[key] = newT;
185       called[key] = true;
186 
187       return newT;
188     }
189 
190     return storage[key];
191   }
192 
193   bool has(string key) {
194     return key in called ? true : false;
195   }
196 
197   void setupWith(string name) {
198     if (!called[name]) {
199       T newT = constructors[name]();
200 
201       storage[name] = newT;
202       called[name] = true;
203     }
204   }
205 
206   void setupAll() {
207     foreach (key; this.constructors.keys) {
208       this.setupWith(key);
209     }
210   }
211 }
212 
213 /**
214  * Script Engine of ChickenClisp
215  */
216 class Engine {
217   enum ConstructorMode {
218     CLONE
219   }
220 
221   // Debug flags for Engine
222   bool debug_get_expression = false;
223 
224   /**
225    * This holds variables and operators.
226    * You can distinguish A VALUE of the child of this from whether a varibale or an operator.
227    */
228   LazedAssocArray!Value variables;
229 
230   bool sync_storage;
231 
232   /**
233    * Default Constructor
234    */
235   this() {
236     this.variables = new LazedAssocArray!Value;
237 
238     // Arithmetic operations
239     this.variables.insert!("+", q{new Value(cast(IOperator)(new AddOperator))});
240     this.variables.insert!("-", q{new Value(cast(IOperator)(new SubOperator))});
241     this.variables.insert!("*", q{new Value(cast(IOperator)(new MulOperator))});
242     this.variables.insert!("/", q{new Value(cast(IOperator)(new DivOperator))});
243     this.variables.insert!("%", q{new Value(cast(IOperator)(new ModOperator))});
244 
245     // Comparison operators
246     this.variables.insert!("=", q{new Value(cast(IOperator)(new EqualOperator))});
247     this.variables.insert!("<", q{new Value(cast(IOperator)(new LessOperator))});
248     this.variables.insert!(">", q{new Value(cast(IOperator)(new GreatOperator))});
249     this.variables.insert!("<=", q{new Value(cast(IOperator)(new LEqOperator))});
250     this.variables.insert!(">=", q{new Value(cast(IOperator)(new GEqOperator))});
251 
252     // Varibale/Function operators
253     this.variables.insert!("def", q{new Value(cast(IOperator)(new DeffunOperator))});
254     this.variables.insert!("set", q{new Value(cast(IOperator)(new SetOperator))});
255     this.variables.insert!("set-p", q{new Value(cast(IOperator)(new SetPOperator))});
256     this.variables.insert!("set-c", q{new Value(cast(IOperator)(new SetCOperator))});
257     this.variables.insert!("get", q{new Value(cast(IOperator)(new GetOperator))});
258     this.variables.insert!("let", q{new Value(cast(IOperator)(new LetOperator))});
259     this.variables.insert!("as-iv", q{new Value(cast(IOperator)(new AsIVOperator))});
260     this.variables.insert!("define", q{new Value(cast(IOperator)(new DefineOperator))});
261     this.variables.insert!("def-var", q{new Value(cast(IOperator)(new DefvarOperator))});
262     this.variables.insert!("get-fun", q{new Value(cast(IOperator)(new GetfunOperator))});
263     this.variables.insert!("set-idx", q{new Value(cast(IOperator)(new SetIdxOperator))});
264 
265     this.variables.insert!("def-macro", q{new Value(cast(IOperator)(new DefmacroOperator))});
266 
267     // Loop operators
268     this.variables.insert!("step", q{new Value(cast(IOperator)(new StepOperator))});
269     this.variables.insert!("times", q{new Value(cast(IOperator)(new TimesOperator))});
270     this.variables.insert!("until", q{new Value(cast(IOperator)(new UntilOperator))});
271     this.variables.insert!("while", q{new Value(cast(IOperator)(new WhileOperator))});
272 
273     // Logic operators
274     this.variables.insert!("!", q{new Value(cast(IOperator)(new NotOperator))});
275     this.variables.insert!("&&", q{new Value(cast(IOperator)(new AndOperator))});
276     this.variables.insert!("||", q{new Value(cast(IOperator)(new OrOperator))});
277 
278     // I/O operators
279     this.variables.insert!("print", q{new Value(cast(IOperator)(new PrintOperator))});
280     this.variables.insert!("println", q{new Value(cast(IOperator)(new PrintlnOperator))});
281 
282     // Condition operators
283     this.variables.insert!("if", q{new Value(cast(IOperator)(new IfOperator))});
284     this.variables.insert!("cond", q{new Value(cast(IOperator)(new CondOperator))});
285     this.variables.insert!("when", q{new Value(cast(IOperator)(new WhenOperator))});
286 
287     // Functional operators
288     this.variables.insert!("lambda", q{new Value(cast(IOperator)(new LambdaOperator))});
289     this.variables.insert!("map", q{new Value(cast(IOperator)(new MapOperator))});
290     this.variables.insert!("for-each", q{new Value(cast(IOperator)(new ForeachOperator))});
291     this.variables.insert!("fold", q{new Value(cast(IOperator)(new FoldOperator))});
292     this.variables.insert!("filter", q{new Value(cast(IOperator)(new FilterOperator))});
293 
294     // List operators
295     this.variables.insert!("car", q{new Value(cast(IOperator)(new CarOperator))});
296     this.variables.insert!("cdr", q{new Value(cast(IOperator)(new CdrOperator))});
297     this.variables.insert!("seq", q{new Value(cast(IOperator)(new SeqOperator))});
298     this.variables.insert!("cons", q{new Value(cast(IOperator)(new ConsOperator))});
299     this.variables.insert!("sort", q{new Value(cast(IOperator)(new SortOperator))});
300     this.variables.insert!("list?", q{new Value(cast(IOperator)(new IsListOperator))});
301     this.variables.insert!("remove", q{new Value(cast(IOperator)(new RemoveOperator))});
302     this.variables.insert!("length", q{new Value(cast(IOperator)(new LengthOperator))});
303 
304     // HashMap operators
305     this.variables.insert!("new-hash", q{new Value(cast(IOperator)(new NewHashOperator))});
306     this.variables.insert!("make-hash", q{new Value(cast(IOperator)(new MakeHashOperator))});
307     this.variables.insert!("hash-set-value",
308         q{new Value(cast(IOperator)(new HashSetValueOperator))});
309     this.variables.insert!("hash-get-value",
310         q{new Value(cast(IOperator)(new HashGetValueOperator))});
311     this.variables.insert!("hash-get-keys",
312         q{new Value(cast(IOperator)(new HashGetKeysOperator))});
313     this.variables.insert!("hash-get-values",
314         q{new Value(cast(IOperator)(new HashGetValuesOperator))});
315 
316     // String operators
317     this.variables.insert!("string-concat",
318         q{new Value(cast(IOperator)(new StringConcatOperator))});
319     this.variables.insert!("string-join", q{new Value(cast(IOperator)(new StringJoinOperator))});
320     this.variables.insert!("string-split", q{new Value(cast(IOperator)(new StringSplitOperator))});
321     this.variables.insert!("string-length",
322         q{new Value(cast(IOperator)(new StringLengthOperator))});
323     this.variables.insert!("string-slice", q{new Value(cast(IOperator)(new StringSliceOperator))});
324     this.variables.insert!("as-string", q{new Value(cast(IOperator)(new AsStringOperator))});
325     this.variables.insert!("string-repeat",
326         q{new Value(cast(IOperator)(new StringRepeatOperator))});
327     this.variables.insert!("string-chomp", q{new Value(cast(IOperator)(new StringChompOperator))});
328 
329     // Conversion operators
330     this.variables.insert!("number-to-string",
331         q{new Value(cast(IOperator)(new NumberToStringOperator))});
332     this.variables.insert!("string-to-number",
333         q{new Value(cast(IOperator)(new StringToNumberOperator))});
334     this.variables.insert!("number-to-char",
335         q{new Value(cast(IOperator)(new NumberToCharOperator))});
336     this.variables.insert!("char-to-number",
337         q{new Value(cast(IOperator)(new CharToNumberOperator))});
338     this.variables.insert!("float-to-integer",
339         q{new Value(cast(IOperator)(new FloatToIntegerOperator))});
340     this.variables.insert!("ubytes-to-string",
341         q{new Value(cast(IOperator)(new UbytesToStringOperator))});
342     this.variables.insert!("ubytes-to-integers",
343         q{new Value(cast(IOperator)(new UbytesToIntegersOperator))});
344 
345     // Array Operators
346     this.variables.insert!("array-new", q{new Value(cast(IOperator)(new ArrayNewOperator))});
347     this.variables.insert!("array-get-n", q{new Value(cast(IOperator)(new ArrayGetNOperator))});
348     this.variables.insert!("array-set-n", q{new Value(cast(IOperator)(new ArraySetNOperator))});
349     this.variables.insert!("array-slice", q{new Value(cast(IOperator)(new ArraySliceOperator))});
350     this.variables.insert!("array-append", q{new Value(cast(IOperator)(new ArrayAppendOperator))});
351     this.variables.insert!("array-concat", q{new Value(cast(IOperator)(new ArrayConcatOperator))});
352     this.variables.insert!("array-length", q{new Value(cast(IOperator)(new ArrayLengthOperator))});
353     this.variables.insert!("array-flatten",
354         q{new Value(cast(IOperator)(new ArrayFlattenOperator))});
355     this.variables.insert!("array-reverse",
356         q{new Value(cast(IOperator)(new ArrayReverseOperator))});
357 
358     // Utility operators
359     this.variables.insert!("eval", q{new Value(cast(IOperator)(new EvalOperator))});
360     this.variables.insert!("load", q{new Value(cast(IOperator)(new LoadOperator))});
361     this.variables.insert!("type", q{new Value(cast(IOperator)(new TypeOperator))});
362     this.variables.insert!("alias", q{new Value(cast(IOperator)(new AliasOperator))});
363     this.variables.insert!("assert", q{new Value(cast(IOperator)(new AssertOperator))});
364     this.variables.insert!("is-null?", q{new Value(cast(IOperator)(new IsNullOperator))});
365     this.variables.insert!("is-hash?", q{new Value(cast(IOperator)(new IsHashMapOperator))});
366     this.variables.insert!("transpile", q{new Value(cast(IOperator)(new TranspileOperator))});
367 
368     // Curl Operators
369     this.variables.insert!("curl-download",
370         q{new Value(cast(IOperator)(new CurlDownloadOperator))});
371     this.variables.insert!("curl-upload", q{new Value(cast(IOperator)(new CurlUploadOperator))});
372     this.variables.insert!("curl-get", q{new Value(cast(IOperator)(new CurlGetOperator))});
373     this.variables.insert!("curl-get-string",
374         q{new Value(cast(IOperator)(new CurlGetStringOperator))});
375     this.variables.insert!("curl-post", q{new Value(cast(IOperator)(new CurlPostOperator))});
376     this.variables.insert!("curl-post-string",
377         q{new Value(cast(IOperator)(new CurlPostStringOperator))});
378 
379     // Uri Operators
380     this.variables.insert!("url-encode-component",
381         q{new Value(cast(IOperator)(new UrlEncodeComponentOperator))});
382 
383     // UUID Operators
384     this.variables.insert!("random-uuid", q{new Value(cast(IOperator)(new RandomUUIDOperator))});
385 
386     // Datetime Operators
387     this.variables.insert!("get-current-unixtime",
388         q{new Value(cast(IOperator)(new GetCurrentUNIXTime))});
389 
390     // Digest Operators
391     this.variables.insert!("hmac-sha1", q{new Value(cast(IOperator)(new HMACSHA1Operator))});
392 
393     // Debug Operators
394     this.variables.insert!("dump-variables",
395         q{new Value(cast(IOperator)(new DumpVaribalesOperator))});
396     this.variables.insert!("peek-closure", q{new Value(cast(IOperator)(new PeekClosureOperator))});
397     this.variables.insert!("call-closure", q{new Value(cast(IOperator)(new CallClosureOperator))});
398     this.variables.insert!("toggle-ge-dbg",
399         q{new Value(cast(IOperator)(new ToggleGEDebugOperator))});
400 
401     // Class Operators
402     this.variables.insert!("class", q{new Value(cast(IOperator)(new ClassOperator))});
403     this.variables.insert!("new", q{new Value(cast(IOperator)(new NewOperator))});
404 
405     // Path Operators
406     this.variables.insert!("path-exists", q{new Value(cast(IOperator)(new PathExistsOperator))});
407     this.variables.insert!("path-is-dir", q{new Value(cast(IOperator)(new PathIsDirOperator))});
408     this.variables.insert!("path-is-file", q{new Value(cast(IOperator)(new PathIsFileOperator))});
409 
410     // File Operators
411     this.variables.insert!("remove-file", q{new Value(cast(IOperator)(new RemoveFileOperator))});
412     this.variables.insert!("remove-dir", q{new Value(cast(IOperator)(new RemoveDirOperator))});
413     this.variables.insert!("get-cwd", q{new Value(cast(IOperator)(new GetcwdOperator))});
414     this.variables.insert!("get-size", q{new Value(cast(IOperator)(new GetsizeOperator))});
415 
416     // STDIO Operators
417     this.variables.insert!("readln", q{new Value(cast(IOperator)(new ReadlnOperator))});
418     this.variables.insert!("stdin-by-line",
419         q{new Value(cast(IOperator)(new StdinByLINEOperator))});
420     this.variables.insert!("stdin-eof", q{new Value(cast(IOperator)(new StdinEofOperator))});
421 
422     // Aliases
423     this.variables.link("not", "!");
424     this.variables.link("and", "&&");
425     this.variables.link("or", "||");
426     this.variables.link("begin", "step");
427 
428     // Classes
429     this.variables.insert("FileClass", () => new Value(cast(ClassType)(new FileClass(this))), true);
430     this.variables.insert("Regex", () => new Value(cast(ClassType)(new RegexClass(this))), true);
431 
432     // Random Operators
433     this.variables.insert!("random-uniform",
434         q{new Value(cast(IOperator)(new RandomUniformOperator))});
435 
436     // Nop Operator
437     this.variables.insert!("nop", q{new Value(cast(IOperator)(new NopOperator))});
438 
439     // SystemOperator
440     this.variables.insert!("system", q{new Value(cast(IOperator)(new SystemOperator))});
441 
442     version (WithFFI) {
443       this.variables.insert!("dll", q{new Value(cast(IOperator)(new DllOperator))});
444     }
445   }
446 
447   /**
448    * Constructor to make a clone
449    */
450   this(ConstructorMode mode) {
451   }
452 
453   /**
454    * Super Class for a cloned object
455    */
456   private Engine _super;
457 
458   Engine peekSuper() {
459     return this._super;
460   }
461 
462   /**
463    * Clone this object
464    */
465   Engine clone() {
466     Engine newEngine = new Engine(ConstructorMode.CLONE);
467 
468     newEngine._super = this;
469 
470     newEngine.variables = new LazedAssocArray!Value;
471 
472     if (!sync_storage) {
473       newEngine.variables.called = this.variables.called.dup;
474       newEngine.variables.constructors = this.variables.constructors;
475       newEngine.variables.storage = this.variables.storage.dup;
476     } else {
477       newEngine.variables.called = this.variables.called;
478       newEngine.variables.constructors = this.variables.constructors;
479       newEngine.variables.storage = this.variables.storage;
480     }
481 
482     return newEngine;
483   }
484 
485   /**
486    * Define new variable
487    */
488   public Value defineVariable(string name, Value value) {
489     this.variables.set(name, value);
490 
491     return value;
492   }
493 
494   /**
495    * Set a value into certain variable
496    */
497   public Value setVariable(string name, Value value) {
498     Engine engine = this;
499 
500     while (true) {
501       if (name in engine.variables.called) {
502         engine.variables.set(name, value);
503         return value;
504       } else if (engine._super !is null) {
505         engine = engine._super;
506       } else {
507         engine.defineVariable(name, value);
508       }
509     }
510   }
511 
512   /**
513    * Get a value from variables table
514    */
515   public Value getVariable(string name) {
516     Engine engine = this;
517 
518     while (true) {
519       if (name in engine.variables.called) {
520         return engine.variables[name];
521       } else if (engine._super !is null) {
522         engine = engine._super;
523       } else {
524         return new Value;
525       }
526     }
527   }
528 
529   public bool hasVariable(string name) {
530     Engine engine = this;
531 
532     while (true) {
533       if (engine.variables.has(name)) {
534         return true;
535       } else if (engine._super !is null) {
536         engine = engine._super;
537       } else {
538         return false;
539       }
540     }
541   }
542 
543   /**
544    * Evalute Object
545    */
546   public Value eval(Value script) {
547     Value ret = new Value(this.getExpression(script));
548 
549     if (ret.type == ValueType.IOperator) {
550       return ret;
551     }
552 
553     enforce(ret.type == ValueType.IExpression);
554 
555     ret = ret.getIExpression.eval(this);
556 
557     if (ret.type == ValueType.IOperator) {
558       return new Value(new Closure(this, ret.getIOperator));
559     } else {
560       return ret;
561     }
562   }
563 
564   /**
565    * getExpression
566    * Build Script Tree
567    */
568   public IExpression getExpression(Value script) {
569     if (debug_get_expression) {
570       import std.stdio;
571 
572       writeln("[getExpression] script -> ", script);
573     }
574 
575     if (script.type == ValueType.ImmediateValue) {
576       return script.getImmediateValue;
577     }
578 
579     if (script.type == ValueType.Array) {
580       Value[] scriptList = script.getArray;
581 
582       if (scriptList.length == 0) {
583         return new ImmediateValue(new Value(ValueType.Null));
584       }
585 
586       if (scriptList[0].type == ValueType.Array) {
587         Value op = this.getVariable(scriptList[0][0].getString);
588 
589         if (op.type == ValueType.Closure) {
590           Closure closure = op.getClosure;
591           Engine engine = closure.engine;
592           IOperator operator = closure.operator;
593 
594           Closure cls = operator.call(engine, scriptList[0].getArray[1 .. $]).getClosure;
595 
596           if (scriptList.length == 2) {
597             return new ImmediateValue(cls.eval(scriptList[1 .. $]));
598           } else {
599             return new ImmediateValue(cls.eval([]));
600           }
601         } else if (op.type == ValueType.IOperator) {
602           CallOperator ret = new CallOperator(this.variables[scriptList[0][0].getString].getIOperator,
603               scriptList[0].getArray[1 .. $]);
604           Value tmp = ret.eval(this);
605 
606           if (tmp.type == ValueType.Closure) {
607             return new ImmediateValue(tmp.getClosure.eval(scriptList[1 .. $]));
608           } else if (tmp.type == ValueType.IOperator) {
609             return new ImmediateValue(tmp.getIOperator.call(this, scriptList[1 .. $]));
610           } else if (tmp.type == ValueType.ClassType) {
611             ClassType cls = tmp.getClassType;
612 
613             Engine tmp_super = cls._engine._super;
614             cls._engine._super = this;
615 
616             auto _ret = new ImmediateValue(cls.call(cls._engine, scriptList[1 .. $]));
617 
618             cls._engine._super = tmp_super;
619 
620             return _ret;
621           } else {
622             throw new Exception("Invalid type was given as a first argument - " ~ op.toString);
623           }
624         } else {
625           throw new Exception("Invalid Operator was given!");
626         }
627       } else if (scriptList[0].type == ValueType.SymbolValue
628           && this.hasVariable(scriptList[0].getString)) {
629         Value tmp = this.getVariable(scriptList[0].getString);
630 
631         if (tmp.type == ValueType.IOperator) {
632           IOperator op = tmp.getIOperator;
633           return new CallOperator(op, scriptList[1 .. $]);
634         } else if (tmp.type == ValueType.Closure) {
635           return new CallOperator(tmp.getClosure.operator, scriptList[1 .. $]);
636         } else if (tmp.type == ValueType.ClassType) {
637           ClassType cls = tmp.getClassType;
638 
639           Engine tmp_super = cls._engine._super;
640           cls._engine._super = this;
641 
642           auto ret = new ImmediateValue(cls.call(cls._engine, scriptList[1 .. $]));
643 
644           cls._engine._super = tmp_super;
645 
646           return ret;
647         } else if (tmp.type == ValueType.Macro) {
648           import orelang.expression.Macro;
649 
650           Macro mcr = tmp.getMacro;
651           return new ImmediateValue(mcr.call(this, scriptList[1 .. $]));
652         } else {
653           throw new Exception("Invalid Operator was given!");
654         }
655       } else {
656         throw new Exception("The function or variable %s is undefined".format(scriptList[0]));
657       }
658     } else {
659       if (script.type == ValueType.SymbolValue || script.type == ValueType.String) {
660         if (script.type == ValueType.SymbolValue) {
661           Value tmp;
662           tmp = this.getVariable(script.getString).dup;
663 
664           if (tmp.type != ValueType.Null) {
665             return new ImmediateValue(tmp);
666           }
667         } else {
668           return new ImmediateValue(new Value(script.getString));
669         }
670       }
671 
672       return new ImmediateValue(script);
673     }
674   }
675 
676   public bool variableDefined(string name) {
677     return this.getVariable(name).type != ValueType.Null;
678   }
679 }