## expand-file.pkg
## (Used with permission)
# Compiled by:
#
src/app/future-lex/src/lexgen.lib# Copy a template file to an output file while expanding placeholders.
# Placeholders are denoted by @id@ on a line by themselves.
### "It helps hand-eye coordination if,
### as you're doing your formulae,
### you gently sing the notation."
###
### -- E.J. Dijkstra
stipulate
package fil = file__premicrothread; # file__premicrothread is from
src/lib/std/src/posix/file--premicrothread.pkgherein
package expand_file
: (weak)
api {
Hook
=
fil::Output_Stream -> Void;
expand
:
{ src: List( String ),
dst: String,
hooks: List( (String, Hook) )
}
->
Void;
}
{
package tio = file__premicrothread; # file__premicrothread is from
src/lib/std/src/posix/file--premicrothread.pkg package ss = substring; # substring is from
src/lib/std/substring.pkg /*
package re = regular_expression_matcher_g (
package p = awk_syntax
package e = backtrack_engine)
package m = match_tree
*/
Hook = fil::Output_Stream -> Void;
/*
placeholderRE = re::compile_string "[\\t ]*@([a-zA-Z][-a-zA-Z0-9_]* )@[\\t ]*"
prefixPlaceholder = re::prefix placeholderRE ss::getc
fun findPlaceholder s
=
case (prefixPlaceholder (ss::from_string s))
THE (m::Match(_, [m::Match (THE { pos, len }, _)]), _)
=>
THE (ss::string (ss::slice (pos, 0, THE len)));
_ => NULL;
esac;
*/
fun find_placeholder s
=
{ trim = ss::drop_suffix char::is_space (ss::drop_prefix char::is_space (ss::from_string s));
size = ss::size trim;
if (size > 2 and
ss::is_prefix "@" trim and
ss::is_suffix "@" trim)
THE (ss::to_string (ss::make_slice (trim, 1, THE (size - 2))));
else
NULL;
fi;
};
# Copy from inStrm to outStrm expanding placeholders:
#
fun copy (in_strm, out_strm, hooks)
=
{
fun lp [] => ();
lp (s ! ss)
=>
{ case (find_placeholder s)
NULL => tio::write (out_strm, s);
THE id => case (list::find (\\ (id', h) = id == id') hooks)
THE (_, h) => h out_strm;
NULL => raise exception DIE "bogus placeholder";
esac;
esac;
lp ss;
};
end;
lp (in_strm);
};
exception OPEN_OUT;
fun expand { src, dst, hooks }
=
{ dst_strm
=
tio::open_for_write dst
except
ex =
{ tio::write (tio::stdout, cat [
"Warning: unable to open output file \"",
dst, "\"\n"
]);
raise exception OPEN_OUT;
};
fun done ()
=
(tio::close_output dst_strm);
copy (src, dst_strm, hooks)
except
ex = { done ();
raise exception ex;
};
done();
}
except OPEN_OUT = ();
};
end;