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.

parserTest.js 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. const test = require('tape')
  2. const helpers = require('./helpers')
  3. const AST = require('../src/ast')
  4. const OsloError = require('../src/osloError')
  5. const tt = require('../src/tokenTypes')
  6. test('parses token stream into a tree', t => {
  7. t.plan(1)
  8. const tree = helpers.parse(`
  9. (div :class "foobar"
  10. (p :class (if #t "primary" "secondary")))
  11. `)
  12. t.deepEqual(tree, [
  13. new AST.Application({
  14. function: new AST.Identifier({ name: 'div', line: 2 }),
  15. args: [
  16. new AST.Attribute({
  17. name: 'class',
  18. value: new AST.String({ value: 'foobar' }),
  19. }),
  20. new AST.Application({
  21. function: new AST.Identifier({ name: 'p', line: 3 }),
  22. args: [
  23. new AST.Attribute({
  24. name: 'class',
  25. value: new AST.Conditional({
  26. condition: new AST.Boolean({ value: true }),
  27. ifCase: new AST.String({ value: 'primary' }),
  28. elseCase: new AST.String({ value: 'secondary' }),
  29. }),
  30. }),
  31. ],
  32. }),
  33. ],
  34. }),
  35. ])
  36. })
  37. test('allow empty strings', t => {
  38. t.plan(1)
  39. const tree = helpers.parse('(p "")')
  40. t.deepEqual(tree, [
  41. new AST.Application({
  42. function: new AST.Identifier({ name: 'p', line: 1 }),
  43. args: [new AST.String({ value: '' })],
  44. }),
  45. ])
  46. })
  47. test('parse lambdas and expressions in function position', t => {
  48. t.plan(1)
  49. const tree = helpers.parse('((lambda (n) (+ n 1)) 5)')
  50. t.deepEqual(tree, [
  51. new AST.Application({
  52. function: new AST.Lambda({
  53. parameters: [new AST.Identifier({ name: 'n' })],
  54. body: new AST.Application({
  55. function: new AST.Identifier({ name: '+', line: 1 }),
  56. args: [
  57. new AST.Identifier({ name: 'n', line: 1 }),
  58. new AST.Number({ value: 1, line: 1 }),
  59. ],
  60. }),
  61. }),
  62. args: [new AST.Number({ value: 5, line: 1 })],
  63. }),
  64. ])
  65. })
  66. test('parse conditionals', t => {
  67. t.plan(1)
  68. const tree = helpers.parse('(if #t (do this) (do that))')
  69. t.deepEqual(tree, [
  70. new AST.Conditional({
  71. condition: new AST.Boolean({ value: true }),
  72. ifCase: new AST.Application({
  73. function: new AST.Identifier({ line: 1, name: 'do' }),
  74. args: [new AST.Identifier({ line: 1, name: 'this' })],
  75. }),
  76. elseCase: new AST.Application({
  77. function: new AST.Identifier({ line: 1, name: 'do' }),
  78. args: [new AST.Identifier({ line: 1, name: 'that' })],
  79. }),
  80. }),
  81. ])
  82. })
  83. test('missing close paren returns error', t => {
  84. t.plan(1)
  85. const tree = helpers.parse('(p ""')
  86. t.deepEqual(
  87. tree,
  88. new OsloError({
  89. line: 1,
  90. message: 'Encountered an unexpected EOF while looking for a ).',
  91. }),
  92. )
  93. })
  94. test('missing close quote returns an error', t => {
  95. t.plan(1)
  96. const tree = helpers.parse('(p "hello world)')
  97. t.deepEqual(
  98. tree,
  99. new OsloError({
  100. line: 1,
  101. message: 'Encountered an unexpected EOF while looking for a ".',
  102. }),
  103. )
  104. })
  105. test('allow returning atomic value from lambda', t => {
  106. t.plan(1)
  107. const tree = helpers.parse('(lambda (x) x)')
  108. t.deepEqual(tree, [
  109. new AST.Lambda({
  110. parameters: [new AST.Identifier({ name: 'x' })],
  111. body: new AST.Identifier({ name: 'x', line: 1 }),
  112. }),
  113. ])
  114. })