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 }