Implement classes with syntax like "div.my-class.my-class2() {}", improve handling...
authorNick Downing <downing.nick@gmail.com>
Sun, 14 Oct 2018 11:52:41 +0000 (22:52 +1100)
committerNick Downing <nick@ndcode.org>
Tue, 30 Oct 2018 07:54:35 +0000 (18:54 +1100)
page.jst
src/expression.js
src/lval.js
template.js

index c031dcd..722c626 100644 (file)
--- a/page.jst
+++ b/page.jst
@@ -1,4 +1,4 @@
-async _env => html(lang=_env.lang val=_env.val quoted-val="\"val\"") {
+async _env => html.'cls-1'.cls-2(lang=_env.lang true=_env.val something-else="\"val\"") {
   head {}
   body {
     `hello
index 60d9168..5a35146 100644 (file)
@@ -264,7 +264,8 @@ pp.parseSubscripts = function(base, startPos, startLoc, noCalls) {
     if ((computed = this.eat(tt.bracketL)) || this.eat(tt.dot)) {
       let node = this.startNodeAt(startPos, startLoc)
       node.object = base
-      node.property = computed ? this.parseExpression() : this.parseIdent(true)
+      //node.property = computed ? this.parseExpression() : this.parseIdent(true)
+      node.property = computed ? this.parseExpression() : this.type === tt.string ? this.parseLiteral(this.value) : this.parseIdent(true) // Nick
       node.computed = !!computed
       if (computed) this.expect(tt.bracketR)
       base = this.finishNode(node, "MemberExpression")
@@ -400,7 +401,7 @@ pp.parseExprAtom = function(refDestructuringErrors) {
     return this.parseTemplate()
 
   default:
-    this.unexpected()
+    return this.parseIdent(true) // Nick this.unexpected()
   }
 }
 
index 847ba36..e5ba610 100644 (file)
@@ -80,14 +80,15 @@ pp.toAssignable = function(node, isBinding, refDestructuringErrors) {
       this.raise(node.start, "Assigning to rvalue")
 
     case "BinaryExpression": // Nick
+    case "Literal": // Nick
       let temp = node
       while (
         temp.type === "BinaryExpression" &&
         temp.operator === "-" &&
-        temp.right.type === "Identifier"
+        (temp.right.type === "Identifier" || temp.right.type === "Literal")
       )
         temp = temp.left
-      if (temp.type !== "Identifier")
+      if (temp.type !== "Identifier" && temp.type !== "Literal")
         this.raise(node.start, "Assigning to rvalue")
       break
     }
@@ -247,14 +248,15 @@ pp.checkLVal = function(expr, bindingType = BIND_NONE, checkClashes) {
     this.raise(expr.start, (bindingType ? "Binding" : "Assigning to") + " rvalue")
 
   case "BinaryExpression": // Nick
+  case "Literal": // Nick
     let temp = expr
     while (
       temp.type === "BinaryExpression" &&
       temp.operator === "-" &&
-      temp.right.type === "Identifier"
+        (temp.right.type === "Identifier" || temp.right.type === "Literal")
     )
       temp = temp.left
-    if (temp.type !== "Identifier")
+    if (temp.type !== "Identifier" && temp.type !== "Literal")
       this.raise(expr.start, (bindingType ? "Binding" : "Assigning to") + " rvalue")
     break
   }
index 816101b..0d273c5 100644 (file)
@@ -2,49 +2,90 @@ let assert = require('assert')
 let transform = require('./transform')
 let html_escape = require('html-escape')
 
-let html_body = (node, st, c) => {
-  let tag, arguments
-  if (node.tag.type === 'CallExpression') {
-    tag = node.tag.callee
-    arguments = node.tag.arguments
+let expr_to_tag = (node, context, html_allowed, call_allowed) => {
+  if (node.type === 'Identifier')
+    context.name.push(node.name)
+  else if (node.type === 'Literal')
+    context.name.push(node.value.toString())
+  else if (node.type === 'BinaryExpression' && node.operator === '-') {
+    if (!expr_to_tag(node.left, context, false, false))
+      return false;
+    if (!expr_to_tag(node.right, context, html_allowed, call_allowed))
+      return false;
   }
-  else {
-    tag = node.tag
-    arguments = []
+  else if (node.type === 'MemberExpression') {
+    if (!expr_to_tag(node.object, context, false, false))
+      return false;
+    context.tag[context.tag_type].push(context.name.join('-'))
+    context.name = []
+    context.tag_type = 1
+    if (!expr_to_tag(node.property, context, html_allowed, call_allowed))
+      return false;
   }
-  assert(tag.type === 'Identifier')
+  else if (html_allowed && node.type === 'HTMLExpression') {
+    if (!expr_to_tag(node.tag, context, false, true))
+      return false;
+    context.tag[context.tag_type].push(context.name.join('-'))
+    context.body = node.body
+  }
+  else if (call_allowed && node.type === 'CallExpression') {
+    if (!expr_to_tag(node.callee, context, false, false))
+      return false;
+    context.arguments = node.arguments
+  }
+  else
+    return false;
+  return true;
+} 
+
+let expr_to_name = (node, name) => {
+  if (node.type === 'Identifier')
+    name.push(node.name)
+  else if (node.type === 'Literal')
+    name.push(node.value.toString())
+  else if (node.type === 'BinaryExpression' && node.operator === '-') {
+    expr_to_name(node.left, name)
+    expr_to_name(node.right, name)
+  }
+  else
+    assert(false)
+}
+
+let html_body = (context, st, c) => {
+  assert(context.tag[0].length == 1)
+  let tag = context.tag[0][0]
+  let prefix = '<' + tag
+
+  if (context.tag[1].length)
+    prefix += ' class="' + context.tag[1].join(' ') + '"'
+
+  let expr = undefined
+  for (var i = 0; i < context.arguments.length; ++i) {
+    let argument = context.arguments[i]
 
-  let prefix = '<' + tag.name, expr = undefined, expr1;
-  for (var i = 0; i < arguments.length; ++i) {
     let name_expr, value_expr
-    if (arguments[i].type === 'AssignmentExpression') {
-      name_expr = arguments[i].left
-      value_expr = arguments[i].right
+    if (
+      argument.type === 'AssignmentExpression' &&
+      argument.operator === '='
+    ) {
+      name_expr = argument.left
+      value_expr = c(argument.right, st, 'Expression')
     }
     else {
-      name_expr = arguments[i]
+      name_expr = argument
       value_expr = undefined
     }
 
-    let name = ''
-    while (
-      name_expr.type === 'BinaryExpression' &&
-      name_expr.operator === '-' &&
-      name_expr.right.type === 'Identifier'
-    ) {
-      name = '-' + name_expr.right.name + name
-      name_expr = name_expr.left
-    }
-    assert(name_expr.type === 'Identifier')
-    name = name_expr.name + name
-    prefix += ' ' + name
+    name = []
+    expr_to_name(name_expr, name)
+    prefix += ' ' + name.join('-')
+
     if (value_expr !== undefined) {
       prefix += '="'
       if (value_expr.type === 'Literal')
         prefix += html_escape(value_expr.value)
       else {
-        expr1 = {
+        let expr1 = {
           type: 'Literal',
           value: prefix
         }
@@ -54,9 +95,7 @@ let html_body = (node, st, c) => {
             type: 'BinaryExpression',
             left: expr,
             operator: '+',
-            right: expr1,
-            start: node.start,
-            end: node.end
+            right: expr1
           },
           operator: '+',
           right: {
@@ -88,7 +127,8 @@ let html_body = (node, st, c) => {
       prefix += '"'
     }
   }
-  expr1 = {
+
+  let expr1 = {
     type: 'Literal',
     value: prefix + '>',
   }
@@ -98,6 +138,7 @@ let html_body = (node, st, c) => {
     operator: '+',
     right: expr1,
   }
+
   let result = [
     {
       type: 'ExpressionStatement',
@@ -120,13 +161,13 @@ let html_body = (node, st, c) => {
         ]
       }
     }
-  ].concat(c(node.body, st, 'Statement').body)
+  ].concat(c(context.body, st, 'Statement').body)
   if (
-    tag.name !== 'br' &&
-    tag.name !== 'img' &&
-    tag.name !== 'input' &&
-    tag.name !== 'link' &&
-    tag.name !== 'meta'
+    tag !== 'br' &&
+    tag !== 'img' &&
+    tag !== 'input' &&
+    tag !== 'link' &&
+    tag !== 'meta'
   )
     result.push(
       {
@@ -148,7 +189,7 @@ let html_body = (node, st, c) => {
           arguments: [
             {
               type: 'Literal',
-              value: '</' + tag.name + '>'
+              value: '</' + tag + '>'
             }
           ]
         }
@@ -159,111 +200,137 @@ let html_body = (node, st, c) => {
 
 let visitors = Object.assign({}, transform.visitors)
 let visitors_ExpressionStatement = visitors.ExpressionStatement
-visitors.ExpressionStatement = (node, st, c) =>
-  node.expression.type === 'Literal' ||
-  node.expression.type === 'TemplateLiteral' ||
-  node.expression.type === 'TaggedTemplateLiteral' ?
-  {
-    type: 'ExpressionStatement',
-    expression: {
-      type: 'CallExpression',
-      callee: {
-        type: 'MemberExpression',
-        object: {
-          type: 'Identifier',
-          name: '_out'
-        },
-        property: {
-          type: 'Identifier',
-          name: 'push'
-        },
-        computed: false
-      },
-      arguments: [
-        {
-          type: 'CallExpression',
-          callee: {
+visitors.ExpressionStatement = (node, st, c) => {
+  if (
+    node.expression.type === 'Literal' ||
+    node.expression.type === 'TemplateLiteral' ||
+    node.expression.type === 'TaggedTemplateLiteral'
+  )
+    return {
+      type: 'ExpressionStatement',
+      expression: {
+        type: 'CallExpression',
+        callee: {
+          type: 'MemberExpression',
+          object: {
             type: 'Identifier',
-            name: '_esc'
+            name: '_out'
           },
-          arguments: [
-            c(node.expression, st, 'Expression')
-          ]
-        }
-      ]
-    }
-  } :
-  node.expression.type === 'HTMLExpression' ?
-  {
-      type: 'BlockStatement',
-      body: html_body(node.expression, st, c)
-  } :
-  visitors_ExpressionStatement(node, st, c)
-visitors.HTMLExpression = (node, st, c) => {
-  return {
-    type: 'CallExpression',
-    callee: {
-      type: 'ArrowFunctionExpression',
-      id: null,
-      expression: false,
-      generator: false,
-      async: false,
-      params: [],
-      body: {
-        type: 'BlockStatement',
-        body: [
+          property: {
+            type: 'Identifier',
+            name: 'push'
+          },
+          computed: false
+        },
+        arguments: [
           {
-            type: 'VariableDeclaration',
-            declarations: [
-              {
-                type: 'VariableDeclarator',
-                id: {
-                  type: 'Identifier',
-                  name: '_out'
-                },
-                init: {
-                  type: 'ArrayExpression',
-                  elements: []
-                }
-              }
-            ],
-            kind: 'let'
+            type: 'CallExpression',
+            callee: {
+              type: 'Identifier',
+              name: '_esc'
+            },
+            arguments: [
+              c(node.expression, st, 'Expression')
+            ]
           }
         ]
-        .concat(html_body(node, st, c))
-        .concat(
-          [
-            {
-              type: 'ReturnStatement',
-              argument: {
-                type: 'CallExpression',
-                callee: {
-                  type: 'MemberExpression',
-                  object: {
-                    type: 'Identifier',
-                    name: '_out'
-                  },
-                  property: {
-                    type: 'Identifier',
-                    name: 'join'
-                  },
-                  computed: false
-                },
-                arguments: [
+      }
+    }
+  if (
+    node.expression.type === 'BinaryExpression' ||
+    node.expression.type === 'MemberExpression' ||
+    node.expression.type === 'HTMLExpression'
+  ) {
+    context = {name: [], tag: [[], []], tag_type: 0, arguments: []}
+    if (
+      expr_to_tag(node.expression, context, true, false) &&
+      context.body !== undefined
+    )
+      return {
+        type: 'BlockStatement',
+        body: html_body(context, st, c)
+      }
+  }
+  return visitors_ExpressionStatement(node, st, c)
+}
+let visitors_Expression = visitors.Expression
+visitors.Expression = (node, st, c) => {
+  if (
+    node.type === 'BinaryExpression' ||
+    node.type === 'MemberExpression' ||
+    node.type === 'HTMLExpression'
+  ) {
+    context = {name: [], tag: [[], []], tag_type: 0, arguments: []}
+    if (
+      expr_to_tag(node, context, true, false) &&
+      context.body !== undefined
+    )
+      return {
+        type: 'CallExpression',
+        callee: {
+          type: 'ArrowFunctionExpression',
+          id: null,
+          expression: false,
+          generator: false,
+          async: false,
+          params: [],
+          body: {
+            type: 'BlockStatement',
+            body: [
+              {
+                type: 'VariableDeclaration',
+                declarations: [
                   {
-                    type: 'Literal',
-                    value: '',
-                    raw: '\'\''
+                    type: 'VariableDeclarator',
+                    id: {
+                      type: 'Identifier',
+                      name: '_out'
+                    },
+                    init: {
+                      type: 'ArrayExpression',
+                      elements: []
+                    }
                   }
-                ]
+                ],
+                kind: 'let'
               }
-            }
-          ]
-        )
+            ]
+            .concat(html_body(context, st, c))
+            .concat(
+              [
+                {
+                  type: 'ReturnStatement',
+                  argument: {
+                    type: 'CallExpression',
+                    callee: {
+                      type: 'MemberExpression',
+                      object: {
+                        type: 'Identifier',
+                        name: '_out'
+                      },
+                      property: {
+                        type: 'Identifier',
+                        name: 'join'
+                      },
+                      computed: false
+                    },
+                    arguments: [
+                      {
+                        type: 'Literal',
+                        value: '',
+                        raw: '\'\''
+                      }
+                    ]
+                  }
+                }
+              ]
+            )
+          }
+        },
+        arguments: []
       }
-    },
-    arguments: []
   }
+  return visitors_Expression(node, st, c)
 }
 
 module.exports = visitors