inline.pl 26 KB

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