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