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 }