diff src/implab/text/format-compile.js @ 0:fc2517695ee1

Initial commit, draft import of existing work
author cin
date Thu, 01 Jun 2017 13:20:03 +0300
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/implab/text/format-compile.js	Thu Jun 01 13:20:03 2017 +0300
@@ -0,0 +1,101 @@
+define(
+    [],
+    function() {
+        var map = {
+            "\\{" : "&curlopen;",
+            "\\}" : "&curlclose;",
+            "&" : "&",
+            "\\:" : ":"
+        };
+
+        var rev = {
+            curlopen : "{",
+            curlclose : "}",
+            amp : "&",
+            colon : ":"
+        };
+
+        var espaceString = function(s) {
+            if (!s)
+                return s;
+            return "'" + s.replace(/('|\\)/g, "\\$1") + "'";
+        };
+
+        var encode = function(s) {
+            if (!s)
+                return s;
+            return s.replace(/\\{|\\}|&|\\:/g, function(m) {
+                return map[m] || m;
+            });
+        };
+
+        var decode = function(s) {
+            if (!s)
+                return s;
+            return s.replace(/&(\w+);/g, function(m, $1) {
+                return rev[$1] || m;
+            });
+        };
+
+        var subst = function(s) {
+            var i = s.indexOf(":"), name, pattern;
+            if (i >= 0) {
+                name = s.substr(0, i);
+                pattern = s.substr(i + 1);
+            } else {
+                name = s;
+            }
+
+            if (pattern)
+                return [
+                    espaceString(decode(name)),
+                    espaceString(decode(pattern)) ];
+            else
+                return [ espaceString(decode(name)) ];
+        };
+
+        var compile = function(str) {
+            if (!str)
+                return function() {};
+
+            var chunks = encode(str).split("{"), chunk;
+
+            var code = [ "var result=[];" ];
+
+            for (var i = 0; i < chunks.length; i++) {
+                chunk = chunks[i];
+
+                if (i === 0) {
+                    if (chunk)
+                        code.push("result.push(" + espaceString(decode(chunk)) +
+                            ");");
+                } else {
+                    var len = chunk.indexOf("}");
+                    if (len < 0)
+                        throw new Error("Unbalanced substitution #" + i);
+
+                    code.push("result.push(subst(" +
+                        subst(chunk.substr(0, len)).join(",") + "));");
+                    if (chunk.length > len + 1)
+                        code.push("result.push(" +
+                            espaceString(decode(chunk.substr(len + 1))) + ");");
+                }
+            }
+
+            code.push("return result.join('');");
+
+            /* jshint -W054 */
+            return new Function("subst", code.join("\n"));
+        };
+
+        var cache = {};
+
+        return function(template) {
+            var compiled = cache[template];
+            if (!compiled) {
+                compiled = compile(template);
+                cache[template] = compiled;
+            }
+            return compiled;
+        };
+    });
\ No newline at end of file