1#!/usr/bin/env perl 2 3my $_fmt; 4$_fmt = "gofmt"; 5$_fmt = "cat -n" if "cat" eq ($ARGV[0] || ""); 6 7use strict; 8use warnings; 9use IO::File; 10 11my $self = __PACKAGE__; 12 13sub functionLabel ($) { 14 return "$_[0]_function"; 15} 16 17sub trim ($) { 18 local $_ = shift; 19 s/^\s*//, s/\s*$// for $_; 20 return $_; 21} 22 23open my $fmt, "|-", "$_fmt" or die $!; 24 25$fmt->print(<<_END_); 26package otto 27 28import ( 29 "math" 30) 31 32func _newContext(runtime *_runtime) { 33@{[ join "\n", $self->newContext() ]} 34} 35 36func newConsoleObject(runtime *_runtime) *_object { 37@{[ join "\n", $self->newConsoleObject() ]} 38} 39_END_ 40 41for (qw/int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float32 float64/) { 42 $fmt->print(<<_END_); 43 44func toValue_$_(value $_) Value { 45 return Value{ 46 kind: valueNumber, 47 value: value, 48 } 49} 50_END_ 51} 52 53$fmt->print(<<_END_); 54 55func toValue_string(value string) Value { 56 return Value{ 57 kind: valueString, 58 value: value, 59 } 60} 61 62func toValue_string16(value []uint16) Value { 63 return Value{ 64 kind: valueString, 65 value: value, 66 } 67} 68 69func toValue_bool(value bool) Value { 70 return Value{ 71 kind: valueBoolean, 72 value: value, 73 } 74} 75 76func toValue_object(value *_object) Value { 77 return Value{ 78 kind: valueObject, 79 value: value, 80 } 81} 82_END_ 83 84close $fmt; 85 86sub newConsoleObject { 87 my $self = shift; 88 89 return 90 $self->block(sub { 91 my $class = "Console"; 92 my @got = $self->functionDeclare( 93 $class, 94 "log", 0, 95 "debug:log", 0, 96 "info:log", 0, 97 "error", 0, 98 "warn:error", 0, 99 "dir", 0, 100 "time", 0, 101 "timeEnd", 0, 102 "trace", 0, 103 "assert", 0, 104 ); 105 return 106 "return @{[ $self->newObject(@got) ]}" 107 }), 108 ; 109} 110 111sub newContext { 112 my $self = shift; 113 return 114 # ObjectPrototype 115 $self->block(sub { 116 my $class = "Object"; 117 return 118 ".${class}Prototype =", 119 $self->globalPrototype( 120 $class, 121 "_classObject", 122 undef, 123 "prototypeValueObject", 124 ), 125 }), 126 127 # FunctionPrototype 128 $self->block(sub { 129 my $class = "Function"; 130 return 131 ".${class}Prototype =", 132 $self->globalPrototype( 133 $class, 134 "_classObject", 135 ".ObjectPrototype", 136 "prototypeValueFunction", 137 ), 138 }), 139 140 # ObjectPrototype 141 $self->block(sub { 142 my $class = "Object"; 143 my @got = $self->functionDeclare( 144 $class, 145 "valueOf", 0, 146 "toString", 0, 147 "toLocaleString", 0, 148 "hasOwnProperty", 1, 149 "isPrototypeOf", 1, 150 "propertyIsEnumerable", 1, 151 ); 152 my @propertyMap = $self->propertyMap( 153 @got, 154 $self->property("constructor", undef), 155 ); 156 my $propertyOrder = $self->propertyOrder(@propertyMap); 157 $propertyOrder =~ s/^propertyOrder: //; 158 return 159 ".${class}Prototype.property =", @propertyMap, 160 ".${class}Prototype.propertyOrder =", $propertyOrder, 161 }), 162 163 # FunctionPrototype 164 $self->block(sub { 165 my $class = "Function"; 166 my @got = $self->functionDeclare( 167 $class, 168 "toString", 0, 169 "apply", 2, 170 "call", 1, 171 "bind", 1, 172 ); 173 my @propertyMap = $self->propertyMap( 174 @got, 175 $self->property("constructor", undef), 176 $self->property("length", $self->numberValue(0), "0"), 177 ); 178 my $propertyOrder = $self->propertyOrder(@propertyMap); 179 $propertyOrder =~ s/^propertyOrder: //; 180 return 181 ".${class}Prototype.property =", @propertyMap, 182 ".${class}Prototype.propertyOrder =", $propertyOrder, 183 }), 184 185 # Object 186 $self->block(sub { 187 my $class = "Object"; 188 return 189 ".$class =", 190 $self->globalFunction( 191 $class, 192 1, 193 $self->functionDeclare( 194 $class, 195 "getPrototypeOf", 1, 196 "getOwnPropertyDescriptor", 2, 197 "defineProperty", 3, 198 "defineProperties", 2, 199 "create", 2, 200 "isExtensible", 1, 201 "preventExtensions", 1, 202 "isSealed", 1, 203 "seal", 1, 204 "isFrozen", 1, 205 "freeze", 1, 206 "keys", 1, 207 "getOwnPropertyNames", 1, 208 ), 209 ), 210 }), 211 212 # Function 213 $self->block(sub { 214 my $class = "Function"; 215 return 216 "Function :=", 217 $self->globalFunction( 218 $class, 219 1, 220 ), 221 ".$class = Function", 222 }), 223 224 # Array 225 $self->block(sub { 226 my $class = "Array"; 227 my @got = $self->functionDeclare( 228 $class, 229 "toString", 0, 230 "toLocaleString", 0, 231 "concat", 1, 232 "join", 1, 233 "splice", 2, 234 "shift", 0, 235 "pop", 0, 236 "push", 1, 237 "slice", 2, 238 "unshift", 1, 239 "reverse", 0, 240 "sort", 1, 241 "indexOf", 1, 242 "lastIndexOf", 1, 243 "every", 1, 244 "some", 1, 245 "forEach", 1, 246 "map", 1, 247 "filter", 1, 248 "reduce", 1, 249 "reduceRight", 1, 250 ); 251 return 252 ".${class}Prototype =", 253 $self->globalPrototype( 254 $class, 255 "_classArray", 256 ".ObjectPrototype", 257 undef, 258 $self->property("length", $self->numberValue("uint32(0)"), "0100"), 259 @got, 260 ), 261 ".$class =", 262 $self->globalFunction( 263 $class, 264 1, 265 $self->functionDeclare( 266 $class, 267 "isArray", 1, 268 ), 269 ), 270 }), 271 272 # String 273 $self->block(sub { 274 my $class = "String"; 275 my @got = $self->functionDeclare( 276 $class, 277 "toString", 0, 278 "valueOf", 0, 279 "charAt", 1, 280 "charCodeAt", 1, 281 "concat", 1, 282 "indexOf", 1, 283 "lastIndexOf", 1, 284 "match", 1, 285 "replace", 2, 286 "search", 1, 287 "split", 2, 288 "slice", 2, 289 "substring", 2, 290 "toLowerCase", 0, 291 "toUpperCase", 0, 292 "substr", 2, 293 "trim", 0, 294 "trimLeft", 0, 295 "trimRight", 0, 296 "localeCompare", 1, 297 "toLocaleLowerCase", 0, 298 "toLocaleUpperCase", 0, 299 ); 300 return 301 ".${class}Prototype =", 302 $self->globalPrototype( 303 $class, 304 "_classString", 305 ".ObjectPrototype", 306 "prototypeValueString", 307 $self->property("length", $self->numberValue("int(0)"), "0"), 308 @got, 309 ), 310 ".$class =", 311 $self->globalFunction( 312 $class, 313 1, 314 $self->functionDeclare( 315 $class, 316 "fromCharCode", 1, 317 ), 318 ), 319 }), 320 321 # Boolean 322 $self->block(sub { 323 my $class = "Boolean"; 324 my @got = $self->functionDeclare( 325 $class, 326 "toString", 0, 327 "valueOf", 0, 328 ); 329 return 330 ".${class}Prototype =", 331 $self->globalPrototype( 332 $class, 333 "_classObject", 334 ".ObjectPrototype", 335 "prototypeValueBoolean", 336 @got, 337 ), 338 ".$class =", 339 $self->globalFunction( 340 $class, 341 1, 342 $self->functionDeclare( 343 $class, 344 ), 345 ), 346 }), 347 348 # Number 349 $self->block(sub { 350 my $class = "Number"; 351 my @got = $self->functionDeclare( 352 $class, 353 "toString", 0, 354 "valueOf", 0, 355 "toFixed", 1, 356 "toExponential", 1, 357 "toPrecision", 1, 358 "toLocaleString", 1, 359 ); 360 return 361 ".${class}Prototype =", 362 $self->globalPrototype( 363 $class, 364 "_classObject", 365 ".ObjectPrototype", 366 "prototypeValueNumber", 367 @got, 368 ), 369 ".$class =", 370 $self->globalFunction( 371 $class, 372 1, 373 $self->functionDeclare( 374 $class, 375 ), 376 $self->numberConstantDeclare( 377 "MAX_VALUE", "math.MaxFloat64", 378 "MIN_VALUE", "math.SmallestNonzeroFloat64", 379 "NaN", "math.NaN()", 380 "NEGATIVE_INFINITY", "math.Inf(-1)", 381 "POSITIVE_INFINITY", "math.Inf(+1)", 382 ), 383 ), 384 }), 385 386 # Math 387 $self->block(sub { 388 my $class = "Math"; 389 return 390 ".$class =", 391 $self->globalObject( 392 $class, 393 $self->functionDeclare( 394 $class, 395 "abs", 1, 396 "acos", 1, 397 "asin", 1, 398 "atan", 1, 399 "atan2", 1, 400 "ceil", 1, 401 "cos", 1, 402 "exp", 1, 403 "floor", 1, 404 "log", 1, 405 "max", 2, 406 "min", 2, 407 "pow", 2, 408 "random", 0, 409 "round", 1, 410 "sin", 1, 411 "sqrt", 1, 412 "tan", 1, 413 ), 414 $self->numberConstantDeclare( 415 "E", "math.E", 416 "LN10", "math.Ln10", 417 "LN2", "math.Ln2", 418 "LOG2E", "math.Log2E", 419 "LOG10E", "math.Log10E", 420 "PI", "math.Pi", 421 "SQRT1_2", "sqrt1_2", 422 "SQRT2", "math.Sqrt2", 423 ) 424 ), 425 }), 426 427 # Date 428 $self->block(sub { 429 my $class = "Date"; 430 my @got = $self->functionDeclare( 431 $class, 432 "toString", 0, 433 "toDateString", 0, 434 "toTimeString", 0, 435 "toUTCString", 0, 436 "toISOString", 0, 437 "toJSON", 1, 438 "toGMTString", 0, 439 "toLocaleString", 0, 440 "toLocaleDateString", 0, 441 "toLocaleTimeString", 0, 442 "valueOf", 0, 443 "getTime", 0, 444 "getYear", 0, 445 "getFullYear", 0, 446 "getUTCFullYear", 0, 447 "getMonth", 0, 448 "getUTCMonth", 0, 449 "getDate", 0, 450 "getUTCDate", 0, 451 "getDay", 0, 452 "getUTCDay", 0, 453 "getHours", 0, 454 "getUTCHours", 0, 455 "getMinutes", 0, 456 "getUTCMinutes", 0, 457 "getSeconds", 0, 458 "getUTCSeconds", 0, 459 "getMilliseconds", 0, 460 "getUTCMilliseconds", 0, 461 "getTimezoneOffset", 0, 462 "setTime", 1, 463 "setMilliseconds", 1, 464 "setUTCMilliseconds", 1, 465 "setSeconds", 2, 466 "setUTCSeconds", 2, 467 "setMinutes", 3, 468 "setUTCMinutes", 3, 469 "setHours", 4, 470 "setUTCHours", 4, 471 "setDate", 1, 472 "setUTCDate", 1, 473 "setMonth", 2, 474 "setUTCMonth", 2, 475 "setYear", 1, 476 "setFullYear", 3, 477 "setUTCFullYear", 3, 478 ); 479 return 480 ".${class}Prototype =", 481 $self->globalPrototype( 482 $class, 483 "_classObject", 484 ".ObjectPrototype", 485 "prototypeValueDate", 486 @got, 487 ), 488 ".$class =", 489 $self->globalFunction( 490 $class, 491 7, 492 $self->functionDeclare( 493 $class, 494 "parse", 1, 495 "UTC", 7, 496 "now", 0, 497 ), 498 ), 499 }), 500 501 # RegExp 502 $self->block(sub { 503 my $class = "RegExp"; 504 my @got = $self->functionDeclare( 505 $class, 506 "toString", 0, 507 "exec", 1, 508 "test", 1, 509 "compile", 1, 510 ); 511 return 512 ".${class}Prototype =", 513 $self->globalPrototype( 514 $class, 515 "_classObject", 516 ".ObjectPrototype", 517 "prototypeValueRegExp", 518 @got, 519 ), 520 ".$class =", 521 $self->globalFunction( 522 $class, 523 2, 524 $self->functionDeclare( 525 $class, 526 ), 527 ), 528 }), 529 530 # Error 531 $self->block(sub { 532 my $class = "Error"; 533 my @got = $self->functionDeclare( 534 $class, 535 "toString", 0, 536 ); 537 return 538 ".${class}Prototype =", 539 $self->globalPrototype( 540 $class, 541 "_classObject", 542 ".ObjectPrototype", 543 undef, 544 @got, 545 $self->property("name", $self->stringValue("Error")), 546 $self->property("message", $self->stringValue("")), 547 ), 548 ".$class =", 549 $self->globalFunction( 550 $class, 551 1, 552 $self->functionDeclare( 553 $class, 554 ), 555 ), 556 }), 557 558 (map { 559 my $class = "${_}Error"; 560 $self->block(sub { 561 my @got = $self->functionDeclare( 562 $class, 563 ); 564 return 565 ".${class}Prototype =", 566 $self->globalPrototype( 567 $class, 568 "_classObject", 569 ".ErrorPrototype", 570 undef, 571 @got, 572 $self->property("name", $self->stringValue($class)), 573 ), 574 ".$class =", 575 $self->globalFunction( 576 $class, 577 1, 578 $self->functionDeclare( 579 $class, 580 ), 581 ), 582 }); 583 } qw/Eval Type Range Reference Syntax URI/), 584 585 # JSON 586 $self->block(sub { 587 my $class = "JSON"; 588 return 589 ".$class =", 590 $self->globalObject( 591 $class, 592 $self->functionDeclare( 593 $class, 594 "parse", 2, 595 "stringify", 3, 596 ), 597 ), 598 }), 599 600 # Global 601 $self->block(sub { 602 my $class = "Global"; 603 my @got = $self->functionDeclare( 604 $class, 605 "eval", 1, 606 "parseInt", 2, 607 "parseFloat", 1, 608 "isNaN", 1, 609 "isFinite", 1, 610 "decodeURI", 1, 611 "decodeURIComponent", 1, 612 "encodeURI", 1, 613 "encodeURIComponent", 1, 614 "escape", 1, 615 "unescape", 1, 616 ); 617 my @propertyMap = $self->propertyMap( 618 @got, 619 $self->globalDeclare( 620 "Object", 621 "Function", 622 "Array", 623 "String", 624 "Boolean", 625 "Number", 626 "Math", 627 "Date", 628 "RegExp", 629 "Error", 630 "EvalError", 631 "TypeError", 632 "RangeError", 633 "ReferenceError", 634 "SyntaxError", 635 "URIError", 636 "JSON", 637 ), 638 $self->property("undefined", $self->undefinedValue(), "0"), 639 $self->property("NaN", $self->numberValue("math.NaN()"), "0"), 640 $self->property("Infinity", $self->numberValue("math.Inf(+1)"), "0"), 641 ); 642 my $propertyOrder = $self->propertyOrder(@propertyMap); 643 $propertyOrder =~ s/^propertyOrder: //; 644 return 645 "runtime.globalObject.property =", 646 @propertyMap, 647 "runtime.globalObject.propertyOrder =", 648 $propertyOrder, 649 ; 650 }), 651 ; 652} 653 654sub propertyMap { 655 my $self = shift; 656 return "map[string]_property{", (join ",\n", @_, ""), "}", 657} 658 659our (@preblock, @postblock); 660sub block { 661 my $self = shift; 662 local @preblock = (); 663 local @postblock = (); 664 my @input = $_[0]->(); 665 my @output; 666 while (@input) { 667 local $_ = shift @input; 668 if (m/^\./) { 669 $_ = "runtime.global$_"; 670 } 671 if (m/ :?=$/) { 672 $_ .= shift @input; 673 } 674 push @output, $_; 675 } 676 return 677 "{", 678 @preblock, 679 @output, 680 @postblock, 681 "}", 682 ; 683} 684 685sub numberConstantDeclare { 686 my $self = shift; 687 my @got; 688 while (@_) { 689 my $name = shift; 690 my $value = shift; 691 push @got, $self->property($name, $self->numberValue($value), "0"), 692 } 693 return @got; 694} 695 696sub functionDeclare { 697 my $self = shift; 698 my $class = shift; 699 my $builtin = "builtin${class}"; 700 my @got; 701 while (@_) { 702 my $name = shift; 703 my $length = shift; 704 $name = $self->newFunction($name, "${builtin}_", $length); 705 push @got, $self->functionProperty($name), 706 } 707 return @got; 708} 709 710sub globalDeclare { 711 my $self = shift; 712 my @got; 713 while (@_) { 714 my $name = shift; 715 push @got, $self->property($name, $self->objectValue("runtime.global.$name"), "0101"), 716 } 717 return @got; 718} 719 720sub propertyOrder { 721 my $self = shift; 722 my $propertyMap = join "", @_; 723 724 my (@keys) = $propertyMap =~ m/("\w+"):/g; 725 my $propertyOrder = 726 join "\n", "propertyOrder: []string{", (join ",\n", @keys, ""), "}"; 727 return $propertyOrder; 728} 729 730sub globalObject { 731 my $self = shift; 732 my $name = shift; 733 734 my $propertyMap = ""; 735 if (@_) { 736 $propertyMap = join "\n", $self->propertyMap(@_); 737 my $propertyOrder = $self->propertyOrder($propertyMap); 738 $propertyMap = "property: $propertyMap,\n$propertyOrder,"; 739 } 740 741 return trim <<_END_; 742&_object{ 743 runtime: runtime, 744 class: "$name", 745 objectClass: _classObject, 746 prototype: runtime.global.ObjectPrototype, 747 extensible: true, 748 $propertyMap 749} 750_END_ 751} 752 753sub globalFunction { 754 my $self = shift; 755 my $name = shift; 756 my $length = shift; 757 758 my $builtin = "builtin${name}"; 759 my $builtinNew = "builtinNew${name}"; 760 my $prototype = "runtime.global.${name}Prototype"; 761 my $propertyMap = ""; 762 unshift @_, 763 $self->property("length", $self->numberValue($length), "0"), 764 $self->property("prototype", $self->objectValue($prototype), "0"), 765 ; 766 767 if (@_) { 768 $propertyMap = join "\n", $self->propertyMap(@_); 769 my $propertyOrder = $self->propertyOrder($propertyMap); 770 $propertyMap = "property: $propertyMap,\n$propertyOrder,"; 771 } 772 773 push @postblock, $self->statement( 774 "$prototype.property[\"constructor\"] =", 775 $self->property(undef, $self->objectValue("runtime.global.${name}"), "0101"), 776 ); 777 778 return trim <<_END_; 779&_object{ 780 runtime: runtime, 781 class: "Function", 782 objectClass: _classObject, 783 prototype: runtime.global.FunctionPrototype, 784 extensible: true, 785 value: @{[ $self->nativeFunctionOf($name, $builtin, $builtinNew) ]}, 786 $propertyMap 787} 788_END_ 789} 790 791sub nativeCallFunction { 792 my $self = shift; 793 my $name = shift; 794 my $func = shift; 795 return trim <<_END_; 796_nativeCallFunction{ "$name", $func } 797_END_ 798} 799 800sub globalPrototype { 801 my $self = shift; 802 my $class = shift; 803 my $classObject = shift; 804 my $prototype = shift; 805 my $value = shift; 806 807 if (!defined $prototype) { 808 $prototype = "nil"; 809 } 810 811 if (!defined $value) { 812 $value = "nil"; 813 } 814 815 if ($prototype =~ m/^\./) { 816 $prototype = "runtime.global$prototype"; 817 } 818 819 my $propertyMap = ""; 820 if (@_) { 821 $propertyMap = join "\n", $self->propertyMap(@_); 822 my $propertyOrder = $self->propertyOrder($propertyMap); 823 $propertyMap = "property: $propertyMap,\n$propertyOrder,"; 824 } 825 826 return trim <<_END_; 827&_object{ 828 runtime: runtime, 829 class: "$class", 830 objectClass: $classObject, 831 prototype: $prototype, 832 extensible: true, 833 value: $value, 834 $propertyMap 835} 836_END_ 837} 838 839sub newFunction { 840 my $self = shift; 841 my $name = shift; 842 my $func = shift; 843 my $length = shift; 844 845 my @name = ($name, $name); 846 if ($name =~ m/^(\w+):(\w+)$/) { 847 @name = ($1, $2); 848 $name = $name[0]; 849 } 850 851 if ($func =~ m/^builtin\w+_$/) { 852 $func = "$func$name[1]"; 853 } 854 855 my $propertyOrder = ""; 856 my @propertyMap = ( 857 $self->property("length", $self->numberValue($length), "0"), 858 ); 859 860 if (@propertyMap) { 861 $propertyOrder = $self->propertyOrder(@propertyMap); 862 $propertyOrder = "$propertyOrder,"; 863 } 864 865 my $label = functionLabel($name); 866 push @preblock, $self->statement( 867 "$label := @{[ trim <<_END_ ]}", 868&_object{ 869 runtime: runtime, 870 class: "Function", 871 objectClass: _classObject, 872 prototype: runtime.global.FunctionPrototype, 873 extensible: true, 874 property: @{[ join "\n", $self->propertyMap(@propertyMap) ]}, 875 $propertyOrder 876 value: @{[ $self->nativeFunctionOf($name, $func) ]}, 877} 878_END_ 879 ); 880 881 return $name; 882} 883 884sub newObject { 885 my $self = shift; 886 887 my $propertyMap = join "\n", $self->propertyMap(@_); 888 my $propertyOrder = $self->propertyOrder($propertyMap); 889 890 return trim <<_END_; 891&_object{ 892 runtime: runtime, 893 class: "Object", 894 objectClass: _classObject, 895 prototype: runtime.global.ObjectPrototype, 896 extensible: true, 897 property: $propertyMap, 898 $propertyOrder, 899} 900_END_ 901} 902 903sub newPrototypeObject { 904 my $self = shift; 905 my $class = shift; 906 my $objectClass = shift; 907 my $value = shift; 908 if (defined $value) { 909 $value = "value: $value,"; 910 } 911 912 my $propertyMap = join "\n", $self->propertyMap(@_); 913 my $propertyOrder = $self->propertyOrder($propertyMap); 914 915 return trim <<_END_; 916&_object{ 917 runtime: runtime, 918 class: "$class", 919 objectClass: $objectClass, 920 prototype: runtime.global.ObjectPrototype, 921 extensible: true, 922 property: $propertyMap, 923 $propertyOrder, 924 $value 925} 926_END_ 927} 928 929sub functionProperty { 930 my $self = shift; 931 my $name = shift; 932 933 return $self->property( 934 $name, 935 $self->objectValue(functionLabel($name)) 936 ); 937} 938 939sub statement { 940 my $self = shift; 941 return join "\n", @_; 942} 943 944sub functionOf { 945 my $self = shift; 946 my $call = shift; 947 my $construct = shift; 948 if ($construct) { 949 $construct = "construct: $construct,"; 950 } else { 951 $construct = ""; 952 } 953 954 return trim <<_END_ 955_functionObject{ 956 call: $call, 957 $construct 958} 959_END_ 960} 961 962sub nativeFunctionOf { 963 my $self = shift; 964 my $name = shift; 965 my $call = shift; 966 my $construct = shift; 967 if ($construct) { 968 $construct = "construct: $construct,"; 969 } else { 970 $construct = ""; 971 } 972 973 return trim <<_END_ 974_nativeFunctionObject{ 975 name: "$name", 976 call: $call, 977 $construct 978} 979_END_ 980} 981 982sub nameProperty { 983 my $self = shift; 984 my $name = shift; 985 my $value = shift; 986 987 return trim <<_END_; 988"$name": _property{ 989 mode: 0101, 990 value: $value, 991} 992_END_ 993} 994 995sub numberValue { 996 my $self = shift; 997 my $value = shift; 998 return trim <<_END_; 999Value{ 1000 kind: valueNumber, 1001 value: $value, 1002} 1003_END_ 1004} 1005 1006sub property { 1007 my $self = shift; 1008 my $name = shift; 1009 my $value = shift; 1010 my $mode = shift; 1011 $mode = "0101" unless defined $mode; 1012 if (! defined $value) { 1013 $value = "Value{}"; 1014 } 1015 if (defined $name) { 1016 return trim <<_END_; 1017"$name": _property{ 1018 mode: $mode, 1019 value: $value, 1020} 1021_END_ 1022 } else { 1023 return trim <<_END_; 1024_property{ 1025 mode: $mode, 1026 value: $value, 1027} 1028_END_ 1029 } 1030 1031} 1032 1033sub objectProperty { 1034 my $self = shift; 1035 my $name = shift; 1036 my $value = shift; 1037 1038 return trim <<_END_; 1039"$name": _property{ 1040 mode: 0101, 1041 value: @{[ $self->objectValue($value)]}, 1042} 1043_END_ 1044} 1045 1046sub objectValue { 1047 my $self = shift; 1048 my $value = shift; 1049 return trim <<_END_ 1050Value{ 1051 kind: valueObject, 1052 value: $value, 1053} 1054_END_ 1055} 1056 1057sub stringValue { 1058 my $self = shift; 1059 my $value = shift; 1060 return trim <<_END_ 1061Value{ 1062 kind: valueString, 1063 value: "$value", 1064} 1065_END_ 1066} 1067 1068sub booleanValue { 1069 my $self = shift; 1070 my $value = shift; 1071 return trim <<_END_ 1072Value{ 1073 kind: valueBoolean, 1074 value: $value, 1075} 1076_END_ 1077} 1078 1079sub undefinedValue { 1080 my $self = shift; 1081 return trim <<_END_ 1082Value{ 1083 kind: valueUndefined, 1084} 1085_END_ 1086} 1087