A templating language that looks like Lisp and compiles to HTML
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lexer.js 2.3KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  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(/\n/)) {
  46. line++
  47. pos++
  48. } else if (source[pos].match(/\s/)) {
  49. pos++
  50. } else {
  51. let endPattern = /[^()"':\s]+/
  52. if (allowSpecialCharactersInLiterals) {
  53. endPattern = /[^"']+/
  54. }
  55. let value = endPattern.exec(source.slice(pos))[0].trim()
  56. if (['if', 'each'].includes(value)) {
  57. tokenStream.tokens.push({
  58. type: tokenTypes.KEYWORD,
  59. line: line,
  60. value: value,
  61. })
  62. } else {
  63. tokenStream.tokens.push({
  64. type: tokenTypes.LITERAL,
  65. line: line,
  66. value: value.trim(),
  67. })
  68. }
  69. pos += value.length
  70. }
  71. }
  72. tokenStream.tokens.push({
  73. type: tokenTypes.EOF,
  74. line: line,
  75. })
  76. return tokenStream
  77. }
  78. }