Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

typed.js 38KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  1. /*
  2. * @fileoverview Type expression parser.
  3. * @author Yusuke Suzuki <utatane.tea@gmail.com>
  4. * @author Dan Tao <daniel.tao@gmail.com>
  5. * @author Andrew Eisenberg <andrew@eisenberg.as>
  6. */
  7. // "typed", the Type Expression Parser for doctrine.
  8. (function () {
  9. 'use strict';
  10. var Syntax,
  11. Token,
  12. source,
  13. length,
  14. index,
  15. previous,
  16. token,
  17. value,
  18. esutils,
  19. utility,
  20. rangeOffset,
  21. addRange;
  22. esutils = require('esutils');
  23. utility = require('./utility');
  24. Syntax = {
  25. NullableLiteral: 'NullableLiteral',
  26. AllLiteral: 'AllLiteral',
  27. NullLiteral: 'NullLiteral',
  28. UndefinedLiteral: 'UndefinedLiteral',
  29. VoidLiteral: 'VoidLiteral',
  30. UnionType: 'UnionType',
  31. ArrayType: 'ArrayType',
  32. RecordType: 'RecordType',
  33. FieldType: 'FieldType',
  34. FunctionType: 'FunctionType',
  35. ParameterType: 'ParameterType',
  36. RestType: 'RestType',
  37. NonNullableType: 'NonNullableType',
  38. OptionalType: 'OptionalType',
  39. NullableType: 'NullableType',
  40. NameExpression: 'NameExpression',
  41. TypeApplication: 'TypeApplication',
  42. StringLiteralType: 'StringLiteralType',
  43. NumericLiteralType: 'NumericLiteralType',
  44. BooleanLiteralType: 'BooleanLiteralType'
  45. };
  46. Token = {
  47. ILLEGAL: 0, // ILLEGAL
  48. DOT_LT: 1, // .<
  49. REST: 2, // ...
  50. LT: 3, // <
  51. GT: 4, // >
  52. LPAREN: 5, // (
  53. RPAREN: 6, // )
  54. LBRACE: 7, // {
  55. RBRACE: 8, // }
  56. LBRACK: 9, // [
  57. RBRACK: 10, // ]
  58. COMMA: 11, // ,
  59. COLON: 12, // :
  60. STAR: 13, // *
  61. PIPE: 14, // |
  62. QUESTION: 15, // ?
  63. BANG: 16, // !
  64. EQUAL: 17, // =
  65. NAME: 18, // name token
  66. STRING: 19, // string
  67. NUMBER: 20, // number
  68. EOF: 21
  69. };
  70. function isTypeName(ch) {
  71. return '><(){}[],:*|?!='.indexOf(String.fromCharCode(ch)) === -1 && !esutils.code.isWhiteSpace(ch) && !esutils.code.isLineTerminator(ch);
  72. }
  73. function Context(previous, index, token, value) {
  74. this._previous = previous;
  75. this._index = index;
  76. this._token = token;
  77. this._value = value;
  78. }
  79. Context.prototype.restore = function () {
  80. previous = this._previous;
  81. index = this._index;
  82. token = this._token;
  83. value = this._value;
  84. };
  85. Context.save = function () {
  86. return new Context(previous, index, token, value);
  87. };
  88. function maybeAddRange(node, range) {
  89. if (addRange) {
  90. node.range = [range[0] + rangeOffset, range[1] + rangeOffset];
  91. }
  92. return node;
  93. }
  94. function advance() {
  95. var ch = source.charAt(index);
  96. index += 1;
  97. return ch;
  98. }
  99. function scanHexEscape(prefix) {
  100. var i, len, ch, code = 0;
  101. len = (prefix === 'u') ? 4 : 2;
  102. for (i = 0; i < len; ++i) {
  103. if (index < length && esutils.code.isHexDigit(source.charCodeAt(index))) {
  104. ch = advance();
  105. code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
  106. } else {
  107. return '';
  108. }
  109. }
  110. return String.fromCharCode(code);
  111. }
  112. function scanString() {
  113. var str = '', quote, ch, code, unescaped, restore; //TODO review removal octal = false
  114. quote = source.charAt(index);
  115. ++index;
  116. while (index < length) {
  117. ch = advance();
  118. if (ch === quote) {
  119. quote = '';
  120. break;
  121. } else if (ch === '\\') {
  122. ch = advance();
  123. if (!esutils.code.isLineTerminator(ch.charCodeAt(0))) {
  124. switch (ch) {
  125. case 'n':
  126. str += '\n';
  127. break;
  128. case 'r':
  129. str += '\r';
  130. break;
  131. case 't':
  132. str += '\t';
  133. break;
  134. case 'u':
  135. case 'x':
  136. restore = index;
  137. unescaped = scanHexEscape(ch);
  138. if (unescaped) {
  139. str += unescaped;
  140. } else {
  141. index = restore;
  142. str += ch;
  143. }
  144. break;
  145. case 'b':
  146. str += '\b';
  147. break;
  148. case 'f':
  149. str += '\f';
  150. break;
  151. case 'v':
  152. str += '\v';
  153. break;
  154. default:
  155. if (esutils.code.isOctalDigit(ch.charCodeAt(0))) {
  156. code = '01234567'.indexOf(ch);
  157. // \0 is not octal escape sequence
  158. // Deprecating unused code. TODO review removal
  159. //if (code !== 0) {
  160. // octal = true;
  161. //}
  162. if (index < length && esutils.code.isOctalDigit(source.charCodeAt(index))) {
  163. //TODO Review Removal octal = true;
  164. code = code * 8 + '01234567'.indexOf(advance());
  165. // 3 digits are only allowed when string starts
  166. // with 0, 1, 2, 3
  167. if ('0123'.indexOf(ch) >= 0 &&
  168. index < length &&
  169. esutils.code.isOctalDigit(source.charCodeAt(index))) {
  170. code = code * 8 + '01234567'.indexOf(advance());
  171. }
  172. }
  173. str += String.fromCharCode(code);
  174. } else {
  175. str += ch;
  176. }
  177. break;
  178. }
  179. } else {
  180. if (ch === '\r' && source.charCodeAt(index) === 0x0A /* '\n' */) {
  181. ++index;
  182. }
  183. }
  184. } else if (esutils.code.isLineTerminator(ch.charCodeAt(0))) {
  185. break;
  186. } else {
  187. str += ch;
  188. }
  189. }
  190. if (quote !== '') {
  191. utility.throwError('unexpected quote');
  192. }
  193. value = str;
  194. return Token.STRING;
  195. }
  196. function scanNumber() {
  197. var number, ch;
  198. number = '';
  199. ch = source.charCodeAt(index);
  200. if (ch !== 0x2E /* '.' */) {
  201. number = advance();
  202. ch = source.charCodeAt(index);
  203. if (number === '0') {
  204. if (ch === 0x78 /* 'x' */ || ch === 0x58 /* 'X' */) {
  205. number += advance();
  206. while (index < length) {
  207. ch = source.charCodeAt(index);
  208. if (!esutils.code.isHexDigit(ch)) {
  209. break;
  210. }
  211. number += advance();
  212. }
  213. if (number.length <= 2) {
  214. // only 0x
  215. utility.throwError('unexpected token');
  216. }
  217. if (index < length) {
  218. ch = source.charCodeAt(index);
  219. if (esutils.code.isIdentifierStartES5(ch)) {
  220. utility.throwError('unexpected token');
  221. }
  222. }
  223. value = parseInt(number, 16);
  224. return Token.NUMBER;
  225. }
  226. if (esutils.code.isOctalDigit(ch)) {
  227. number += advance();
  228. while (index < length) {
  229. ch = source.charCodeAt(index);
  230. if (!esutils.code.isOctalDigit(ch)) {
  231. break;
  232. }
  233. number += advance();
  234. }
  235. if (index < length) {
  236. ch = source.charCodeAt(index);
  237. if (esutils.code.isIdentifierStartES5(ch) || esutils.code.isDecimalDigit(ch)) {
  238. utility.throwError('unexpected token');
  239. }
  240. }
  241. value = parseInt(number, 8);
  242. return Token.NUMBER;
  243. }
  244. if (esutils.code.isDecimalDigit(ch)) {
  245. utility.throwError('unexpected token');
  246. }
  247. }
  248. while (index < length) {
  249. ch = source.charCodeAt(index);
  250. if (!esutils.code.isDecimalDigit(ch)) {
  251. break;
  252. }
  253. number += advance();
  254. }
  255. }
  256. if (ch === 0x2E /* '.' */) {
  257. number += advance();
  258. while (index < length) {
  259. ch = source.charCodeAt(index);
  260. if (!esutils.code.isDecimalDigit(ch)) {
  261. break;
  262. }
  263. number += advance();
  264. }
  265. }
  266. if (ch === 0x65 /* 'e' */ || ch === 0x45 /* 'E' */) {
  267. number += advance();
  268. ch = source.charCodeAt(index);
  269. if (ch === 0x2B /* '+' */ || ch === 0x2D /* '-' */) {
  270. number += advance();
  271. }
  272. ch = source.charCodeAt(index);
  273. if (esutils.code.isDecimalDigit(ch)) {
  274. number += advance();
  275. while (index < length) {
  276. ch = source.charCodeAt(index);
  277. if (!esutils.code.isDecimalDigit(ch)) {
  278. break;
  279. }
  280. number += advance();
  281. }
  282. } else {
  283. utility.throwError('unexpected token');
  284. }
  285. }
  286. if (index < length) {
  287. ch = source.charCodeAt(index);
  288. if (esutils.code.isIdentifierStartES5(ch)) {
  289. utility.throwError('unexpected token');
  290. }
  291. }
  292. value = parseFloat(number);
  293. return Token.NUMBER;
  294. }
  295. function scanTypeName() {
  296. var ch, ch2;
  297. value = advance();
  298. while (index < length && isTypeName(source.charCodeAt(index))) {
  299. ch = source.charCodeAt(index);
  300. if (ch === 0x2E /* '.' */) {
  301. if ((index + 1) >= length) {
  302. return Token.ILLEGAL;
  303. }
  304. ch2 = source.charCodeAt(index + 1);
  305. if (ch2 === 0x3C /* '<' */) {
  306. break;
  307. }
  308. }
  309. value += advance();
  310. }
  311. return Token.NAME;
  312. }
  313. function next() {
  314. var ch;
  315. previous = index;
  316. while (index < length && esutils.code.isWhiteSpace(source.charCodeAt(index))) {
  317. advance();
  318. }
  319. if (index >= length) {
  320. token = Token.EOF;
  321. return token;
  322. }
  323. ch = source.charCodeAt(index);
  324. switch (ch) {
  325. case 0x27: /* ''' */
  326. case 0x22: /* '"' */
  327. token = scanString();
  328. return token;
  329. case 0x3A: /* ':' */
  330. advance();
  331. token = Token.COLON;
  332. return token;
  333. case 0x2C: /* ',' */
  334. advance();
  335. token = Token.COMMA;
  336. return token;
  337. case 0x28: /* '(' */
  338. advance();
  339. token = Token.LPAREN;
  340. return token;
  341. case 0x29: /* ')' */
  342. advance();
  343. token = Token.RPAREN;
  344. return token;
  345. case 0x5B: /* '[' */
  346. advance();
  347. token = Token.LBRACK;
  348. return token;
  349. case 0x5D: /* ']' */
  350. advance();
  351. token = Token.RBRACK;
  352. return token;
  353. case 0x7B: /* '{' */
  354. advance();
  355. token = Token.LBRACE;
  356. return token;
  357. case 0x7D: /* '}' */
  358. advance();
  359. token = Token.RBRACE;
  360. return token;
  361. case 0x2E: /* '.' */
  362. if (index + 1 < length) {
  363. ch = source.charCodeAt(index + 1);
  364. if (ch === 0x3C /* '<' */) {
  365. advance(); // '.'
  366. advance(); // '<'
  367. token = Token.DOT_LT;
  368. return token;
  369. }
  370. if (ch === 0x2E /* '.' */ && index + 2 < length && source.charCodeAt(index + 2) === 0x2E /* '.' */) {
  371. advance(); // '.'
  372. advance(); // '.'
  373. advance(); // '.'
  374. token = Token.REST;
  375. return token;
  376. }
  377. if (esutils.code.isDecimalDigit(ch)) {
  378. token = scanNumber();
  379. return token;
  380. }
  381. }
  382. token = Token.ILLEGAL;
  383. return token;
  384. case 0x3C: /* '<' */
  385. advance();
  386. token = Token.LT;
  387. return token;
  388. case 0x3E: /* '>' */
  389. advance();
  390. token = Token.GT;
  391. return token;
  392. case 0x2A: /* '*' */
  393. advance();
  394. token = Token.STAR;
  395. return token;
  396. case 0x7C: /* '|' */
  397. advance();
  398. token = Token.PIPE;
  399. return token;
  400. case 0x3F: /* '?' */
  401. advance();
  402. token = Token.QUESTION;
  403. return token;
  404. case 0x21: /* '!' */
  405. advance();
  406. token = Token.BANG;
  407. return token;
  408. case 0x3D: /* '=' */
  409. advance();
  410. token = Token.EQUAL;
  411. return token;
  412. case 0x2D: /* '-' */
  413. token = scanNumber();
  414. return token;
  415. default:
  416. if (esutils.code.isDecimalDigit(ch)) {
  417. token = scanNumber();
  418. return token;
  419. }
  420. // type string permits following case,
  421. //
  422. // namespace.module.MyClass
  423. //
  424. // this reduced 1 token TK_NAME
  425. utility.assert(isTypeName(ch));
  426. token = scanTypeName();
  427. return token;
  428. }
  429. }
  430. function consume(target, text) {
  431. utility.assert(token === target, text || 'consumed token not matched');
  432. next();
  433. }
  434. function expect(target, message) {
  435. if (token !== target) {
  436. utility.throwError(message || 'unexpected token');
  437. }
  438. next();
  439. }
  440. // UnionType := '(' TypeUnionList ')'
  441. //
  442. // TypeUnionList :=
  443. // <<empty>>
  444. // | NonemptyTypeUnionList
  445. //
  446. // NonemptyTypeUnionList :=
  447. // TypeExpression
  448. // | TypeExpression '|' NonemptyTypeUnionList
  449. function parseUnionType() {
  450. var elements, startIndex = index - 1;
  451. consume(Token.LPAREN, 'UnionType should start with (');
  452. elements = [];
  453. if (token !== Token.RPAREN) {
  454. while (true) {
  455. elements.push(parseTypeExpression());
  456. if (token === Token.RPAREN) {
  457. break;
  458. }
  459. expect(Token.PIPE);
  460. }
  461. }
  462. consume(Token.RPAREN, 'UnionType should end with )');
  463. return maybeAddRange({
  464. type: Syntax.UnionType,
  465. elements: elements
  466. }, [startIndex, previous]);
  467. }
  468. // ArrayType := '[' ElementTypeList ']'
  469. //
  470. // ElementTypeList :=
  471. // <<empty>>
  472. // | TypeExpression
  473. // | '...' TypeExpression
  474. // | TypeExpression ',' ElementTypeList
  475. function parseArrayType() {
  476. var elements, startIndex = index - 1, restStartIndex;
  477. consume(Token.LBRACK, 'ArrayType should start with [');
  478. elements = [];
  479. while (token !== Token.RBRACK) {
  480. if (token === Token.REST) {
  481. restStartIndex = index - 3;
  482. consume(Token.REST);
  483. elements.push(maybeAddRange({
  484. type: Syntax.RestType,
  485. expression: parseTypeExpression()
  486. }, [restStartIndex, previous]));
  487. break;
  488. } else {
  489. elements.push(parseTypeExpression());
  490. }
  491. if (token !== Token.RBRACK) {
  492. expect(Token.COMMA);
  493. }
  494. }
  495. expect(Token.RBRACK);
  496. return maybeAddRange({
  497. type: Syntax.ArrayType,
  498. elements: elements
  499. }, [startIndex, previous]);
  500. }
  501. function parseFieldName() {
  502. var v = value;
  503. if (token === Token.NAME || token === Token.STRING) {
  504. next();
  505. return v;
  506. }
  507. if (token === Token.NUMBER) {
  508. consume(Token.NUMBER);
  509. return String(v);
  510. }
  511. utility.throwError('unexpected token');
  512. }
  513. // FieldType :=
  514. // FieldName
  515. // | FieldName ':' TypeExpression
  516. //
  517. // FieldName :=
  518. // NameExpression
  519. // | StringLiteral
  520. // | NumberLiteral
  521. // | ReservedIdentifier
  522. function parseFieldType() {
  523. var key, rangeStart = previous;
  524. key = parseFieldName();
  525. if (token === Token.COLON) {
  526. consume(Token.COLON);
  527. return maybeAddRange({
  528. type: Syntax.FieldType,
  529. key: key,
  530. value: parseTypeExpression()
  531. }, [rangeStart, previous]);
  532. }
  533. return maybeAddRange({
  534. type: Syntax.FieldType,
  535. key: key,
  536. value: null
  537. }, [rangeStart, previous]);
  538. }
  539. // RecordType := '{' FieldTypeList '}'
  540. //
  541. // FieldTypeList :=
  542. // <<empty>>
  543. // | FieldType
  544. // | FieldType ',' FieldTypeList
  545. function parseRecordType() {
  546. var fields, rangeStart = index - 1, rangeEnd;
  547. consume(Token.LBRACE, 'RecordType should start with {');
  548. fields = [];
  549. if (token === Token.COMMA) {
  550. consume(Token.COMMA);
  551. } else {
  552. while (token !== Token.RBRACE) {
  553. fields.push(parseFieldType());
  554. if (token !== Token.RBRACE) {
  555. expect(Token.COMMA);
  556. }
  557. }
  558. }
  559. rangeEnd = index;
  560. expect(Token.RBRACE);
  561. return maybeAddRange({
  562. type: Syntax.RecordType,
  563. fields: fields
  564. }, [rangeStart, rangeEnd]);
  565. }
  566. // NameExpression :=
  567. // Identifier
  568. // | TagIdentifier ':' Identifier
  569. //
  570. // Tag identifier is one of "module", "external" or "event"
  571. // Identifier is the same as Token.NAME, including any dots, something like
  572. // namespace.module.MyClass
  573. function parseNameExpression() {
  574. var name = value, rangeStart = index - name.length;
  575. expect(Token.NAME);
  576. if (token === Token.COLON && (
  577. name === 'module' ||
  578. name === 'external' ||
  579. name === 'event')) {
  580. consume(Token.COLON);
  581. name += ':' + value;
  582. expect(Token.NAME);
  583. }
  584. return maybeAddRange({
  585. type: Syntax.NameExpression,
  586. name: name
  587. }, [rangeStart, previous]);
  588. }
  589. // TypeExpressionList :=
  590. // TopLevelTypeExpression
  591. // | TopLevelTypeExpression ',' TypeExpressionList
  592. function parseTypeExpressionList() {
  593. var elements = [];
  594. elements.push(parseTop());
  595. while (token === Token.COMMA) {
  596. consume(Token.COMMA);
  597. elements.push(parseTop());
  598. }
  599. return elements;
  600. }
  601. // TypeName :=
  602. // NameExpression
  603. // | NameExpression TypeApplication
  604. //
  605. // TypeApplication :=
  606. // '.<' TypeExpressionList '>'
  607. // | '<' TypeExpressionList '>' // this is extension of doctrine
  608. function parseTypeName() {
  609. var expr, applications, startIndex = index - value.length;
  610. expr = parseNameExpression();
  611. if (token === Token.DOT_LT || token === Token.LT) {
  612. next();
  613. applications = parseTypeExpressionList();
  614. expect(Token.GT);
  615. return maybeAddRange({
  616. type: Syntax.TypeApplication,
  617. expression: expr,
  618. applications: applications
  619. }, [startIndex, previous]);
  620. }
  621. return expr;
  622. }
  623. // ResultType :=
  624. // <<empty>>
  625. // | ':' void
  626. // | ':' TypeExpression
  627. //
  628. // BNF is above
  629. // but, we remove <<empty>> pattern, so token is always TypeToken::COLON
  630. function parseResultType() {
  631. consume(Token.COLON, 'ResultType should start with :');
  632. if (token === Token.NAME && value === 'void') {
  633. consume(Token.NAME);
  634. return {
  635. type: Syntax.VoidLiteral
  636. };
  637. }
  638. return parseTypeExpression();
  639. }
  640. // ParametersType :=
  641. // RestParameterType
  642. // | NonRestParametersType
  643. // | NonRestParametersType ',' RestParameterType
  644. //
  645. // RestParameterType :=
  646. // '...'
  647. // '...' Identifier
  648. //
  649. // NonRestParametersType :=
  650. // ParameterType ',' NonRestParametersType
  651. // | ParameterType
  652. // | OptionalParametersType
  653. //
  654. // OptionalParametersType :=
  655. // OptionalParameterType
  656. // | OptionalParameterType, OptionalParametersType
  657. //
  658. // OptionalParameterType := ParameterType=
  659. //
  660. // ParameterType := TypeExpression | Identifier ':' TypeExpression
  661. //
  662. // Identifier is "new" or "this"
  663. function parseParametersType() {
  664. var params = [], optionalSequence = false, expr, rest = false, startIndex, restStartIndex = index - 3, nameStartIndex;
  665. while (token !== Token.RPAREN) {
  666. if (token === Token.REST) {
  667. // RestParameterType
  668. consume(Token.REST);
  669. rest = true;
  670. }
  671. startIndex = previous;
  672. expr = parseTypeExpression();
  673. if (expr.type === Syntax.NameExpression && token === Token.COLON) {
  674. nameStartIndex = previous - expr.name.length;
  675. // Identifier ':' TypeExpression
  676. consume(Token.COLON);
  677. expr = maybeAddRange({
  678. type: Syntax.ParameterType,
  679. name: expr.name,
  680. expression: parseTypeExpression()
  681. }, [nameStartIndex, previous]);
  682. }
  683. if (token === Token.EQUAL) {
  684. consume(Token.EQUAL);
  685. expr = maybeAddRange({
  686. type: Syntax.OptionalType,
  687. expression: expr
  688. }, [startIndex, previous]);
  689. optionalSequence = true;
  690. } else {
  691. if (optionalSequence) {
  692. utility.throwError('unexpected token');
  693. }
  694. }
  695. if (rest) {
  696. expr = maybeAddRange({
  697. type: Syntax.RestType,
  698. expression: expr
  699. }, [restStartIndex, previous]);
  700. }
  701. params.push(expr);
  702. if (token !== Token.RPAREN) {
  703. expect(Token.COMMA);
  704. }
  705. }
  706. return params;
  707. }
  708. // FunctionType := 'function' FunctionSignatureType
  709. //
  710. // FunctionSignatureType :=
  711. // | TypeParameters '(' ')' ResultType
  712. // | TypeParameters '(' ParametersType ')' ResultType
  713. // | TypeParameters '(' 'this' ':' TypeName ')' ResultType
  714. // | TypeParameters '(' 'this' ':' TypeName ',' ParametersType ')' ResultType
  715. function parseFunctionType() {
  716. var isNew, thisBinding, params, result, fnType, startIndex = index - value.length;
  717. utility.assert(token === Token.NAME && value === 'function', 'FunctionType should start with \'function\'');
  718. consume(Token.NAME);
  719. // Google Closure Compiler is not implementing TypeParameters.
  720. // So we do not. if we don't get '(', we see it as error.
  721. expect(Token.LPAREN);
  722. isNew = false;
  723. params = [];
  724. thisBinding = null;
  725. if (token !== Token.RPAREN) {
  726. // ParametersType or 'this'
  727. if (token === Token.NAME &&
  728. (value === 'this' || value === 'new')) {
  729. // 'this' or 'new'
  730. // 'new' is Closure Compiler extension
  731. isNew = value === 'new';
  732. consume(Token.NAME);
  733. expect(Token.COLON);
  734. thisBinding = parseTypeName();
  735. if (token === Token.COMMA) {
  736. consume(Token.COMMA);
  737. params = parseParametersType();
  738. }
  739. } else {
  740. params = parseParametersType();
  741. }
  742. }
  743. expect(Token.RPAREN);
  744. result = null;
  745. if (token === Token.COLON) {
  746. result = parseResultType();
  747. }
  748. fnType = maybeAddRange({
  749. type: Syntax.FunctionType,
  750. params: params,
  751. result: result
  752. }, [startIndex, previous]);
  753. if (thisBinding) {
  754. // avoid adding null 'new' and 'this' properties
  755. fnType['this'] = thisBinding;
  756. if (isNew) {
  757. fnType['new'] = true;
  758. }
  759. }
  760. return fnType;
  761. }
  762. // BasicTypeExpression :=
  763. // '*'
  764. // | 'null'
  765. // | 'undefined'
  766. // | TypeName
  767. // | FunctionType
  768. // | UnionType
  769. // | RecordType
  770. // | ArrayType
  771. function parseBasicTypeExpression() {
  772. var context, startIndex;
  773. switch (token) {
  774. case Token.STAR:
  775. consume(Token.STAR);
  776. return maybeAddRange({
  777. type: Syntax.AllLiteral
  778. }, [previous - 1, previous]);
  779. case Token.LPAREN:
  780. return parseUnionType();
  781. case Token.LBRACK:
  782. return parseArrayType();
  783. case Token.LBRACE:
  784. return parseRecordType();
  785. case Token.NAME:
  786. startIndex = index - value.length;
  787. if (value === 'null') {
  788. consume(Token.NAME);
  789. return maybeAddRange({
  790. type: Syntax.NullLiteral
  791. }, [startIndex, previous]);
  792. }
  793. if (value === 'undefined') {
  794. consume(Token.NAME);
  795. return maybeAddRange({
  796. type: Syntax.UndefinedLiteral
  797. }, [startIndex, previous]);
  798. }
  799. if (value === 'true' || value === 'false') {
  800. consume(Token.NAME);
  801. return maybeAddRange({
  802. type: Syntax.BooleanLiteralType,
  803. value: value === 'true'
  804. }, [startIndex, previous]);
  805. }
  806. context = Context.save();
  807. if (value === 'function') {
  808. try {
  809. return parseFunctionType();
  810. } catch (e) {
  811. context.restore();
  812. }
  813. }
  814. return parseTypeName();
  815. case Token.STRING:
  816. next();
  817. return maybeAddRange({
  818. type: Syntax.StringLiteralType,
  819. value: value
  820. }, [previous - value.length - 2, previous]);
  821. case Token.NUMBER:
  822. next();
  823. return maybeAddRange({
  824. type: Syntax.NumericLiteralType,
  825. value: value
  826. }, [previous - String(value).length, previous]);
  827. default:
  828. utility.throwError('unexpected token');
  829. }
  830. }
  831. // TypeExpression :=
  832. // BasicTypeExpression
  833. // | '?' BasicTypeExpression
  834. // | '!' BasicTypeExpression
  835. // | BasicTypeExpression '?'
  836. // | BasicTypeExpression '!'
  837. // | '?'
  838. // | BasicTypeExpression '[]'
  839. function parseTypeExpression() {
  840. var expr, rangeStart;
  841. if (token === Token.QUESTION) {
  842. rangeStart = index - 1;
  843. consume(Token.QUESTION);
  844. if (token === Token.COMMA || token === Token.EQUAL || token === Token.RBRACE ||
  845. token === Token.RPAREN || token === Token.PIPE || token === Token.EOF ||
  846. token === Token.RBRACK || token === Token.GT) {
  847. return maybeAddRange({
  848. type: Syntax.NullableLiteral
  849. }, [rangeStart, previous]);
  850. }
  851. return maybeAddRange({
  852. type: Syntax.NullableType,
  853. expression: parseBasicTypeExpression(),
  854. prefix: true
  855. }, [rangeStart, previous]);
  856. } else if (token === Token.BANG) {
  857. rangeStart = index - 1;
  858. consume(Token.BANG);
  859. return maybeAddRange({
  860. type: Syntax.NonNullableType,
  861. expression: parseBasicTypeExpression(),
  862. prefix: true
  863. }, [rangeStart, previous]);
  864. } else {
  865. rangeStart = previous;
  866. }
  867. expr = parseBasicTypeExpression();
  868. if (token === Token.BANG) {
  869. consume(Token.BANG);
  870. return maybeAddRange({
  871. type: Syntax.NonNullableType,
  872. expression: expr,
  873. prefix: false
  874. }, [rangeStart, previous]);
  875. }
  876. if (token === Token.QUESTION) {
  877. consume(Token.QUESTION);
  878. return maybeAddRange({
  879. type: Syntax.NullableType,
  880. expression: expr,
  881. prefix: false
  882. }, [rangeStart, previous]);
  883. }
  884. if (token === Token.LBRACK) {
  885. consume(Token.LBRACK);
  886. expect(Token.RBRACK, 'expected an array-style type declaration (' + value + '[])');
  887. return maybeAddRange({
  888. type: Syntax.TypeApplication,
  889. expression: maybeAddRange({
  890. type: Syntax.NameExpression,
  891. name: 'Array'
  892. }, [rangeStart, previous]),
  893. applications: [expr]
  894. }, [rangeStart, previous]);
  895. }
  896. return expr;
  897. }
  898. // TopLevelTypeExpression :=
  899. // TypeExpression
  900. // | TypeUnionList
  901. //
  902. // This rule is Google Closure Compiler extension, not ES4
  903. // like,
  904. // { number | string }
  905. // If strict to ES4, we should write it as
  906. // { (number|string) }
  907. function parseTop() {
  908. var expr, elements;
  909. expr = parseTypeExpression();
  910. if (token !== Token.PIPE) {
  911. return expr;
  912. }
  913. elements = [expr];
  914. consume(Token.PIPE);
  915. while (true) {
  916. elements.push(parseTypeExpression());
  917. if (token !== Token.PIPE) {
  918. break;
  919. }
  920. consume(Token.PIPE);
  921. }
  922. return maybeAddRange({
  923. type: Syntax.UnionType,
  924. elements: elements
  925. }, [0, index]);
  926. }
  927. function parseTopParamType() {
  928. var expr;
  929. if (token === Token.REST) {
  930. consume(Token.REST);
  931. return maybeAddRange({
  932. type: Syntax.RestType,
  933. expression: parseTop()
  934. }, [0, index]);
  935. }
  936. expr = parseTop();
  937. if (token === Token.EQUAL) {
  938. consume(Token.EQUAL);
  939. return maybeAddRange({
  940. type: Syntax.OptionalType,
  941. expression: expr
  942. }, [0, index]);
  943. }
  944. return expr;
  945. }
  946. function parseType(src, opt) {
  947. var expr;
  948. source = src;
  949. length = source.length;
  950. index = 0;
  951. previous = 0;
  952. addRange = opt && opt.range;
  953. rangeOffset = opt && opt.startIndex || 0;
  954. next();
  955. expr = parseTop();
  956. if (opt && opt.midstream) {
  957. return {
  958. expression: expr,
  959. index: previous
  960. };
  961. }
  962. if (token !== Token.EOF) {
  963. utility.throwError('not reach to EOF');
  964. }
  965. return expr;
  966. }
  967. function parseParamType(src, opt) {
  968. var expr;
  969. source = src;
  970. length = source.length;
  971. index = 0;
  972. previous = 0;
  973. addRange = opt && opt.range;
  974. rangeOffset = opt && opt.startIndex || 0;
  975. next();
  976. expr = parseTopParamType();
  977. if (opt && opt.midstream) {
  978. return {
  979. expression: expr,
  980. index: previous
  981. };
  982. }
  983. if (token !== Token.EOF) {
  984. utility.throwError('not reach to EOF');
  985. }
  986. return expr;
  987. }
  988. function stringifyImpl(node, compact, topLevel) {
  989. var result, i, iz;
  990. switch (node.type) {
  991. case Syntax.NullableLiteral:
  992. result = '?';
  993. break;
  994. case Syntax.AllLiteral:
  995. result = '*';
  996. break;
  997. case Syntax.NullLiteral:
  998. result = 'null';
  999. break;
  1000. case Syntax.UndefinedLiteral:
  1001. result = 'undefined';
  1002. break;
  1003. case Syntax.VoidLiteral:
  1004. result = 'void';
  1005. break;
  1006. case Syntax.UnionType:
  1007. if (!topLevel) {
  1008. result = '(';
  1009. } else {
  1010. result = '';
  1011. }
  1012. for (i = 0, iz = node.elements.length; i < iz; ++i) {
  1013. result += stringifyImpl(node.elements[i], compact);
  1014. if ((i + 1) !== iz) {
  1015. result += compact ? '|' : ' | ';
  1016. }
  1017. }
  1018. if (!topLevel) {
  1019. result += ')';
  1020. }
  1021. break;
  1022. case Syntax.ArrayType:
  1023. result = '[';
  1024. for (i = 0, iz = node.elements.length; i < iz; ++i) {
  1025. result += stringifyImpl(node.elements[i], compact);
  1026. if ((i + 1) !== iz) {
  1027. result += compact ? ',' : ', ';
  1028. }
  1029. }
  1030. result += ']';
  1031. break;
  1032. case Syntax.RecordType:
  1033. result = '{';
  1034. for (i = 0, iz = node.fields.length; i < iz; ++i) {
  1035. result += stringifyImpl(node.fields[i], compact);
  1036. if ((i + 1) !== iz) {
  1037. result += compact ? ',' : ', ';
  1038. }
  1039. }
  1040. result += '}';
  1041. break;
  1042. case Syntax.FieldType:
  1043. if (node.value) {
  1044. result = node.key + (compact ? ':' : ': ') + stringifyImpl(node.value, compact);
  1045. } else {
  1046. result = node.key;
  1047. }
  1048. break;
  1049. case Syntax.FunctionType:
  1050. result = compact ? 'function(' : 'function (';
  1051. if (node['this']) {
  1052. if (node['new']) {
  1053. result += (compact ? 'new:' : 'new: ');
  1054. } else {
  1055. result += (compact ? 'this:' : 'this: ');
  1056. }
  1057. result += stringifyImpl(node['this'], compact);
  1058. if (node.params.length !== 0) {
  1059. result += compact ? ',' : ', ';
  1060. }
  1061. }
  1062. for (i = 0, iz = node.params.length; i < iz; ++i) {
  1063. result += stringifyImpl(node.params[i], compact);
  1064. if ((i + 1) !== iz) {
  1065. result += compact ? ',' : ', ';
  1066. }
  1067. }
  1068. result += ')';
  1069. if (node.result) {
  1070. result += (compact ? ':' : ': ') + stringifyImpl(node.result, compact);
  1071. }
  1072. break;
  1073. case Syntax.ParameterType:
  1074. result = node.name + (compact ? ':' : ': ') + stringifyImpl(node.expression, compact);
  1075. break;
  1076. case Syntax.RestType:
  1077. result = '...';
  1078. if (node.expression) {
  1079. result += stringifyImpl(node.expression, compact);
  1080. }
  1081. break;
  1082. case Syntax.NonNullableType:
  1083. if (node.prefix) {
  1084. result = '!' + stringifyImpl(node.expression, compact);
  1085. } else {
  1086. result = stringifyImpl(node.expression, compact) + '!';
  1087. }
  1088. break;
  1089. case Syntax.OptionalType:
  1090. result = stringifyImpl(node.expression, compact) + '=';
  1091. break;
  1092. case Syntax.NullableType:
  1093. if (node.prefix) {
  1094. result = '?' + stringifyImpl(node.expression, compact);
  1095. } else {
  1096. result = stringifyImpl(node.expression, compact) + '?';
  1097. }
  1098. break;
  1099. case Syntax.NameExpression:
  1100. result = node.name;
  1101. break;
  1102. case Syntax.TypeApplication:
  1103. result = stringifyImpl(node.expression, compact) + '.<';
  1104. for (i = 0, iz = node.applications.length; i < iz; ++i) {
  1105. result += stringifyImpl(node.applications[i], compact);
  1106. if ((i + 1) !== iz) {
  1107. result += compact ? ',' : ', ';
  1108. }
  1109. }
  1110. result += '>';
  1111. break;
  1112. case Syntax.StringLiteralType:
  1113. result = '"' + node.value + '"';
  1114. break;
  1115. case Syntax.NumericLiteralType:
  1116. result = String(node.value);
  1117. break;
  1118. case Syntax.BooleanLiteralType:
  1119. result = String(node.value);
  1120. break;
  1121. default:
  1122. utility.throwError('Unknown type ' + node.type);
  1123. }
  1124. return result;
  1125. }
  1126. function stringify(node, options) {
  1127. if (options == null) {
  1128. options = {};
  1129. }
  1130. return stringifyImpl(node, options.compact, options.topLevel);
  1131. }
  1132. exports.parseType = parseType;
  1133. exports.parseParamType = parseParamType;
  1134. exports.stringify = stringify;
  1135. exports.Syntax = Syntax;
  1136. }());
  1137. /* vim: set sw=4 ts=4 et tw=80 : */