magicscript.js 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371
  1. function Span(source, start, end) {
  2. if (source instanceof Span && start instanceof Span) {
  3. this.source = source.source;
  4. this.start = source.start;
  5. this.end = start.end;
  6. this.cachedText = this.source.substring(this.start, this.end);
  7. } else {
  8. this.source = source;
  9. this.start = start || 0;
  10. this.end = end || source.length;
  11. this.cachedText = source.substring(this.start, this.end);
  12. }
  13. }
  14. Span.prototype.getText = function () {
  15. return this.cachedText;
  16. }
  17. Span.prototype.getSource = function () {
  18. return this.source;
  19. }
  20. Span.prototype.getStart = function () {
  21. return this.start;
  22. }
  23. Span.prototype.getEnd = function () {
  24. return this.end;
  25. }
  26. Span.prototype.toString = function () {
  27. return "Span [text=" + this.getText() + ", start=" + this.start + ", end=" + this.end + "]";
  28. ;
  29. }
  30. function throwError() {
  31. var message = '';
  32. var span;
  33. for (var i = 0, len = arguments.length; i < len; i++) {
  34. var value = arguments[i];
  35. if (value instanceof Span) {
  36. span = value
  37. } else {
  38. message += value + ' ';
  39. }
  40. }
  41. throw {message: message, span: span};
  42. }
  43. function CharacterStream(source, start, end) {
  44. this.index = start === undefined ? 0 : start;
  45. this.end = end === undefined ? source.length : end;
  46. this.source = source;
  47. this.spanStart = 0;
  48. }
  49. CharacterStream.prototype.hasMore = function () {
  50. return this.index < this.end;
  51. }
  52. CharacterStream.prototype.consume = function () {
  53. return this.source.charAt(this.index++);
  54. }
  55. CharacterStream.prototype.match = function (needle, consume) {
  56. if (typeof needle !== 'string') {
  57. needle = needle.literal;
  58. }
  59. var needleLength = needle.length;
  60. if (needleLength + this.index > this.end) {
  61. return false;
  62. }
  63. for (var i = 0, j = this.index; i < needleLength; i++, j++) {
  64. if (this.index >= this.end) return false;
  65. if (needle.charAt(i) != this.source.charAt(j)) return false;
  66. }
  67. if (consume) this.index += needleLength;
  68. return true;
  69. }
  70. CharacterStream.prototype.matchDigit = function (consume) {
  71. if (this.index >= this.end) return false;
  72. var c = this.source.charAt(this.index);
  73. if (!isNaN(c)) {
  74. if (consume) this.index++;
  75. return true;
  76. }
  77. return false;
  78. }
  79. CharacterStream.prototype.matchIdentifierStart = function (consume) {
  80. if (this.index >= this.end) return false;
  81. var c = this.source.charAt(this.index);
  82. if (c.match(/\w/) || c == '$' || c == '_' || c == '@') {
  83. if (consume) this.index++;
  84. return true;
  85. }
  86. return false;
  87. }
  88. CharacterStream.prototype.matchIdentifierPart = function (consume) {
  89. if (this.index >= this.end) return false;
  90. var c = this.source.charAt(this.index);
  91. if (c.match(/\w/) || c == '$' || c == '_') {
  92. if (consume) this.index++;
  93. return true;
  94. }
  95. return false;
  96. }
  97. CharacterStream.prototype.skipWhiteSpace = function (consume) {
  98. while (true) {
  99. if (this.index >= this.end) return;
  100. var c = this.source.charAt(this.index);
  101. if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
  102. this.index++;
  103. continue;
  104. } else {
  105. break;
  106. }
  107. }
  108. }
  109. CharacterStream.prototype.getSpan = function (start, end) {
  110. return new Span(this.source, start, end);
  111. }
  112. CharacterStream.prototype.skipLine = function () {
  113. while (true) {
  114. if (this.index >= this.end) {
  115. return;
  116. }
  117. if (this.source.charAt(this.index++) == '\n') {
  118. break;
  119. }
  120. }
  121. }
  122. CharacterStream.prototype.skipUntil = function (chars) {
  123. while (true) {
  124. if (this.index >= this.end) {
  125. return;
  126. }
  127. var matched = true;
  128. for (var i = 0, len = chars.length; i < len && this.index + i < this.end; i++) {
  129. if (chars.charAt(i) != this.source.charAt(this.index + i)) {
  130. matched = false;
  131. break;
  132. }
  133. }
  134. this.index += matched ? chars.length : 1;
  135. if (matched) {
  136. break;
  137. }
  138. }
  139. }
  140. CharacterStream.prototype.startSpan = function () {
  141. this.spanStart = this.index;
  142. }
  143. CharacterStream.prototype.endSpan = function () {
  144. return new Span(this.source, this.spanStart, this.index);
  145. }
  146. CharacterStream.prototype.getPosition = function () {
  147. return this.index;
  148. }
  149. function Token(tokenType, span) {
  150. this.type = tokenType;
  151. this.span = span;
  152. }
  153. Token.prototype.getTokenType = function () {
  154. return this.type;
  155. }
  156. Token.prototype.getSpan = function () {
  157. return this.span;
  158. }
  159. Token.prototype.getText = function () {
  160. return this.span.getText();
  161. }
  162. var TokenType = {
  163. Period: {literal: '.', error: '.'},
  164. Lambda: {literal: '=>', error: '->'},
  165. Comma: {literal: ',', error: ','},
  166. Semicolon: {literal: ';', error: ';'},
  167. Colon: {literal: ':', error: ':'},
  168. Plus: {literal: '+', error: '+'},
  169. Minus: {literal: '-', error: '-'},
  170. Asterisk: {literal: '*', error: '*'},
  171. ForwardSlash: {literal: '/', error: '/'},
  172. PostSlash: {literal: '\\', error: '\\'},
  173. Percentage: {literal: '%', error: '%'},
  174. LeftParantheses: {literal: '(', error: '('},
  175. RightParantheses: {literal: ')', error: ')'},
  176. LeftBracket: {literal: '[', error: '['},
  177. RightBracket: {literal: ']', error: ']'},
  178. LeftCurly: {literal: '{', error: '{'},
  179. RightCurly: {error: '}'},// 特殊待遇!
  180. Less: {literal: '<', error: '<'},
  181. Greater: {literal: '>', error: '>'},
  182. LessEqual: {literal: '<=', error: '<='},
  183. GreaterEqual: {literal: '>=', error: '>='},
  184. Equal: {literal: '==', error: '=='},
  185. NotEqual: {literal: '!=', error: '!='},
  186. Assignment: {literal: '=', error: '='},
  187. And: {literal: '&&', error: '&&'},
  188. Or: {literal: '||', error: '||'},
  189. Xor: {literal: '^', error: '^'},
  190. Not: {literal: '!', error: '!'},
  191. Questionmark: {literal: '?', error: '?'},
  192. DoubleQuote: {literal: '"', error: '"'},
  193. SingleQuote: {literal: '\'', error: '\''},
  194. BooleanLiteral: {error: 'true 或 false'},
  195. DoubleLiteral: {error: '一个 double 类型数值'},
  196. FloatLiteral: {error: '一个 float 类型数值'},
  197. LongLiteral: {error: '一个 long 类型数值'},
  198. IntegerLiteral: {error: '一个 int 类型数值'},
  199. ShortLiteral: {error: '一个 short 类型数值'},
  200. ByteLiteral: {error: '一个 byte 类型数据'},
  201. CharacterLiteral: {error: '一个 char 类型数据'},
  202. StringLiteral: {error: '一个 字符串'},
  203. NullLiteral: {error: 'null'},
  204. Identifier: {error: '标识符'}
  205. };
  206. var tokenTypeValues = Object.getOwnPropertyNames(TokenType).map(e => TokenType[e]);
  207. TokenType.getSortedValues = function () {
  208. if (this.values) {
  209. return this.values;
  210. }
  211. this.values = tokenTypeValues.sort(function (o1, o2) {
  212. if (!o1.literal && !o2.literal) {
  213. return 0;
  214. }
  215. if (!o1.literal && !!o2.literal) {
  216. return 1;
  217. }
  218. if (!!o1.literal && !o2.literal) {
  219. return -1;
  220. }
  221. return o2.literal.length - o1.literal.length;
  222. })
  223. return this.values;
  224. }
  225. function TokenStream(tokens) {
  226. this.tokens = tokens;
  227. this.index = 0;
  228. this.end = tokens.length;
  229. }
  230. TokenStream.prototype.hasMore = function () {
  231. return this.index < this.end;
  232. }
  233. TokenStream.prototype.hasNext = function () {
  234. return this.index + 1 < this.end;
  235. }
  236. TokenStream.prototype.makeIndex = function () {
  237. return this.index;
  238. }
  239. TokenStream.prototype.resetIndex = function (index) {
  240. this.index = index;
  241. }
  242. TokenStream.prototype.getToken = function (consume) {
  243. var token = this.tokens[this.index];
  244. if (consume) {
  245. this.index++;
  246. }
  247. return token;
  248. }
  249. TokenStream.prototype.consume = function () {
  250. if (!this.hasMore()) {
  251. throwError('Reached the end of the source.')
  252. }
  253. return this.tokens[this.index++];
  254. }
  255. TokenStream.prototype.next = function () {
  256. if (!this.hasMore()) {
  257. throwError('Reached the end of the source.')
  258. }
  259. return this.tokens[++this.index];
  260. }
  261. TokenStream.prototype.prev = function () {
  262. if (this.index == 0) {
  263. throwError('Reached the end of the source.')
  264. }
  265. return this.tokens[--this.index];
  266. }
  267. TokenStream.prototype.getPrev = function () {
  268. if (this.index == 0) {
  269. throwError('Reached the end of the source.')
  270. }
  271. return this.tokens[this.index - 1];
  272. }
  273. TokenStream.prototype.match = function (tokenOrText, consume) {
  274. if (this.index >= this.end) {
  275. return false;
  276. }
  277. var match = false;
  278. if (Array.isArray(tokenOrText)) {
  279. for (var i = 0, len = tokenOrText.length; i < len; i++) {
  280. if (this.match(tokenOrText[i], consume)) {
  281. return true;
  282. }
  283. }
  284. } else if (typeof tokenOrText == 'string') {
  285. if (this.tokens[this.index].getText() == tokenOrText) {
  286. match = true
  287. }
  288. } else {
  289. if (this.tokens[this.index].type == tokenOrText) {
  290. match = true
  291. }
  292. }
  293. if (match && consume) {
  294. this.index++;
  295. }
  296. return match;
  297. }
  298. TokenStream.prototype.expect = function (text) {
  299. if (this.match(text, true)) {
  300. return this.tokens[this.index - 1];
  301. } else {
  302. var token = this.index < this.tokens.length ? this.tokens[this.index] : null;
  303. var span = token != null ? token.getSpan() : null;
  304. if (span == null) {
  305. throwError("Expected '" + text + "', but reached the end of the source.")
  306. } else {
  307. if (text instanceof Token) {
  308. text = text.type.error;
  309. }
  310. throw new Error();
  311. throwError("Expected '" + text + "', but got '" + token.getText() + "'", span)
  312. }
  313. }
  314. }
  315. TokenStream.prototype.getSource = function () {
  316. if (this.tokens.length == 0) {
  317. return null;
  318. }
  319. return this.tokens[0].getSpan().getSource();
  320. }
  321. var Parser = {
  322. scriptClass: {},
  323. tokenize: function (source) {
  324. var stream = new CharacterStream(source, 0, source.length);
  325. var tokens = [];
  326. var leftCount = 0;
  327. var rightCount = 0;
  328. while (stream.hasMore()) {
  329. stream.skipWhiteSpace();
  330. if (stream.match("//", true)) { //注释
  331. stream.skipLine();
  332. continue;
  333. }
  334. if (stream.match("/*", true)) { //多行注释
  335. stream.skipUntil("*/");
  336. continue;
  337. }
  338. if (stream.matchDigit(false)) {
  339. var type = TokenType.IntegerLiteral;
  340. stream.startSpan();
  341. while (stream.matchDigit(true)) {
  342. ;
  343. }
  344. if (stream.match(TokenType.Period.literal, true)) {
  345. type = TokenType.FloatLiteral;
  346. while (stream.matchDigit(true)) {
  347. ;
  348. }
  349. }
  350. if (stream.match("b", true) || stream.match("B", true)) {
  351. if (type == TokenType.FloatLiteral) {
  352. throwError("Byte literal can not have a decimal point.", stream.endSpan());
  353. }
  354. type = TokenType.ByteLiteral;
  355. } else if (stream.match("s", true) || stream.match("S", true)) {
  356. if (type == TokenType.FloatLiteral) {
  357. throwError("Short literal can not have a decimal point.", stream.endSpan());
  358. }
  359. type = TokenType.ShortLiteral;
  360. } else if (stream.match("l", true) || stream.match("L", true)) {
  361. if (type == TokenType.FloatLiteral) {
  362. throwError("Long literal can not have a decimal point.", stream.endSpan());
  363. }
  364. type = TokenType.LongLiteral;
  365. } else if (stream.match("f", true) || stream.match("F", true)) {
  366. type = TokenType.FloatLiteral;
  367. } else if (stream.match("d", true) || stream.match("D", true)) {
  368. type = TokenType.DoubleLiteral;
  369. }
  370. tokens.push(new Token(type, stream.endSpan()));
  371. continue;
  372. }
  373. // String literal
  374. if (stream.match(TokenType.SingleQuote.literal, true)) {
  375. stream.startSpan();
  376. var matchedEndQuote = false;
  377. while (stream.hasMore()) {
  378. // Note: escape sequences like \n are parsed in StringLiteral
  379. if (stream.match("\\", true)) {
  380. stream.consume();
  381. continue;
  382. }
  383. if (stream.match(TokenType.SingleQuote.literal, true)) {
  384. matchedEndQuote = true;
  385. break;
  386. }
  387. var ch = stream.consume();
  388. if(ch == '\r' || ch == '\n'){
  389. throwError("''定义的字符串不能换行", stream.endSpan());
  390. }
  391. }
  392. if (!matchedEndQuote) {
  393. throwError("字符串没有结束符\'", stream.endSpan());
  394. }
  395. var stringSpan = stream.endSpan();
  396. stringSpan = stream.getSpan(stringSpan.getStart() - 1, stringSpan.getEnd());
  397. tokens.push(new Token(TokenType.StringLiteral, stringSpan));
  398. continue;
  399. }
  400. // String literal
  401. if (stream.match('"""', true)) {
  402. stream.startSpan();
  403. var matchedEndQuote = false;
  404. while (stream.hasMore()) {
  405. // Note: escape sequences like \n are parsed in StringLiteral
  406. if (stream.match("\\", true)) {
  407. stream.consume();
  408. continue;
  409. }
  410. if (stream.match('"""', true)) {
  411. matchedEndQuote = true;
  412. break;
  413. }
  414. stream.consume();
  415. }
  416. if (!matchedEndQuote) {
  417. throwError('多行字符串没有结束符"""', stream.endSpan());
  418. }
  419. var stringSpan = stream.endSpan();
  420. stringSpan = stream.getSpan(stringSpan.getStart() - 1, stringSpan.getEnd() - 2);
  421. tokens.push(new Token(TokenType.StringLiteral, stringSpan));
  422. continue;
  423. }
  424. // String literal
  425. if (stream.match(TokenType.DoubleQuote.literal, true)) {
  426. stream.startSpan();
  427. var matchedEndQuote = false;
  428. while (stream.hasMore()) {
  429. // Note: escape sequences like \n are parsed in StringLiteral
  430. if (stream.match("\\", true)) {
  431. stream.consume();
  432. continue;
  433. }
  434. if (stream.match(TokenType.DoubleQuote.literal, true)) {
  435. matchedEndQuote = true;
  436. break;
  437. }
  438. var ch = stream.consume();
  439. if(ch == '\r' || ch == '\n'){
  440. throwError('"定义的字符串不能换行', stream.endSpan());
  441. }
  442. }
  443. if (!matchedEndQuote) {
  444. throwError("字符串没有结束符\"", stream.endSpan());
  445. }
  446. var stringSpan = stream.endSpan();
  447. stringSpan = stream.getSpan(stringSpan.getStart() - 1, stringSpan.getEnd());
  448. tokens.push(new Token(TokenType.StringLiteral, stringSpan));
  449. continue;
  450. }
  451. // Identifier, keyword, boolean literal, or null literal
  452. if (stream.matchIdentifierStart(true)) {
  453. stream.startSpan();
  454. while (stream.matchIdentifierPart(true)) {
  455. ;
  456. }
  457. var identifierSpan = stream.endSpan();
  458. identifierSpan = stream.getSpan(identifierSpan.getStart() - 1, identifierSpan.getEnd());
  459. if ("true" == (identifierSpan.getText()) || "false" == (identifierSpan.getText())) {
  460. tokens.push(new Token(TokenType.BooleanLiteral, identifierSpan));
  461. } else if ("null" == (identifierSpan.getText())) {
  462. tokens.push(new Token(TokenType.NullLiteral, identifierSpan));
  463. } else {
  464. tokens.push(new Token(TokenType.Identifier, identifierSpan));
  465. }
  466. continue;
  467. }
  468. var continueOuter = false;
  469. // Simple tokens
  470. var values = TokenType.getSortedValues();
  471. for (var i = 0, len = values.length; i < len; i++) {
  472. var t = values[i];
  473. if (t.literal != null) {
  474. if (stream.match(t.literal, true)) {
  475. if (t == TokenType.LeftCurly) {
  476. leftCount++;
  477. }
  478. tokens.push(new Token(t, stream.getSpan(stream.getPosition() - t.literal.length, stream.getPosition())));
  479. continueOuter = true;
  480. break;
  481. }
  482. }
  483. }
  484. if (continueOuter) {
  485. continue;
  486. }
  487. if (leftCount != rightCount && stream.match("}", true)) {
  488. rightCount++;
  489. tokens.push(new Token(TokenType.RightCurly, stream.getSpan(stream.getPosition() - 1, stream.getPosition())));
  490. continueOuter = true;
  491. }
  492. if (continueOuter) {
  493. continue;
  494. }
  495. if (stream.hasMore()) {
  496. throwError("Unknown token", stream.getSpan(stream.getPosition(), stream.getPosition() + 1));
  497. }
  498. }
  499. return tokens;
  500. },
  501. getSimpleClass: function (target) {
  502. var index = target.lastIndexOf('.')
  503. if (index > -1) {
  504. return target.substring(index + 1);
  505. }
  506. return target;
  507. },
  508. getWrapperClass: function (target) {
  509. if (target == 'int' || target == 'java.lang.Integer') {
  510. return 'java.lang.Integer';
  511. }
  512. if (target == 'string' || target == 'java.lang.String') {
  513. return 'java.lang.String';
  514. }
  515. if (target == 'double' || target == 'java.lang.Double') {
  516. return 'java.lang.Double';
  517. }
  518. if (target == 'float' || target == 'java.lang.Float') {
  519. return 'java.lang.Float';
  520. }
  521. if (target == 'byte' || target == 'java.lang.Byte') {
  522. return 'java.lang.Byte';
  523. }
  524. if (target == 'short' || target == 'java.lang.Short') {
  525. return 'java.lang.Short';
  526. }
  527. if (target == 'long' || target == 'java.lang.Long') {
  528. return 'java.lang.Long';
  529. }
  530. if (target.indexOf('[]') > -1) {
  531. return 'Object[]';
  532. }
  533. return target || 'java.lang.Object';
  534. },
  535. parse: function (stream) {
  536. try{
  537. var vars = {
  538. db: 'org.ssssssss.magicapi.functions.DatabaseQuery'
  539. };
  540. var expression;
  541. while (stream.hasMore()) {
  542. var token = stream.consume();
  543. if (token.type == TokenType.Identifier && token.getText() == 'var') {
  544. var varName = stream.consume().getText();
  545. if (stream.match(TokenType.Assignment, true)) {
  546. var value = this.parseStatement(stream);
  547. vars[varName] = value.getJavaType(vars);
  548. if (!stream.hasMore()) {
  549. expression = value;
  550. }
  551. }
  552. } else if (token.type == TokenType.Identifier && token.getText() == 'import') {
  553. var varName;
  554. var value;
  555. if (stream.match(TokenType.Identifier, false)) {
  556. varName = stream.consume().getText();
  557. value = varName;
  558. } else if (stream.match(TokenType.StringLiteral, false)) {
  559. value = stream.consume().getText();
  560. value = value.substring(1, value.length - 1);
  561. }
  562. if (stream.match('as', true)) {
  563. varName = stream.consume().getText();
  564. }
  565. if (Parser.scriptClass[value] === undefined) {
  566. MagicEditor.ajax({
  567. url: 'class',
  568. data: {
  569. className: value
  570. },
  571. success: function (list) {
  572. Parser.scriptClass[value] = null;
  573. for (var i = 0, len = list.length; i < len; i++) {
  574. var item = list[i];
  575. Parser.scriptClass[item.className] = item;
  576. }
  577. }
  578. })
  579. }
  580. if (varName) {
  581. vars[varName] = value;
  582. }
  583. } else if (token.type == TokenType.Assignment) {
  584. var varName = stream.getPrev().getText()
  585. var value = this.parseStatement(stream);
  586. vars[varName] = value.getJavaType(vars);
  587. if (!stream.hasMore()) {
  588. expression = value;
  589. }
  590. } else if (token.type == TokenType.Identifier) {
  591. var index = stream.makeIndex();
  592. stream.prev();
  593. try {
  594. expression = this.parseAccessOrCall(stream, token.type);
  595. } catch (e) {
  596. expression = null;
  597. stream.resetIndex(index);
  598. }
  599. }
  600. }
  601. return expression && expression.getJavaType(vars);
  602. }catch(e){
  603. return '';
  604. }
  605. },
  606. parseStatement: function (tokens, expectRightCurly) {
  607. var result = null;
  608. if (tokens.match("import", false)) {
  609. result = this.parseImport(tokens);
  610. } else if (tokens.match("var", false)) {
  611. result = this.parseVarDefine(tokens);
  612. } else if (tokens.match("if", false)) {
  613. result = this.parseIfStatement(tokens);
  614. } else if (tokens.match("return", false)) {
  615. result = this.parseReturn(tokens);
  616. } else if (tokens.match("for", false)) {
  617. result = this.parseForStatement(tokens);
  618. } else if (tokens.match("continue", false)) {
  619. result = new AST.Continue(tokens.consume().getSpan());
  620. } else if (tokens.match("break", false)) {
  621. result = new AST.Break(tokens.consume().getSpan());
  622. } else {
  623. result = this.parseExpression(tokens, expectRightCurly);
  624. }
  625. // consume semi-colons as statement delimiters
  626. while (tokens.match(";", true)) {
  627. ;
  628. }
  629. return result;
  630. },
  631. parseReturn : function(stream){
  632. stream.expect("return");
  633. if (stream.match(";", false)) return new AST.Return(null);
  634. return new AST.Return(this.parseExpression(stream));
  635. },
  636. parseImport: function (stream) {
  637. var opening = stream.expect("import").getSpan();
  638. if (stream.hasMore()) {
  639. var expected = stream.consume();
  640. var packageName = null;
  641. var isStringLiteral = expected.getType() == TokenType.StringLiteral;
  642. if (isStringLiteral) {
  643. packageName = new AST.TypeLiteral('string', expected.getSpan()).getValue();
  644. } else if (expected.getType() == TokenType.Identifier) {
  645. packageName = expected.getSpan().getText();
  646. } else {
  647. throwError("Expected identifier or string, but got stream is " + expected.getType().getError(), stream.getPrev().getSpan());
  648. }
  649. var varName = packageName;
  650. if (isStringLiteral || stream.match("as", false)) {
  651. stream.expect("as");
  652. expected = stream.expect(TokenType.Identifier);
  653. varName = expected.getSpan().getText();
  654. }
  655. return new AST.Import(packageName, varName, !isStringLiteral);
  656. }
  657. throwError("Expected identifier or string, but got stream is EOF", stream.getPrev().getSpan());
  658. },
  659. parseVarDefine: function (stream) {
  660. var opening = stream.expect("var").getSpan();
  661. var expected = null;
  662. if (stream.hasMore()) {
  663. expected = TokenType.Identifier;
  664. var token = stream.expect(expected);
  665. var variableName = token.getSpan().getText();
  666. expected = TokenType.Assignment;
  667. if (stream.hasMore()) {
  668. stream.expect(expected);
  669. return new AST.VariableDefine(new Span(opening, stream.getPrev().getSpan()), variableName, this.parseExpression(stream));
  670. }
  671. }
  672. throwError("Expected " + expected.getError() + ", but got stream is EOF", stream.getPrev().getSpan());
  673. },
  674. expectCloseing: function (stream) {
  675. if (!stream.hasMore()) {
  676. throwError("Did not find closing }.", stream.prev().getSpan());
  677. }
  678. return stream.expect("}").getSpan();
  679. },
  680. parseIfStatement: function (stream) {
  681. var openingIf = stream.expect("if").getSpan();
  682. var condition = this.parseExpression(stream);
  683. stream.expect("{");
  684. var trueBlock = [];
  685. while (stream.hasMore() && !stream.match("}", false)) {
  686. var node = this.parseStatement(stream, true);
  687. if (node != null) {
  688. trueBlock.push(node);
  689. }
  690. }
  691. this.expectCloseing(stream);
  692. var elseIfs = [];
  693. var falseBlock = [];
  694. while (stream.hasMore() && stream.match("else", true)) {
  695. if (stream.hasMore() && stream.match("if", false)) {
  696. var elseIfOpening = stream.expect("if").getSpan();
  697. var elseIfCondition = this.parseExpression(stream);
  698. stream.expect("{");
  699. var elseIfBlock = [];
  700. while (stream.hasMore() && !stream.match("}", false)) {
  701. var node = this.parseStatement(stream, true);
  702. if (node != null) {
  703. elseIfBlock.push(node);
  704. }
  705. }
  706. this.expectCloseing(stream);
  707. var elseIfSpan = new Span(elseIfOpening, elseIfBlock.length > 0 ? elseIfBlock[elseIfBlock.length - 1].getSpan() : elseIfOpening);
  708. elseIfs.push(new AST.IfStatement(elseIfSpan, elseIfCondition, elseIfBlock, [], []));
  709. } else {
  710. stream.expect("{");
  711. while (stream.hasMore() && !stream.match("}", false)) {
  712. falseBlock.push(this.parseStatement(stream, true));
  713. }
  714. this.expectCloseing(stream);
  715. break;
  716. }
  717. }
  718. var closingEnd = stream.getPrev().getSpan();
  719. return new AST.IfStatement(new Span(openingIf, closingEnd), condition, trueBlock, elseIfs, falseBlock);
  720. },
  721. parseNewExpression: function (stream) {
  722. var identifier = stream.expect(TokenType.Identifier);
  723. var args = this.parseArguments(stream);
  724. var closing = stream.expect(")").getSpan();
  725. return new AST.NewStatement(identifier.getText(), args);
  726. },
  727. parseExpression: function (stream, expectRightCurly) {
  728. return this.parseTernaryOperator(stream, expectRightCurly);
  729. },
  730. parseTernaryOperator: function (stream, expectRightCurly) {
  731. var condition = this.parseBinaryOperator(stream, 0, expectRightCurly);
  732. if (stream.match(TokenType.Questionmark, true)) {
  733. var trueExpression = this.parseTernaryOperator(stream, expectRightCurly);
  734. stream.expect(TokenType.Colon);
  735. var falseExpression = this.parseTernaryOperator(stream, expectRightCurly);
  736. return new AST.TernaryOperation(condition, trueExpression, falseExpression);
  737. } else {
  738. return condition;
  739. }
  740. },
  741. binaryOperatorPrecedence: [
  742. [TokenType.Assignment],
  743. [TokenType.Or, TokenType.And, TokenType.Xor],
  744. [TokenType.Equal, TokenType.NotEqual],
  745. [TokenType.Less, TokenType.LessEqual, TokenType.Greater, TokenType.GreaterEqual],
  746. [TokenType.Plus, TokenType.Minus],
  747. [TokenType.ForwardSlash, TokenType.Asterisk, TokenType.Percentage]
  748. ],
  749. unaryOperators: [TokenType.Not, TokenType.Plus, TokenType.Minus],
  750. parseBinaryOperator: function (stream, level, expectRightCurly) {
  751. var nextLevel = level + 1;
  752. var left = nextLevel == this.binaryOperatorPrecedence.length ? this.parseUnaryOperator(stream, expectRightCurly) : this.parseBinaryOperator(stream, nextLevel, expectRightCurly);
  753. var operators = this.binaryOperatorPrecedence[level];
  754. while (stream.hasMore() && stream.match(operators, false)) {
  755. var operator = stream.consume();
  756. var right = nextLevel == this.binaryOperatorPrecedence.length ? this.parseUnaryOperator(stream, expectRightCurly) : this.parseBinaryOperator(stream, nextLevel, expectRightCurly);
  757. left = new AST.BinaryOperation(left, operator, right);
  758. }
  759. return left;
  760. },
  761. parseUnaryOperator: function (stream, expectRightCurly) {
  762. if (stream.match(this.unaryOperators,false)) {
  763. return new AST.UnaryOperation(stream.consume(), this.parseUnaryOperator(stream, expectRightCurly));
  764. } else {
  765. if (stream.match(TokenType.LeftParantheses, false)) { //(
  766. var openSpan = stream.expect(TokenType.LeftParantheses).getSpan();
  767. var index = stream.makeIndex();
  768. var parameters = [];
  769. while (stream.match(TokenType.Identifier, false)) {
  770. var identifier = stream.expect(TokenType.Identifier);
  771. parameters.push(identifier.getSpan().getText());
  772. if (stream.match(TokenType.Comma, true)) { //,
  773. continue;
  774. }
  775. if (stream.match(TokenType.RightParantheses, true)) { //)
  776. if (stream.match(TokenType.Lambda, true)) { // =>
  777. return this.parseLambdaBody(stream, openSpan, parameters);
  778. }
  779. break;
  780. }
  781. }
  782. if (stream.match(TokenType.RightParantheses, true) && stream.match(TokenType.Lambda, true)) {
  783. return this.parseLambdaBody(stream, openSpan, parameters);
  784. }
  785. stream.resetIndex(index);
  786. var expression = this.parseExpression(stream);
  787. stream.expect(TokenType.RightParantheses);
  788. return expression;
  789. } else {
  790. return this.parseAccessOrCallOrLiteral(stream, expectRightCurly);
  791. }
  792. }
  793. },
  794. parseListLiteral: function (stream) {
  795. var openBracket = stream.expect(TokenType.LeftBracket).getSpan();
  796. var values = [];
  797. while (stream.hasMore() && !stream.match(TokenType.RightBracket, false)) {
  798. values.push(this.parseExpression(stream));
  799. if (!stream.match(TokenType.RightBracket, false)) {
  800. stream.expect(TokenType.Comma);
  801. }
  802. }
  803. var closeBracket = stream.expect(TokenType.RightBracket).getSpan();
  804. return new AST.TypeLiteral('list', new Span(openBracket, closeBracket), values);
  805. },
  806. parseMapLiteral: function (stream) {
  807. var openCurly = stream.expect(TokenType.LeftCurly).getSpan();
  808. var keys = [];
  809. var values = [];
  810. while (stream.hasMore() && !stream.match("}", false)) {
  811. if (stream.match(TokenType.StringLiteral, false)) {
  812. keys.push(stream.expect(TokenType.StringLiteral));
  813. } else {
  814. keys.push(stream.expect(TokenType.Identifier));
  815. }
  816. stream.expect(":");
  817. values.push(this.parseExpression(stream));
  818. if (!stream.match("}", false)) {
  819. stream.expect(TokenType.Comma);
  820. }
  821. }
  822. var closeCurly = stream.expect("}").getSpan();
  823. return new AST.TypeLiteral('map', new Span(openCurly, closeCurly), keys, values);
  824. },
  825. parseAccessOrCallOrLiteral: function (stream, expectRightCurly) {
  826. if (expectRightCurly && stream.match("}", false)) {
  827. return null;
  828. } else if (stream.match(TokenType.Identifier, false)) {
  829. return this.parseAccessOrCall(stream, TokenType.Identifier);
  830. } else if (stream.match(TokenType.LeftCurly, false)) {
  831. return this.parseMapLiteral(stream);
  832. } else if (stream.match(TokenType.LeftBracket, false)) {
  833. return this.parseListLiteral(stream);
  834. } else if (stream.match(TokenType.StringLiteral, false)) {
  835. if (stream.hasNext()) {
  836. if (stream.next().type == TokenType.Period) {
  837. stream.prev();
  838. return this.parseAccessOrCall(stream, TokenType.StringLiteral);
  839. }
  840. stream.prev();
  841. }
  842. return new AST.TypeLiteral('string', stream.expect(TokenType.StringLiteral).getSpan());
  843. } else if (stream.match(TokenType.BooleanLiteral, false)) {
  844. return new AST.TypeLiteral('boolean', stream.expect(TokenType.BooleanLiteral).getSpan());
  845. } else if (stream.match(TokenType.DoubleLiteral, false)) {
  846. return new AST.TypeLiteral('double', stream.expect(TokenType.DoubleLiteral).getSpan());
  847. } else if (stream.match(TokenType.FloatLiteral, false)) {
  848. return new AST.TypeLiteral('float', stream.expect(TokenType.FloatLiteral).getSpan());
  849. } else if (stream.match(TokenType.ByteLiteral, false)) {
  850. return new AST.TypeLiteral('byte', stream.expect(TokenType.ByteLiteral).getSpan());
  851. } else if (stream.match(TokenType.ShortLiteral, false)) {
  852. return new AST.TypeLiteral('short', stream.expect(TokenType.ShortLiteral).getSpan());
  853. } else if (stream.match(TokenType.IntegerLiteral, false)) {
  854. return new AST.TypeLiteral('int', stream.expect(TokenType.IntegerLiteral).getSpan());
  855. } else if (stream.match(TokenType.LongLiteral, false)) {
  856. return new AST.TypeLiteral('long', stream.expect(TokenType.LongLiteral).getSpan());
  857. } else if (stream.match(TokenType.NullLiteral, false)) {
  858. return new AST.TypeLiteral('null', stream.expect(TokenType.NullLiteral).getSpan());
  859. } else {
  860. throwError("Expected a variable, field, map, array, function or method call, or literal.", stream.consume().getText());
  861. return null; // not reached
  862. }
  863. },
  864. parseArguments: function (stream) {
  865. stream.expect(TokenType.LeftParantheses);
  866. var args = [];
  867. while (stream.hasMore() && !stream.match(TokenType.RightParantheses, false)) {
  868. args.push(this.parseExpression(stream));
  869. if (!stream.match(TokenType.RightParantheses, false)) stream.expect(TokenType.Comma);
  870. }
  871. return args;
  872. },
  873. parseAccessOrCall: function (stream, tokenType) {
  874. var identifier = stream.expect(tokenType).getSpan();
  875. if(tokenType == TokenType.Identifier && "new" == identifier.getText()){
  876. return this.parseNewExpression(stream);
  877. }
  878. if (tokenType == TokenType.Identifier && stream.match(TokenType.Lambda, true)) {
  879. return this.parseLambdaBody(stream, identifier, [identifier.getText()]);
  880. }
  881. var result = tokenType == TokenType.StringLiteral ? new AST.TypeLiteral('string', identifier) : new AST.VariableAccess(identifier);
  882. while (stream.hasMore() && stream.match([TokenType.LeftParantheses, TokenType.LeftBracket, TokenType.Period], false)) {
  883. // function or method call
  884. if (stream.match(TokenType.LeftParantheses, false)) {
  885. var args = this.parseArguments(stream);
  886. var closingSpan = stream.expect(TokenType.RightParantheses).getSpan();
  887. if (result instanceof AST.VariableAccess || result instanceof AST.MapOrArrayAccess)
  888. result = new AST.FunctionCall(result, args);
  889. else if (result instanceof AST.MemberAccess) {
  890. result = new AST.MethodCall(result, args);
  891. } else {
  892. throwError("Expected a variable, field or method.", stream);
  893. }
  894. }
  895. // map or array access
  896. else if (stream.match(TokenType.LeftBracket, true)) {
  897. var keyOrIndex = this.parseExpression(stream);
  898. var closingSpan = stream.expect(TokenType.RightBracket).getSpan();
  899. result = new AST.MapOrArrayAccess(result, keyOrIndex);
  900. }
  901. // field or method access
  902. else if (stream.match(TokenType.Period, true)) {
  903. identifier = stream.expect(TokenType.Identifier).getSpan();
  904. result = new AST.MemberAccess(result, identifier);
  905. }
  906. }
  907. return result;
  908. },
  909. parseLambdaBody: function (stream, openSpan, parameters) {
  910. var index = stream.makeIndex();
  911. var childNodes = [];
  912. try {
  913. var expression = this.parseExpression(stream);
  914. childNodes.push(new AST.Return(new Span("return", 0, 6), expression));
  915. return new AST.LambdaFunction(expression);
  916. } catch (e) {
  917. stream.resetIndex(index);
  918. if (stream.match(TokenType.LeftCurly, true)) {
  919. while (stream.hasMore() && !stream.match("}",false)) {
  920. childNodes.push(this.parseStatement(stream, true));
  921. }
  922. var closeSpan = this.expectCloseing(stream);
  923. return new AST.LambdaFunction(childNodes);
  924. } else {
  925. var node = this.parseStatement(stream);
  926. childNodes.push(new AST.Return(new Span("return", 0, 6), node));
  927. return new AST.LambdaFunction(node);
  928. }
  929. }
  930. }
  931. }
  932. var AST = {
  933. TypeLiteral: function (type) {
  934. this.type = type;
  935. this.getJavaType = function () {
  936. if (type == 'string') {
  937. return 'java.lang.String';
  938. }
  939. if (type == 'boolean') {
  940. return 'java.lang.Boolean';
  941. }
  942. if (type == 'int') {
  943. return 'java.lang.Integer';
  944. }
  945. if (type == 'short') {
  946. return 'java.lang.Short';
  947. }
  948. if (type == 'byte') {
  949. return 'java.lang.Byte';
  950. }
  951. if (type == 'double') {
  952. return 'java.lang.Double';
  953. }
  954. if (type == 'float') {
  955. return 'java.lang.Float';
  956. }
  957. if (type == 'long') {
  958. return 'java.lang.Long';
  959. }
  960. if (type == 'null') {
  961. return null;
  962. }
  963. if (type == 'list') {
  964. return 'java.util.List';
  965. }
  966. if (type == 'map') {
  967. return 'java.util.Map';
  968. }
  969. return 'java.lang.Object';
  970. }
  971. },
  972. VariableDefine: function () {
  973. },
  974. TernaryOperation: function (condition, trueExpression, falseExpression) {
  975. },
  976. UnaryOperation: function () {
  977. },
  978. Return : function(result){
  979. this.getJavaType = function(env){
  980. return result == null ? '' : result.getJavaType(env);
  981. }
  982. },
  983. NewStatement: function (identifier) {
  984. this.getJavaType = function (env) {
  985. return env[identifier] || 'java.lang.Object';
  986. }
  987. },
  988. BinaryOperation: function (left, operator, right) {
  989. this.getJavaType = function () {
  990. if (operator.type == TokenType.Plus) {
  991. if (left.type == 'string' || right.type == 'string') {
  992. return 'java.lang.String';
  993. }
  994. }
  995. if (left.type == 'double' || right.type == 'double') {
  996. return 'java.lang.Double';
  997. }
  998. if (left.type == 'float' || right.type == 'float') {
  999. return 'java.lang.Float';
  1000. }
  1001. if (left.type == 'long' || right.type == 'long') {
  1002. return 'java.lang.Long';
  1003. }
  1004. if (left.type == 'int' || right.type == 'int') {
  1005. return 'java.lang.Integer';
  1006. }
  1007. if (left.type == 'short' || right.type == 'short') {
  1008. return 'java.lang.Short';
  1009. }
  1010. if (left.type == 'byte' || right.type == 'byte') {
  1011. return 'java.lang.Byte';
  1012. }
  1013. return 'java.lang.Object';
  1014. }
  1015. },
  1016. LambdaFunction: function (returnValue) {
  1017. this.getJavaType = function (env) {
  1018. if(returnValue == null){
  1019. return 'java.lang.Object';
  1020. }else if(Array.isArray(returnValue)){
  1021. for(var i=0,len = returnValue.length;i<len;i++){
  1022. var node = returnValue[i];
  1023. if(node instanceof AST.Return){
  1024. return node.getJavaType(env);
  1025. }
  1026. }
  1027. return 'java.lang.Object';
  1028. }else{
  1029. returnValue.getJavaType(env);
  1030. }
  1031. }
  1032. },
  1033. matchTypes: function (parameters, args) {
  1034. if (parameters.length == args.length) {
  1035. return true;
  1036. }
  1037. },
  1038. MethodCall: function (node, args) {
  1039. this.node = node;
  1040. this.args = args;
  1041. this.getJavaType = function (env) {
  1042. var target = node.node.getJavaType(env);
  1043. var targetMethod = node.member;
  1044. target = Parser.scriptClass[target];
  1045. var methods = target && target.methods;
  1046. if (methods) {
  1047. for (var i = 0, len = methods.length; i < len; i++) {
  1048. var m = methods[i];
  1049. if (m.name == targetMethod && AST.matchTypes(m.parameters, args)) {
  1050. return Parser.getWrapperClass(m.returnType);
  1051. }
  1052. }
  1053. }
  1054. return 'java.lang.Object';
  1055. }
  1056. },
  1057. FunctionCall: function (result) {
  1058. this.getJavaType = function(env){
  1059. return result.getJavaType(env);
  1060. }
  1061. },
  1062. MemberAccess: function (node, member) {
  1063. this.node = node;
  1064. this.member = member.getText();
  1065. this.getJavaType = function (env, args) {
  1066. var target = node.getJavaType(env);
  1067. target = Parser.scriptClass[target];
  1068. if(target.superClass == 'java.util.HashMap'){
  1069. var methods = target && target.methods;
  1070. if (methods) {
  1071. for (var i = 0, len = methods.length; i < len; i++) {
  1072. var method = methods[i];
  1073. if (method.name == 'get' && method.parameters.length == 1) {
  1074. return Parser.getWrapperClass(method.returnType);
  1075. }
  1076. }
  1077. }
  1078. }
  1079. return 'java.lang.Object';
  1080. }
  1081. },
  1082. MapOrArrayAccess: function () {
  1083. },
  1084. IfStatement: function () {
  1085. },
  1086. VariableAccess: function (span) {
  1087. this.name = span.getText();
  1088. this.getJavaType = function (env) {
  1089. return (env && env[span.getText()]) || 'java.lang.String'
  1090. }
  1091. }
  1092. }
  1093. require(['vs/editor/editor.main'], function() {
  1094. monaco.languages.register({ id :'magicscript'});
  1095. monaco.languages.setLanguageConfiguration('magicscript',{
  1096. wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
  1097. brackets: [
  1098. ['{', '}'],
  1099. ['[', ']'],
  1100. ['(', ')'],
  1101. ],
  1102. comments: {
  1103. lineComment: '//',
  1104. blockComment: ['/*', '*/'],
  1105. },
  1106. operators: ['<=', '>=', '==', '!=', '+', '-','*', '/', '%', '&','|', '!', '&&', '||', '?', ':', ],
  1107. autoClosingPairs: [
  1108. { open: '{', close: '}' },
  1109. { open: '[', close: ']' },
  1110. { open: '(', close: ')' },
  1111. {open: '"""', close: '"""', notIn: ['string.multi']},
  1112. { open: '"', close: '"', notIn: ['string'] },
  1113. { open: '\'', close: '\'', notIn: ['string'] },
  1114. ],
  1115. })
  1116. var defaultSuggestions = [{
  1117. label: 'if',
  1118. kind: monaco.languages.CompletionItemKind.Snippet,
  1119. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1120. insertText: [
  1121. 'if (${1:condition}) {',
  1122. '\t$0',
  1123. '}'
  1124. ].join('\n')
  1125. }, {
  1126. label: 'ret',
  1127. detail : 'return',
  1128. kind: monaco.languages.CompletionItemKind.Snippet,
  1129. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1130. insertText: 'return $1;'
  1131. }, {
  1132. label: 'ife',
  1133. detail : 'if else',
  1134. kind: monaco.languages.CompletionItemKind.Snippet,
  1135. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1136. insertText: [
  1137. 'if (${1:condition}) {',
  1138. '\t$2',
  1139. '} else {',
  1140. '\t$3',
  1141. '}'
  1142. ].join('\n')
  1143. }, {
  1144. label: 'for',
  1145. kind: monaco.languages.CompletionItemKind.Snippet,
  1146. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1147. insertText: [
  1148. 'for (${1:item} in ${2:range(${3:0},${4:100})}}) {',
  1149. '\t$0',
  1150. '}'
  1151. ].join('\n')
  1152. }, {
  1153. label: 'br',
  1154. detail : 'break',
  1155. kind: monaco.languages.CompletionItemKind.Snippet,
  1156. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1157. insertText: 'break;'
  1158. }, {
  1159. label: 'co',
  1160. detail : 'continue',
  1161. kind: monaco.languages.CompletionItemKind.Snippet,
  1162. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1163. insertText: 'continue;'
  1164. }, {
  1165. label: 'try',
  1166. detail : 'try catch',
  1167. kind: monaco.languages.CompletionItemKind.Snippet,
  1168. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1169. insertText: [
  1170. 'try {',
  1171. '\t$1',
  1172. '} catch(e) {',
  1173. '\t$2',
  1174. '}'
  1175. ].join('\n')
  1176. }, {
  1177. label: 'tryf',
  1178. detail : 'try catch finally',
  1179. kind: monaco.languages.CompletionItemKind.Snippet,
  1180. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1181. insertText: [
  1182. 'try {',
  1183. '\t$1',
  1184. '} catch(e) {',
  1185. '\t$2',
  1186. '} finally {',
  1187. '\t$3',
  1188. '}'
  1189. ].join('\n')
  1190. }, {
  1191. label: 'cat',
  1192. detail : 'catch',
  1193. kind: monaco.languages.CompletionItemKind.Snippet,
  1194. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1195. insertText: [
  1196. 'catch(e) {',
  1197. '\t$1',
  1198. '}'
  1199. ].join('\n')
  1200. }, {
  1201. label: 'fin',
  1202. detail : 'finally',
  1203. kind: monaco.languages.CompletionItemKind.Snippet,
  1204. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1205. insertText: [
  1206. 'finally {',
  1207. '\t$1',
  1208. '}'
  1209. ].join('\n')
  1210. }];
  1211. monaco.languages.registerCompletionItemProvider('magicscript',{
  1212. provideCompletionItems: function (model, position) {
  1213. var value = model.getValueInRange({
  1214. startLineNumber: 1,
  1215. startColumn: 1,
  1216. endLineNumber: position.lineNumber,
  1217. endColumn: position.column
  1218. });
  1219. var suggestions = [];
  1220. if (value.charAt(value.length - 1) == '.' && value.length > 1) {
  1221. try{
  1222. var className = Parser.parse(new TokenStream(Parser.tokenize(value.substring(0, value.length - 1))));
  1223. if (className) {
  1224. var target = Parser.scriptClass[className];
  1225. if (target !== undefined) {
  1226. if (target != null) {
  1227. for (var j = 0; j < target.attributes.length; j++) {
  1228. var attribute = target.attributes[j];
  1229. suggestions.push({
  1230. label: attribute.name,
  1231. kind: monaco.languages.CompletionItemKind.Field,
  1232. detail: attribute.type + ":" + attribute.name,
  1233. insertText: attribute.name,
  1234. sortText: ' ~~' + attribute.name
  1235. })
  1236. }
  1237. var methods = target.methods;
  1238. for (var i = 0, len = methods.length; i < len; i++) {
  1239. var method = methods[i];
  1240. method.insertText = method.name;
  1241. if (method.parameters.length > 0) {
  1242. var params = [];
  1243. var params1 = [];
  1244. var params2 = [];
  1245. for (var j = 0; j < method.parameters.length; j++) {
  1246. params.push('${' + (j + 1) + ':' + method.parameters[j].name + '}');
  1247. params1.push(method.parameters[j].name);
  1248. params2.push(Parser.getSimpleClass(method.parameters[j].type) + " " + method.parameters[j].name);
  1249. }
  1250. if (!method.comment) {
  1251. method.comment = Parser.getSimpleClass(method.returnType) + ':' + method.name + '(' + params1.join(',') + ')';
  1252. }
  1253. method.fullName = method.name + '(' + params2.join(', ') + ')';
  1254. method.insertText += '(' + params.join(',') + ')';
  1255. } else {
  1256. method.insertText += '()';
  1257. method.fullName = method.name + '()';
  1258. if (!method.comment) {
  1259. method.comment = Parser.getSimpleClass(method.returnType) + ':' + method.name + '()';
  1260. }
  1261. }
  1262. }
  1263. for (var j = 0; j < methods.length; j++) {
  1264. var method = methods[j];
  1265. suggestions.push({
  1266. sortText: method.sortText || method.fullName,
  1267. label: method.fullName,
  1268. kind: monaco.languages.CompletionItemKind.Method,
  1269. detail: method.comment,
  1270. insertText: method.insertText,
  1271. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
  1272. })
  1273. }
  1274. }
  1275. }
  1276. }
  1277. }catch (e) {
  1278. }
  1279. } else {
  1280. suggestions = defaultSuggestions;
  1281. }
  1282. return {
  1283. suggestions : suggestions
  1284. }
  1285. },
  1286. triggerCharacters: ['.']
  1287. })
  1288. monaco.languages.setMonarchTokensProvider('magicscript',{
  1289. escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
  1290. keywords : ['new','var','if','else','for','in','return','import','break','continue','as','null','true','false','try','catch','finally'],
  1291. digits: /\d+(_+\d+)*/,
  1292. tokenizer : {
  1293. root : [
  1294. [/[a-zA-Z_$][\w$]*/,{
  1295. cases :{
  1296. "@keywords" : { token : "keywords" },
  1297. "@default" : "identifier"
  1298. }
  1299. }],
  1300. [/[{}()\[\]]/, '@brackets'],
  1301. [/(@digits)[lLbBsSdDfF]?/, 'number'],
  1302. [/\/\*\*(?!\/)/, 'comment.doc', '@mulcomment'],
  1303. [/\/\*/, 'comment', '@comment'],
  1304. [/\/\/.*$/, 'comment'],
  1305. [/[;,.]/, 'delimiter'],
  1306. [/"([^"\\]|\\.)*$/, 'string.invalid'],
  1307. [/'([^'\\]|\\.)*$/, 'string.invalid'],
  1308. [/""/, 'string.multi', '@string_multi'],
  1309. [/"/, 'string', '@string_double'],
  1310. [/'/, 'string', '@string_single'],
  1311. ],
  1312. comment: [
  1313. [/[^\/*]+/, 'comment'],
  1314. // [/\/\*/, 'comment', '@push' ], // nested comment not allowed :-(
  1315. // [/\/\*/, 'comment.invalid' ], // this breaks block comments in the shape of /* //*/
  1316. [/\*\//, 'comment', '@pop'],
  1317. [/[\/*]/, 'comment']
  1318. ],
  1319. mulcomment: [
  1320. [/[^\/*]+/, 'comment.doc'],
  1321. // [/\/\*/, 'comment.doc', '@push' ], // nested comment not allowed :-(
  1322. [/\/\*/, 'comment.doc.invalid'],
  1323. [/\*\//, 'comment.doc', '@pop'],
  1324. [/[\/*]/, 'comment.doc']
  1325. ],
  1326. string_multi: [
  1327. [/"""/, {token: 'string', next: '@pop'}],
  1328. [/"/, {token: 'string', next: '@string_multi_embedded', nextEmbedded: 'sql'}]
  1329. ],
  1330. string_multi_embedded: [
  1331. [/"""/, {token: '@rematch', next: '@pop', nextEmbedded: '@pop'}],
  1332. [/[^"""]+/, '']
  1333. ],
  1334. string_double: [
  1335. [/[^\\"]+/, 'string'],
  1336. [/@escapes/, 'string.escape'],
  1337. [/\\./, 'string.escape.invalid'],
  1338. [/"/, 'string', '@pop']
  1339. ],
  1340. string_single: [
  1341. [/[^\\']+/, 'string'],
  1342. [/@escapes/, 'string.escape'],
  1343. [/\\./, 'string.escape.invalid'],
  1344. [/'/, 'string', '@pop']
  1345. ],
  1346. }
  1347. })
  1348. });