magicscript.js 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381
  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. _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.editor.defineTheme('magicscript', {
  1096. base: 'vs',
  1097. inherit: true,
  1098. rules: [
  1099. { token: 'keywords.null', foreground: 'ff0001' },
  1100. { token: 'keywords', foreground: '0000ff' },
  1101. { token: 'keywords.true', foreground: '0000ff' },
  1102. { token: 'keywords.false', foreground: '0000ff' },
  1103. { token: 'number', foreground: '0000ff' },
  1104. { token: 'comment', foreground: '008000' },
  1105. { token: 'comment.mul', foreground: '008000' },
  1106. { token: 'method.call.empty', foreground: 'ff0000', fontStyle: 'bold' },
  1107. ]
  1108. });
  1109. monaco.languages.setLanguageConfiguration('magicscript',{
  1110. wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
  1111. brackets: [
  1112. ['{', '}'],
  1113. ['[', ']'],
  1114. ['(', ')'],
  1115. ],
  1116. comments: {
  1117. lineComment: '//',
  1118. blockComment: ['/*', '*/'],
  1119. },
  1120. operators: ['<=', '>=', '==', '!=', '+', '-','*', '/', '%', '&','|', '!', '&&', '||', '?', ':', ],
  1121. autoClosingPairs: [
  1122. { open: '{', close: '}' },
  1123. { open: '[', close: ']' },
  1124. { open: '(', close: ')' },
  1125. {open: '"""', close: '"""', notIn: ['string.multi']},
  1126. { open: '"', close: '"', notIn: ['string'] },
  1127. { open: '\'', close: '\'', notIn: ['string'] },
  1128. ],
  1129. })
  1130. var defaultSuggestions = [{
  1131. label: 'if',
  1132. kind: monaco.languages.CompletionItemKind.Snippet,
  1133. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1134. insertText: [
  1135. 'if (${1:condition}) {',
  1136. '\t$0',
  1137. '}'
  1138. ].join('\n')
  1139. }, {
  1140. label: 'ret',
  1141. detail : 'return',
  1142. kind: monaco.languages.CompletionItemKind.Snippet,
  1143. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1144. insertText: 'return $1;'
  1145. }, {
  1146. label: 'ife',
  1147. detail : 'if else',
  1148. kind: monaco.languages.CompletionItemKind.Snippet,
  1149. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1150. insertText: [
  1151. 'if (${1:condition}) {',
  1152. '\t$2',
  1153. '} else {',
  1154. '\t$3',
  1155. '}'
  1156. ].join('\n')
  1157. }, {
  1158. label: 'for',
  1159. kind: monaco.languages.CompletionItemKind.Snippet,
  1160. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1161. insertText: [
  1162. 'for (${1:item} in ${2:range(${3:0},${4:100})}}) {',
  1163. '\t$0',
  1164. '}'
  1165. ].join('\n')
  1166. }, {
  1167. label: 'br',
  1168. detail : 'break',
  1169. kind: monaco.languages.CompletionItemKind.Snippet,
  1170. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1171. insertText: 'break;'
  1172. }, {
  1173. label: 'co',
  1174. detail : 'continue',
  1175. kind: monaco.languages.CompletionItemKind.Snippet,
  1176. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1177. insertText: 'continue;'
  1178. }, {
  1179. label: 'try',
  1180. detail : 'try catch',
  1181. kind: monaco.languages.CompletionItemKind.Snippet,
  1182. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1183. insertText: [
  1184. 'try {',
  1185. '\t$1',
  1186. '} catch(e) {',
  1187. '\t$2',
  1188. '}'
  1189. ].join('\n')
  1190. }, {
  1191. label: 'tryf',
  1192. detail : 'try catch finally',
  1193. kind: monaco.languages.CompletionItemKind.Snippet,
  1194. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1195. insertText: [
  1196. 'try {',
  1197. '\t$1',
  1198. '} catch(e) {',
  1199. '\t$2',
  1200. '} finally {',
  1201. '\t$3',
  1202. '}'
  1203. ].join('\n')
  1204. }, {
  1205. label: 'cat',
  1206. detail : 'catch',
  1207. kind: monaco.languages.CompletionItemKind.Snippet,
  1208. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1209. insertText: [
  1210. 'catch(e) {',
  1211. '\t$1',
  1212. '}'
  1213. ].join('\n')
  1214. }, {
  1215. label: 'fin',
  1216. detail : 'finally',
  1217. kind: monaco.languages.CompletionItemKind.Snippet,
  1218. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
  1219. insertText: [
  1220. 'finally {',
  1221. '\t$1',
  1222. '}'
  1223. ].join('\n')
  1224. }];
  1225. monaco.languages.registerCompletionItemProvider('magicscript',{
  1226. provideCompletionItems: function (model, position) {
  1227. var value = model.getValueInRange({
  1228. startLineNumber: 1,
  1229. startColumn: 1,
  1230. endLineNumber: position.lineNumber,
  1231. endColumn: position.column
  1232. });
  1233. var suggestions = [];
  1234. if (value.charAt(value.length - 1) == '.' && value.length > 1) {
  1235. var className = Parser.parse(new TokenStream(Parser.tokenize(value.substring(0, value.length - 1))));
  1236. if (className) {
  1237. var target = Parser.scriptClass[className];
  1238. if (target !== undefined) {
  1239. if (target != null) {
  1240. for (var j = 0; j < target.attributes.length; j++) {
  1241. var attribute = target.attributes[j];
  1242. suggestions.push({
  1243. label: attribute.name,
  1244. kind: monaco.languages.CompletionItemKind.Field,
  1245. detail: attribute.type + ":" + attribute.name,
  1246. insertText: attribute.name,
  1247. sortText: ' ~~' + attribute.name
  1248. })
  1249. }
  1250. var methods = target.methods;
  1251. for (var i = 0, len = methods.length; i < len; i++) {
  1252. var method = methods[i];
  1253. method.insertText = method.name;
  1254. if (method.parameters.length > 0) {
  1255. var params = [];
  1256. var params1 = [];
  1257. var params2 = [];
  1258. for (var j = 0; j < method.parameters.length; j++) {
  1259. params.push('${' + (j + 1) + ':' + method.parameters[j].name + '}');
  1260. params1.push(method.parameters[j].name);
  1261. params2.push(Parser.getSimpleClass(method.parameters[j].type) + " " + method.parameters[j].name);
  1262. }
  1263. if (!method.comment) {
  1264. method.comment = Parser.getSimpleClass(method.returnType) + ':' + method.name + '(' + params1.join(',') + ')';
  1265. }
  1266. method.fullName = method.name + '(' + params2.join(', ') + ')';
  1267. method.insertText += '(' + params.join(',') + ')';
  1268. } else {
  1269. method.insertText += '()';
  1270. method.fullName = method.name + '()';
  1271. if (!method.comment) {
  1272. method.comment = Parser.getSimpleClass(method.returnType) + ':' + method.name + '()';
  1273. }
  1274. }
  1275. }
  1276. for (var j = 0; j < methods.length; j++) {
  1277. var method = methods[j];
  1278. suggestions.push({
  1279. sortText: method.sortText || method.fullName,
  1280. label: method.fullName,
  1281. kind: monaco.languages.CompletionItemKind.Method,
  1282. detail: method.comment,
  1283. insertText: method.insertText,
  1284. insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
  1285. })
  1286. }
  1287. }
  1288. }
  1289. }
  1290. } else {
  1291. suggestions = defaultSuggestions;
  1292. }
  1293. return {
  1294. suggestions : suggestions
  1295. }
  1296. },
  1297. triggerCharacters: ['.']
  1298. })
  1299. monaco.languages.setMonarchTokensProvider('magicscript',{
  1300. escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
  1301. keywords : ['new','var','if','else','for','in','return','import','break','continue','as','null','true','false','try','catch','finally'],
  1302. digits: /\d+(_+\d+)*/,
  1303. tokenizer : {
  1304. root : [
  1305. [/[a-zA-Z_$][\w$]*/,{
  1306. cases :{
  1307. "@keywords" : { token : "keywords" },
  1308. "@default" : "identifier"
  1309. }
  1310. }],
  1311. [/[{}()\[\]]/, '@brackets'],
  1312. [/(@digits)[lLbBsSdDfF]?/, 'number'],
  1313. [/\/\*\*(?!\/)/, 'comment.mul', '@mulcomment'],
  1314. [/\/\*/, 'comment', '@comment'],
  1315. [/\/\/.*$/, 'comment'],
  1316. [/[;,.]/, 'delimiter'],
  1317. [/"([^"\\]|\\.)*$/, 'string.invalid'],
  1318. [/'([^'\\]|\\.)*$/, 'string.invalid'],
  1319. [/""/, 'string.multi', '@string_multi'],
  1320. [/"/, 'string', '@string_double'],
  1321. [/'/, 'string', '@string_single'],
  1322. ],
  1323. comment: [
  1324. [/[^\/*]+/, 'comment'],
  1325. // [/\/\*/, 'comment', '@push' ], // nested comment not allowed :-(
  1326. // [/\/\*/, 'comment.invalid' ], // this breaks block comments in the shape of /* //*/
  1327. [/\*\//, 'comment', '@pop'],
  1328. [/[\/*]/, 'comment']
  1329. ],
  1330. mulcomment: [
  1331. [/[^\/*]+/, 'comment.mul'],
  1332. // [/\/\*/, 'comment.doc', '@push' ], // nested comment not allowed :-(
  1333. [/\/\*/, 'comment.mul.invalid'],
  1334. [/\*\//, 'comment.mul', '@pop'],
  1335. [/[\/*]/, 'comment.mul']
  1336. ],
  1337. string_multi: [
  1338. [/"""/, {token: 'string.multi', next: '@pop'}],
  1339. [/"/, {token: 'string.multi', next: '@string_multi_embedded', nextEmbedded: 'sql'}]
  1340. ],
  1341. string_multi_embedded: [
  1342. [/"""/, {token: '@rematch', next: '@pop', nextEmbedded: '@pop'}],
  1343. [/[^"""]+/, '']
  1344. ],
  1345. string_double: [
  1346. [/[^\\"]+/, 'string'],
  1347. // [/@escapes/, 'string.escape'],
  1348. [/\\./, 'string.escape.invalid'],
  1349. [/"/, 'string', '@pop']
  1350. ],
  1351. string_single: [
  1352. [/[^\\']+/, 'string'],
  1353. [/@escapes/, 'string.escape'],
  1354. [/\\./, 'string.escape.invalid'],
  1355. [/'/, 'string', '@pop']
  1356. ],
  1357. }
  1358. })
  1359. });