author | Michael Krelin <hacker@klever.net> | 2011-08-26 21:22:00 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2011-08-26 21:22:00 (UTC) |
commit | 1d00b262ddf0d6c3207a4b796d48899ed79bffcd (patch) (side-by-side diff) | |
tree | 03d745873ba13ffb0e2fe1831ecb41f7c0b05758 | |
download | cliche-1d00b262ddf0d6c3207a4b796d48899ed79bffcd.zip cliche-1d00b262ddf0d6c3207a4b796d48899ed79bffcd.tar.gz cliche-1d00b262ddf0d6c3207a4b796d48899ed79bffcd.tar.bz2 |
initial commit into the public repository0.0
Signed-off-by: Michael Krelin <hacker@klever.net>
-rw-r--r-- | .gitignore | 18 | ||||
-rw-r--r-- | AUTHORS | 3 | ||||
-rw-r--r-- | COPYING | 19 | ||||
-rw-r--r-- | ChangeLog | 0 | ||||
-rw-r--r-- | Makefile.am | 15 | ||||
-rw-r--r-- | NEWS.xml | 6 | ||||
-rw-r--r-- | NEWS.xsl | 24 | ||||
-rw-r--r-- | README | 16 | ||||
-rw-r--r-- | autogen.bash | 6 | ||||
-rw-r--r-- | configure.ac | 23 | ||||
-rw-r--r-- | src/.gitignore | 3 | ||||
-rw-r--r-- | src/Makefile.am | 15 | ||||
-rw-r--r-- | src/cliche.1 | 99 | ||||
-rw-r--r-- | src/cliche.rl | 331 | ||||
-rw-r--r-- | test/.gitignore | 22 | ||||
-rw-r--r-- | test/Makefile.am | 32 | ||||
-rw-r--r-- | test/r01_closing_at_the_line_start.clichec | 16 | ||||
-rw-r--r-- | test/r01_closing_at_the_line_start.expected | 8 | ||||
-rw-r--r-- | test/r02_anchor_after_literal.clichec | 8 | ||||
-rw-r--r-- | test/r02_anchor_after_literal.expected | 3 | ||||
-rw-r--r-- | test/r03_percent_after_empty.clichec | 8 | ||||
-rw-r--r-- | test/r03_percent_after_empty.expected | 6 | ||||
-rw-r--r-- | test/r04_too_seamless_transitions.clichec | 9 | ||||
-rw-r--r-- | test/r04_too_seamless_transitions.expected | 3 |
24 files changed, 693 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8523ddd --- a/dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +/INSTALL +Makefile +Makefile.in +/aclocal.m4 +/autom4te.cache/ +/config.h +/config.h.in +/config.log +/config.status +/configure +/depcomp +/install-sh +/missing +/stamp-h1 +.deps/ +/NEWS +*.o +*.cliche.cc @@ -0,0 +1,3 @@ +Klever dissected: + Michael 'hacker' Krelin <hacker@klever.net> + Leonid Ivanov <kamel@klever.net> @@ -0,0 +1,19 @@ +Copyright (c) 2011 Klever Group (http://www.klever.net/) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 --- a/dev/null +++ b/ChangeLog diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..77e96ad --- a/dev/null +++ b/Makefile.am @@ -0,0 +1,15 @@ +SUBDIRS=src test + +all-local: NEWS + +NEWS: NEWS.xsl NEWS.xml + $(XSLTPROC) -o $@ $^ +EXTRA_DIST = NEWS.xml NEWS.xsl + +ISSUEFILES = $$(find ${top_srcdir} -type f '(' \ + -name '*.rl' -or -name '*.h' \ + ')' ) \ + ${top_srcdir}/configure.ac +issues: todo fixme xxx +todo fixme xxx: + @grep --color=auto -in '$@:' ${ISSUEFILES} || true diff --git a/NEWS.xml b/NEWS.xml new file mode 100644 index 0000000..106fbbd --- a/dev/null +++ b/NEWS.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="us-ascii"?> +<news> + <version version="0.0" date="Aug 27th, 2011"> + <ni>Initial release</ni> + </version> +</news> diff --git a/NEWS.xsl b/NEWS.xsl new file mode 100644 index 0000000..7c71307 --- a/dev/null +++ b/NEWS.xsl @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="us-ascii"?> +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + > + <xsl:output + method="text" + encoding="us-ascii" + media-type="text/plain" /> + + <xsl:template match="news"> + <xsl:apply-templates/> + </xsl:template> + <xsl:template match="version"> + <xsl:value-of select="concat(@version,' (',@date,')
')"/> + <xsl:apply-templates/> + </xsl:template> + <xsl:template match="ni"> + <xsl:text> - </xsl:text> + <xsl:apply-templates mode="text"/> + <xsl:text>
</xsl:text> + </xsl:template> + <xsl:template match="*|text()"/> + +</xsl:stylesheet> @@ -0,0 +1,16 @@ +Constructs: + +code embedded in output: +<%code> ++i; </%code> +% ++i; + +output embedded in code: +int i=0; +<%output>whoa, it's <% i++ %>!</%output> + +embed literal in the code: +#define URL "http://www.klever.net/" +<%literal> + a text that is going to be there is a string + with some possibilities <% URL %> +</%literal> diff --git a/autogen.bash b/autogen.bash new file mode 100644 index 0000000..14798fd --- a/dev/null +++ b/autogen.bash @@ -0,0 +1,6 @@ +#!/bin/bash + aclocal \ +&& autoheader \ +&& automake -a \ +&& autoconf \ +&& ./configure "$@" diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..4ecdb31 --- a/dev/null +++ b/configure.ac @@ -0,0 +1,23 @@ +AC_INIT([cliche],[0.0],[cliche-bugs@klever.net]) +AC_CONFIG_SRCDIR([src/cliche.rl]) +AC_CONFIG_HEADERS([config.h]) +AM_INIT_AUTOMAKE([check-news dist-bzip2 parallel-tests color-tests]) + +AC_PROG_INSTALL +AC_PROG_CXX +AC_PATH_PROG([RAGEL],[ragel],[false]) +test "$RAGEL" = "false" && AC_MSG_ERROR([No ragel FSM compiler found]) +AC_PROG_SED + +AC_PATH_PROG([XSLTPROC],[xsltproc],[true]) + +AC_CHECK_FUNC([getopt_long],[ + AC_DEFINE([HAVE_GETOPT_LONG],[1],[define to make use of getopt_long]) +]) + +AC_CONFIG_FILES([ + Makefile + src/Makefile + test/Makefile +]) +AC_OUTPUT diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..090e0ca --- a/dev/null +++ b/src/.gitignore @@ -0,0 +1,3 @@ +/COPYING.cc +/cliche +/cliche.cc diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..d5102a7 --- a/dev/null +++ b/src/Makefile.am @@ -0,0 +1,15 @@ +bin_PROGRAMS = cliche +man_MANS = cliche.1 + +EXTRA_DIST=$(man_MANS) + +cliche_SOURCES = cliche.rl COPYING.cc +CLEANFILES=cliche.cc + +COPYING.cc: ${top_srcdir}/COPYING + (echo 'const char *COPYING=' \ + && $(SED) -e 's/"/\\"/g' -e 's/^/\"/' -e 's/$$/\\n\"/' \ + && echo ';') <$< >$@ || (rm $@;exit 1) + +.rl.cc: + $(RAGEL) -C -o $@ $< diff --git a/src/cliche.1 b/src/cliche.1 new file mode 100644 index 0000000..af61a15 --- a/dev/null +++ b/src/cliche.1 @@ -0,0 +1,99 @@ +.TH cliche 1 "August 27th, 2011" "cliche" "Klever Group (http://www.klever.net/)" +.hla en + +.SH NAME + +cliche \- A tinimalistc template preprocessor for c++ + +.SH SYNOPSYS + +\fBcliche\fR +[\fB-h\fR] [\fB--help\fR] [\fB--usage\fR] +[\fB-V\fR] [\fB--version\fR] +[\fB-L\fR] [\fB--license\fR] +[\fB-o\fR \fIfile\fR] [\fB--output=\fR\fIfile\fR] +[\fB-t\fR \fIcode\fR|\fIoutput\fR] [\fB--top=\fR\fIcode\fR|\fIoutput\fR] +[\fB-C\fR] [\fB-O\fR] + +.SH DESCRIPTION + +cliche preprocesses its input to produce c++ code streaming +out the template while executing embedded c++ code and +expressions. + +An example of cliche input file may look like this: + +.ti 1 +#include <iostream> +.ti 1 +int main() { +.ti 2 + for(int i=0;i<5;++i) { +.ti 3 + <%output> +.ti 4 + <i>Whoa, it's <b><% i %></b> already!</i><br/> +.ti 3 + </%output> +.ti 2 + } +.ti 1 +} + +.SH OPTIONS + +.TP +\fB-o\fR \fIfile\fR, \fB--output=\fR\fIfile\fR +Write output to the specified file. +.TP +\fB-t\fR \fIcode\fR|\fIoutput\fR, \fB--top=\fR\fIcode\fR|\fIoutput\fR +Expect input to have code or output (as if in <%code></%code> or <%output></%output> block) on the top-level. Code templates are suitable for feeding into compiler as is, whereas output templates may be better suited for #include. +.TP +\fB-C\fR +Same as \fB-t code\fR. +.TP +\fB-O\fR +Same as \fB-t output\fR. +.TP +\fB-h\fR, \fB--help\fR, \fB--usage\fR +Display short usage instructions and exit. +.TP +\fB-V\fR, \fB--version\fR +Report version and exit. +.TP +\fB-L\fR, \fB--license\fR +Show licensing terms. + +.SH EXIT STATUS +Unsurprisingly, \fBcliche\fR returns zero in case of success and non-zero otherwise. + +.SH AUTHOR + +Written by Michael Krelin <hacker@klever.net> + + +.SH COPYRIGHT + +Copyright (c) 2011 Klever Group (http://www.klever.net/) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +.SH BUGS + +You tell me. Send reports to <cliche-bugs@klever.net> diff --git a/src/cliche.rl b/src/cliche.rl new file mode 100644 index 0000000..1f1f07f --- a/dev/null +++ b/src/cliche.rl @@ -0,0 +1,331 @@ +#include <getopt.h> +#include <iostream> +#include <cstring> +#include <cassert> +#include <algorithm> +#include <fstream> + +#include "config.h" + +struct line_counting_monkey { + int n; + const char *p; + const char *fn; + + line_counting_monkey(const char *fn_,const char *p_) : fn(fn_), n(1), p(p_) { } + + int lineno(const char *pp) { + if(pp>p) { + n += std::count(p,pp,'\n'); + p = pp; + } + return n; + } +}; + +struct code_writing_monkey { + std::ostream& o; + enum omode_type { + om_code = 0, om_output, om_inline, om_literal, + oms + }; + omode_type omode; + int last_anchor, since_anchor; + + code_writing_monkey(std::ostream& o_) : o(o_), omode(om_code), last_anchor(-1), since_anchor(0) { } + + void modify(omode_type om,line_counting_monkey* lcm=0,const char *p=0) { + static const char *om_transitions[oms][oms] = { + // To: From: + // code output inline literal + { "", "CLICHE_OUTPUT_LITERAL(\n", "CLICHE_STREAM << (", "" }, // code + { ");\n", "", ");\n(CLICHE_STREAM) << (", 0 }, // output + { ");\n", ");\nCLICHE_OUTPUT_LITERAL(\n", "", 0 }, // inline + { " ", 0, 0, "" }, // literal + }; + assert(0 <= omode && omode < oms); + assert(0 <= om && om < oms); + const char *t = om_transitions[omode][om]; + assert(t); // TODO: complain? + o << t; + since_anchor += std::count(t,t+strlen(t),'\n'); + if(lcm && t && *t && om!=omode && p) anchor(*lcm,p); + omode = om; + } + + void prologue() { + assert(omode==om_code); + o << + "#ifndef CLICHE_STREAM\n" + "# define CLICHE_STREAM (std::cout)\n" + "# define CLICHE_STREAM_AUTODEFINED\n" + "#endif\n" + "#ifndef CLICHE_OUTPUT_LITERAL\n" + "# define CLICHE_OUTPUT_LITERAL(sl) (CLICHE_STREAM).write((sl),sizeof(sl)-sizeof(\"\"))\n" + "#endif\n"; + } + void epilogue() { + modify(om_code); + o << "\n" + "#ifdef CLICHE_STREAM_AUTODEFINED\n" + "# undef CLICHE_STREAM\n" + "# undef CLICHE_STREAM_AUTODEFINED\n" + "#endif\n"; + } + + void monkey(const char *d,size_t l=0) { + if(!(l || (l=strlen(d)))) return; + if(omode!=om_output && omode!=om_literal) { + since_anchor += std::count(d,d+l,'\n'); + o.write(d,l); + return; + } + o.put('"'); + const char *p=d; + while(l--) { + char c; + switch(*d) { + case '\r': c='r'; break; + case '\n': c='n'; break; + case '\t': c='t'; break; + case '\a': c='a'; break; + case '\b': c='b'; break; + case '\v': c='v'; break; + case '\f': c='f'; break; + case '\'': case '\"': case '\\': c=*d; break; + case 0: c='0'; break; + default: c=0; break; + }; + if(!c) { + ++d; + continue; + } + if(p!=d) o.write(p,d-p); + o.put('\\'); + if(c=='0') + o.write("000",3); + else + o.put(c); + p=++d; + } + if(p!=d) o.write(p,d-p); + o.write("\"\n",2); ++since_anchor; + } + + void monkey_as(omode_type om,const char *d,size_t l=0,line_counting_monkey *lcm=0,const char *p=0) { modify(om,lcm,p); monkey(d,l); } + + void anchor(line_counting_monkey& lcm,const char *p) { + // modify(om_code); + int l = lcm.lineno(p); + if(last_anchor>0 && last_anchor+since_anchor==l) return; + o << "\n#line " << (since_anchor=0,last_anchor=l) << " \"" << lcm.fn << "\"\n"; + } +}; + + +%%{ + machine cliche; + + linebreak = /[\r\n]/; + + action monkey { + cwm.monkey(ts,te-ts); + } + action monkey_code { + cwm.monkey_as(cwm.om_code,ts,te-ts,&lcm,p); + } + action monkey_output { + cwm.monkey_as(cwm.om_output,ts,te-ts,&lcm,p); + } + action monkey_literal { + cwm.monkey_as(cwm.om_literal,ts,te-ts,&lcm,p); + } + + slashstar_comment := + ( any* :>> '*/' ) ${ cwm.monkey(fpc,1); } @{ fret; }; + + outputblock := |* + '%' (^linebreak)* linebreak { cwm.monkey_as(cwm.om_code,ts+1,te-ts-1,&lcm,p); }; + any=> { fhold; fcall outputline; }; + + *|; + outputline := |* + (^linebreak)* linebreak -- ('</%output>' | '<%code>' | ('<%' space) ) { cwm.monkey_as(cwm.om_output,ts,te-ts,&lcm,p); fret; }; + '<%code>' { cwm.modify(cwm.om_code,&lcm,p); fcall codeblock; }; + '</%output>' { --top; fret; }; + '<%' space { cwm.modify(cwm.om_inline,&lcm,p); fcall inlineblock; }; + (^linebreak)+ -- ( '%' | '<' ) => monkey_output; + any => monkey_output; + *|; + + inlineblock := |* + space '%>' { cwm.modify(cwm.om_code,&lcm,p); fret; }; + "'" ( [^'\\] | /\\./ )* "'" => monkey; + '"' ( [^"\\] | /\\./ )* '"' => monkey; + '/*' { cwm.monkey("/*",2); fcall slashstar_comment; }; + '//' (^linebreak)* (linebreak) => monkey; + any => monkey; + *|; + + literalblock := |* + any => { fhold; fcall literalline; }; + *|; + literalline := |* + (^linebreak)* linebreak -- ('</%literal>' | ('<%' space) ) { cwm.monkey_as(cwm.om_literal,ts,te-ts,&lcm,p); fret; }; + '</%literal>' { --top; fret; }; + '<%' space { cwm.modify(cwm.om_code,&lcm,p); fcall inlineblock; }; + (^linebreak)+ -- ( '%' | '<' ) => monkey_literal; + any => monkey_literal; + *|; + + codeblock := |* + '<%output>' { fcall outputblock; }; + '<%literal>' { fcall literalblock; }; + '</%code>' { fret; }; + "'" ( [^'\\] | /\\./ )* "'" => monkey_code; + '"' ( [^"\\] | /\\./ )* '"' => monkey_code; + '/*' { cwm.monkey("/*",2); fcall slashstar_comment; }; + '//' (^linebreak)* (linebreak) => monkey_code; + any => monkey_code; + *|; + + main := any >{ + fhold; + switch(topmode) { + case code_writing_monkey::om_output: fgoto outputblock; + case code_writing_monkey::om_code: fgoto codeblock; + default: ;/* TODO: WTD? */ + }; + }; +}%% + +%% write data; + +static const char *biname = 0; +static void display_usage() { + std::cerr << PACKAGE " Version " VERSION "\n" + "Copyright (c) 2011 Klever Group\n" + "\n" + " " << biname << " [otpions] [input-file]\n" + "\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help\n" + " --usage display this text\n" + " -V, --version display version number\n" + " -L, --license show license\n" + " -o <file>, --output=<file> write output to the named file\n" + " -t code|output, --top=code|output\n" +#else + " -h display this text\n" + " -V display version number\n" + " -L show license\n" + " -o <file> write output to the named file\n" + " -t code|output\n" +#endif + " set toplevel processing mode [output]\n" + " -C same as -t=code\n" + " -O same as -t=output (default)\n" + "\n"; +} + +int main(int argc,char *argv[]) { + biname = *argv; + std::string ofile; + code_writing_monkey::omode_type topmode = code_writing_monkey::om_output; + while(true) { + static const char shopts[] = "hVLo:t:CO"; +#if HAVE_GETOPT_LONG + static struct option opts[] = { + { "help", no_argument, 0, 'h' }, + { "usage", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'V' }, + { "license", no_argument, 0, 'L' }, + { "output", required_argument, 0, 'o' }, + { "top", required_argument, 0, 't' }, + { NULL, 0, 0, 0 } + }; + int c = getopt_long(argc,argv,shopts,opts,NULL); +#else + int c = getopt(argc,argv,shopts); +#endif + if(c==-1) break; + switch(c) { + case 't': + if(!strcasecmp(optarg,"code")) { + topmode = code_writing_monkey::om_code; + break; + }else if(!strcasecmp(optarg,"output")) { + topmode = code_writing_monkey::om_output; + break; + } + std::cerr << "Unkown '" << optarg << "' mode" << std::endl; + case '?': /* unknown option */ + case 'h': display_usage(); exit(0); break; + case 'V': std::cerr << VERSION << std::endl; exit(0); break; + case 'L': + extern const char *COPYING; + std::cerr << COPYING << std::endl; + exit(0); break; + case 'o': ofile = optarg; break; + case 'C': topmode = code_writing_monkey::om_code; break; + case 'O': topmode = code_writing_monkey::om_output; break; + default: + std::cerr << "Huh?" << std::endl; + exit(1); break; + } + } +#undef LS + if((optind+1)!=argc) { + display_usage(); exit(1); + /* TODO: or use stdin if no parameter specified? */ + } + + std::string ifile = argv[optind]; + if(ofile.empty()) ofile = ifile+".cc"; + std::ifstream ist(ifile.c_str(),std::ios::in); + std::ofstream ost(ofile.c_str(),std::ios::out); + if(!ost) { + std::cerr << "failed to open '" << ofile << "' for writing" << std::endl; + exit(2); + } + + int cs, act; + char *ts, *te; + int stack[128], top=0; + %% write init; + char input[512]; + int have = 0; + char *eof = 0; + code_writing_monkey cwm(ost); + cwm.prologue(); + line_counting_monkey lcm(ifile.c_str(),input); + cwm.anchor(lcm,0); + while(!eof) { + if(have==sizeof(input)) { + std::cerr << "No space to read in" << std::endl; + break; + } + char *p = input+have; + int lw = sizeof(input)-have; + int lp = ist.read(p,lw).gcount(); + char *pe = p+lp; + eof = (lp==lw)?0:pe; + %%write exec; + if(cs==cliche_error) { + std::cerr << "cliche error" << std::endl; + break; + } + if(ts) { + lcm.lineno(ts); + te = ((char*)memmove(input,ts,have=pe-ts)) + (te-ts); + ts = input; + }else{ + lcm.lineno(pe); + have = 0; + } + lcm.p = input; + } + cwm.epilogue(); + return 0; +} +/* vim:set ft=ragel ts=8 sw=8 cin si ai: */ diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..54191cb --- a/dev/null +++ b/test/.gitignore @@ -0,0 +1,22 @@ +/test-suite.log + +/r01_closing_at_the_line_start +/r01_closing_at_the_line_start.out +/r01_closing_at_the_line_start.diff +/r01_closing_at_the_line_start.check +/r01_closing_at_the_line_start.log +/r02_anchor_after_literal +/r02_anchor_after_literal.out +/r02_anchor_after_literal.diff +/r02_anchor_after_literal.check +/r02_anchor_after_literal.log +/r03_percent_after_empty +/r03_percent_after_empty.out +/r03_percent_after_empty.diff +/r03_percent_after_empty.check +/r03_percent_after_empty.log +/r04_too_seamless_transitions +/r04_too_seamless_transitions.out +/r04_too_seamless_transitions.diff +/r04_too_seamless_transitions.check +/r04_too_seamless_transitions.log diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..705278d --- a/dev/null +++ b/test/Makefile.am @@ -0,0 +1,32 @@ +TESTS=\ + r01_closing_at_the_line_start.clichec \ + r02_anchor_after_literal.clichec \ + r03_percent_after_empty.clichec \ + r04_too_seamless_transitions.clichec + +EXTRA_DIST=$(TESTS) +CLEANFILES = $(basename $(TESTS)) \ + $(foreach s,.out .diff,$(addsuffix $s,$(basename $(TESTS)))) +.INTERMEDIATE: $(CLEANFILES) + +TEST_EXTENSIONS=.clichec +CLICHEC_LOG_COMPILER=test_clichec() { \ + $(MAKE) "$$(basename $$1 .clichec)"{,.{out,diff,check}} ;\ +}; test_clichec + +gitignore: .gitignore +.gitignore: Makefile + for t in ${TESTS} ; do for f in "$${t%.*}"{,.{out,diff,check,log}} ; do \ + grep -q "^/$$f" .gitignore || echo "/$$f" >>.gitignore ;\ + done done + +CLICHE=${top_builddir}/src/cliche +SUFFIXES=.clichec .cc .out .diff .check +.clichec.cc: + $(CLICHE) -C -o $@ $< +%.out: % + ${builddir}/$< >$@ +%.diff: ${builddir}/%.out ${srcdir}/%.expected + @-diff -u "$*.expected" "$*.out" >"$@" +%.check: %.diff + @test -s "$<" && { cat "$*.out";cp "$*.out" "$*.unexpected" ; exit 1 ; } || true diff --git a/test/r01_closing_at_the_line_start.clichec b/test/r01_closing_at_the_line_start.clichec new file mode 100644 index 0000000..11ebd8f --- a/dev/null +++ b/test/r01_closing_at_the_line_start.clichec @@ -0,0 +1,16 @@ +#include <iostream> +int main() { +const char *t0 = +<%literal> + + test-literal + +</%literal>; +std::cout << t0; + +<%output> + + test-output + +</%output> +} diff --git a/test/r01_closing_at_the_line_start.expected b/test/r01_closing_at_the_line_start.expected new file mode 100644 index 0000000..7854811 --- a/dev/null +++ b/test/r01_closing_at_the_line_start.expected @@ -0,0 +1,8 @@ + + + test-literal + + + + test-output + diff --git a/test/r02_anchor_after_literal.clichec b/test/r02_anchor_after_literal.clichec new file mode 100644 index 0000000..c2049c0 --- a/dev/null +++ b/test/r02_anchor_after_literal.clichec @@ -0,0 +1,8 @@ +#include <iostream> +int main() { +const char *l3 = <%literal>line 3</%literal> ":"; int nl3 = __LINE__; +std::cout << l3 << nl3 << std::endl; +{<%output>line 5 (<% __LINE__ %>)</%output>} +int l6 = __LINE__; +std::cout << std::endl << "line 6: " << l6 << std::endl; +}; diff --git a/test/r02_anchor_after_literal.expected b/test/r02_anchor_after_literal.expected new file mode 100644 index 0000000..b53c949 --- a/dev/null +++ b/test/r02_anchor_after_literal.expected @@ -0,0 +1,3 @@ +line 3:3 +line 5 (5) +line 6: 6 diff --git a/test/r03_percent_after_empty.clichec b/test/r03_percent_after_empty.clichec new file mode 100644 index 0000000..62c82eb --- a/dev/null +++ b/test/r03_percent_after_empty.clichec @@ -0,0 +1,8 @@ +#include <iostream> +int main() {<%output> +Test for broken handling of '^% ' line following the empty line. +Like this: + +% std::cout << 1 << std::endl; + +</%output>} diff --git a/test/r03_percent_after_empty.expected b/test/r03_percent_after_empty.expected new file mode 100644 index 0000000..f2ee7b2 --- a/dev/null +++ b/test/r03_percent_after_empty.expected @@ -0,0 +1,6 @@ + +Test for broken handling of '^% ' line following the empty line. +Like this: + +1 + diff --git a/test/r04_too_seamless_transitions.clichec b/test/r04_too_seamless_transitions.clichec new file mode 100644 index 0000000..c313013 --- a/dev/null +++ b/test/r04_too_seamless_transitions.clichec @@ -0,0 +1,9 @@ +#include <iostream> +int main() { +int a=1,b=2; +<%output> +The transition like this - <% a %><% b %> should not glue 'ab' in the source together. +Really. +</%output> +} + diff --git a/test/r04_too_seamless_transitions.expected b/test/r04_too_seamless_transitions.expected new file mode 100644 index 0000000..2ab4e9f --- a/dev/null +++ b/test/r04_too_seamless_transitions.expected @@ -0,0 +1,3 @@ + +The transition like this - 12 should not glue 'ab' in the source together. +Really. |