aat

git mirror of https://ccx.te2000.cz/bzr/aat
git clone https://ccx.te2000.cz/git/aat
Log | Files | Refs | README

commit 6d71aca625db7dea237604472baa55c9f55c84f5
Author: Jan Pobrislo <ccx@webprojekty.cz>
Date:   Wed, 14 Aug 2013 22:02:38 +0200

initial commit
Diffstat:
Abin/aat | 7+++++++
Abin/aat.awk | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Abin/aat_macros.sed | 7+++++++
Ahello.aat | 10++++++++++
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! +{%}%}