commit 6d71aca625db7dea237604472baa55c9f55c84f5
Author: Jan Pobrislo <ccx@webprojekty.cz>
Date: Wed, 14 Aug 2013 22:02:38 +0200
initial commit
Diffstat:
4 files changed, 166 insertions(+), 0 deletions(-)
diff --git a/bin/aat b/bin/aat
@@ -0,0 +1,7 @@
+#!/bin/sh
+: ${AWK:=awk}
+: ${SED:=awk}
+DIR="$(dirname "$0")"
+TEMPLATE="$1"
+shift
+$AWK -f "$DIR/aat.awk" "$TEMPLATE" | sed -f "$DIR/aat_macros.sed" | awk -f /dev/stdin "$@"
diff --git a/bin/aat.awk b/bin/aat.awk
@@ -0,0 +1,142 @@
+#!/bin/awk -f
+BEGIN {
+ tok_n = 0
+ mode = "t"
+}
+
+function token(content) {
+ if(!content) return
+ if(tok_n && mode == tok_type[tok_n] && tok_content[tok_n] !~ "\n$") {
+ #if(DEBUG) printf "concat \"%s\" \"%s\"\n", tok_content[tok_n], content
+ tok_content[tok_n] = tok_content[tok_n] content
+ } else {
+ tok_type[++tok_n] = mode
+ tok_content[tok_n] = content
+ }
+ if(DEBUG) printf "token %d (%s): \"%s\"\n", tok_n, mode, tok_content[tok_n] >"/dev/stderr"
+}
+
+{
+ line = $0
+ while(length(line)) {
+ if(DEBUG) printf "%d: \"%s\"\n", tok_n, line >"/dev/stderr"
+ eat_nl = 0
+ if(mode == "t") {
+ m = match(line, /\{[{%]/)
+ if(m) {
+ # start expression
+ token(substr(line, 1, m-1))
+ if (substr(line, m, RLENGTH) == "{{")
+ mode = "e"
+ else
+ mode = "a"
+ line = substr(line, m+RLENGTH)
+ } else {
+ token(line)
+ line = ""
+ }
+ } else if(mode == "e" || mode == "a") {
+ if(mode == "e")
+ m = match(line, /^(}?([^}"]|("([^"]|\\")*")))+/)
+ else
+ m = match(line, /^([^%"]|(%+[^}%"])|("([^"]|\\")*"))+/)
+ if(m) {
+ if(DEBUG) printf "expr match: \"%s\"\n", substr(line, m, RLENGTH) >"/dev/stderr"
+ token(substr(line, 1, RLENGTH))
+ line = substr(line, RLENGTH+1)
+ } else if(length(line) == 1) {
+ # end of line
+ token(line)
+ line = ""
+ } else if(match(line, /^%+$/)) {
+ token(line)
+ line = ""
+ } else if( \
+ (mode == "e" && substr(line, 1, 2) == "}}") || \
+ (mode == "a" && substr(line, 1, 2) == "%}") ) {
+ # end of expression
+ if(mode == "a") eat_nl = 1
+ mode = "t"
+ line = substr(line, 3)
+ } else {
+ print "ERROR: could not parse line " NR ": " line >"/dev/stderr"
+ exit 1
+ }
+ } else {
+ print "ERROR: unknown mode: " mode >"/dev/stderr"
+ exit 1
+ }
+ if(DEBUG) printf "-<%s>- \"%s\"\n", mode, line >"/dev/stderr"
+ }
+
+ # don't add newline just after the code block
+ if(eat_nl)
+ eat_nl = 0
+ else
+ token("\n")
+}
+
+function apply_macros(c) {
+ orig = c
+ for(man_apply_n in macros) {
+ m = macros[man_apply_n]
+ if(!match(m, /^\/([^\/]|(\\\/))+\//)) {
+ print "ERROR: invalid macro regexp: " m >"/dev/stderr"
+ exit 1
+ }
+ regexp = substr(m, 2, RLENGTH-2)
+ m = substr(m, RLENGTH+1)
+ if(!match(m, /^([^\/]|(\\\/))*\//)) {
+ print "ERROR: invalid macro replacement: " m >"/dev/stderr"
+ exit 1
+ }
+ replacement = substr(m, 1, RLENGTH-1)
+ flags = substr(m, RLENGTH)
+ # gensub() is not posix
+ if(match(flags, /g/))
+ sub_count = gsub(regexp, replacement, c)
+ else
+ sub_count = sub(regexp, replacement, c)
+ if(DEBUG && sub_count) printf "code \"%s\" matched macro /%s/, replacing with \"%s\", flags \"%s\"\n", orig, regexp, replacement, flags
+ if(sub_count) {
+ if(match(flags, /r/))
+ return apply_macros(c)
+ return c
+ }
+ }
+ return c
+}
+
+END {
+ nl = 1
+ mac_n = 0
+ for(tok_n=1; tok_type[tok_n]; tok_n++) {
+ mode = tok_type[tok_n]
+ c = tok_content[tok_n]
+ if(nl && mode != "a") {
+ printf "%s", "printf \"%s\", "
+ nl = 0
+ }
+ if(mode == "t") {
+ linebreak = match(c, "\n$")
+ gsub(/\\/, "\\\\", c)
+ gsub(/"/, "\\\"", c)
+ gsub(/\n/, "\\n", c)
+ printf "\"%s\"%s", c, (linebreak ? "\n" : "")
+ nl = linebreak
+ } else if(mode == "a") {
+ if(match(c, /\/([^\/]|(\\\/))+\/([^\/]|(\\\/))*\/[[:alpha:]]*/)) {
+ macros[++mac_n] = c
+ } else {
+ c = apply_macros(c)
+ printf "%s%s%s", (nl ? "" : "\n"), c, (c ~ /\n$/ ? "" : "\n")
+ nl = 1
+ }
+ } else if(mode == "e") {
+ printf "%s", c
+ } else {
+ print "ERROR: unknown mode: " mode >"/dev/stderr"
+ exit 1
+ }
+ }
+}
diff --git a/bin/aat_macros.sed b/bin/aat_macros.sed
@@ -0,0 +1,7 @@
+#!/bin/sed -f
+s/^[[:space:]]*FOR[[:space:]]\+\([[:alnum:]]\+\)[[:space:]]\+IN[[:space:]]\+\(.\+\)$/for(last in \2){};for(key in \2){\n\1 = \2[key]; is_last = key == last/
+s/^[[:space:]]*ENDFOR[[:space:]]*$/}/
+s/^[[:space:]]*IF[[:space:]]\+\(.\+\)$/if(\1) {\n/
+s/^[[:space:]]*ELIF[[:space:]]\+\(.\+\)$/} else if(\1) {\n/
+s/^[[:space:]]*ELSE[[:space:]]*$/} else {/
+s/^[[:space:]]*ENDIF[[:space:]]*$/}/
diff --git a/hello.aat b/hello.aat
@@ -0,0 +1,10 @@
+{%#!/bin/awk -f
+BEGIN {
+split("Jack Joe Jonathan", names)
+FOR name IN names
+%}
+Hello {{name (is_last ? "!" : ",")}}
+{% ENDFOR %}
+
+Welcome to the world of {{toupper("awk")}} templating!
+{%}%}