A templating language that looks like Lisp and compiles to HTML
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

lexer.js 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. const TokenStream = require("./tokenStream");
  2. const tokenTypes = require("./tokenTypes");
  3. module.exports = class Lexer {
  4. scan(source) {
  5. let pos = 0;
  6. let line = 1;
  7. let tokenStream = new TokenStream();
  8. let allowSpecialCharactersInLiterals = false;
  9. while (pos < source.length) {
  10. if (source[pos].match(/\(/) && !allowSpecialCharactersInLiterals) {
  11. tokenStream.tokens.push({
  12. type: tokenTypes.OPAREN,
  13. line: line
  14. });
  15. pos++;
  16. } else if (source[pos].match(/\)/)) {
  17. tokenStream.tokens.push({
  18. type: tokenTypes.CPAREN,
  19. line: line
  20. });
  21. pos++;
  22. } else if (source[pos].match(/["]/)) {
  23. allowSpecialCharactersInLiterals = !allowSpecialCharactersInLiterals;
  24. tokenStream.tokens.push({
  25. type: tokenTypes.QUOTE,
  26. line: line
  27. });
  28. pos++;
  29. } else if (source[pos].match(/:/)) {
  30. let value = /:([^()'"\s]+)/.exec(source.slice(pos))[1].trim();
  31. tokenStream.tokens.push({
  32. type: tokenTypes.ATTRIBUTE,
  33. line: line,
  34. value: value
  35. });
  36. pos += value.length + 1; // the +1 is to account for the colon
  37. } else if (source[pos].match(/\'/)) {
  38. let value = /'([^()"\s]+)/.exec(source.slice(pos))[1].trim();
  39. tokenStream.tokens.push({
  40. type: tokenTypes.SYMBOL,
  41. line: line,
  42. value: value
  43. });
  44. pos += value.length + 1; // the +1 is to account for the apostrophe
  45. } else if (source[pos].match(/\d/)) {
  46. let number = "";
  47. while (source[pos] && source[pos].match(/\d/)) {
  48. number += source[pos];
  49. pos++;
  50. }
  51. tokenStream.tokens.push({
  52. type: tokenTypes.NUMBER,
  53. line: line,
  54. value: parseFloat(number)
  55. });
  56. } else if (source.slice(pos).match(/^#(t|f)/)) {
  57. pos++;
  58. tokenStream.tokens.push({
  59. type: tokenTypes.BOOLEAN,
  60. line: line,
  61. value: source[pos] === "t" ? true : false
  62. });
  63. pos++;
  64. } else if (source[pos].match(/\n/)) {
  65. line++;
  66. pos++;
  67. } else if (source[pos].match(/\s/)) {
  68. pos++;
  69. } else {
  70. let endPattern = /[^()"':\s]+/;
  71. if (allowSpecialCharactersInLiterals) {
  72. endPattern = /[^"']+/;
  73. }
  74. let value = endPattern.exec(source.slice(pos))[0].trim();
  75. if (allowSpecialCharactersInLiterals) {
  76. tokenStream.tokens.push({
  77. type: tokenTypes.LITERAL,
  78. line: line,
  79. value: value
  80. });
  81. } else {
  82. tokenStream.tokens.push({
  83. type: tokenTypes.IDENTIFIER,
  84. line: line,
  85. value: value.trim()
  86. });
  87. }
  88. pos += value.length;
  89. }
  90. }
  91. tokenStream.tokens.push({
  92. type: tokenTypes.EOF,
  93. line: line
  94. });
  95. return tokenStream;
  96. }
  97. };