From cf57857ce5f9e64d66a7b6e4f407d777522db190 Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Mon, 8 Oct 2018 23:14:19 -0400 Subject: [PATCH] bin/: Server/client build scripts These scripts allow the TAME compiler stack to be invoked naturally, rather than requiring the use of a Makefile today. This will not only allow users to more easily invoke the compiler, but will also allow us to invoke TAME naturally from Makefile and remove the klugery that has existed for so long. This users a server/client architecture in order to mitigate the startup cost of the JVM. More documentation will follow. Note that there are a bunch of symlinks in rater/---this is a transition step to allow the build to continue working as it did before, which relies on a directory structure that exists outside of this repository. This will be cleaned up in the future. * .gitignore (bin/dslc): Add ignore for generated file. * bin/dslc.in: New script to encapsulate Java invocation. * bin/tame: New script (client). * bin/tamed: New script (server). * configure.ac (JAVA_OPTS, DSLC_CLASSPATH, AUTOGENERATED): New variables for dslc.in. Output bin/dslc. * rater/README.md: Note that this symlink mess is temporary. * rater/c1map: New symlink for dslc assumptions. * rater/c1map.xsl: Likewise. * rater/calc.xsd: Likewise. * rater/compile.xsl: Likewise. * rater/compiler: Likewise. * rater/dot.xsl: Likewise. * rater/include: Likewise. * rater/link.xsl: Likewise. * rater/standalone.xsl: Likewise. * rater/summary.xsl: Likewise. * rater/tame: Likewise (warning: circular symlink). * src/current/src/com/lovullo/dslc/DslCompiler.java (_DslCompiler)[compile]: Output `DONE' lines. --- .gitignore | 1 + bin/dslc.in | 28 + bin/tame | 220 ++ bin/tamed | 217 ++ configure.ac | 10 + rater/README.md | 6 + rater/c1map | 1 + rater/c1map.xsl | 1 + rater/calc.xsd | 1 + rater/compile.xsl | 1 + rater/compiler | 1 + rater/dot.xsl | 1 + rater/include | 1 + rater/link.xsl | 1 + rater/rater.xsd | 1987 +++++++++++++++++ rater/standalone.xsl | 1 + rater/summary.xsl | 1 + rater/tame | 1 + .../src/com/lovullo/dslc/DslCompiler.java | 5 + 19 files changed, 2485 insertions(+) create mode 100644 bin/dslc.in create mode 100755 bin/tame create mode 100755 bin/tamed create mode 100644 rater/README.md create mode 120000 rater/c1map create mode 120000 rater/c1map.xsl create mode 120000 rater/calc.xsd create mode 120000 rater/compile.xsl create mode 120000 rater/compiler create mode 120000 rater/dot.xsl create mode 120000 rater/include create mode 120000 rater/link.xsl create mode 100644 rater/rater.xsd create mode 120000 rater/standalone.xsl create mode 120000 rater/summary.xsl create mode 120000 rater/tame diff --git a/.gitignore b/.gitignore index db0b0567..d52e3f7b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.info # autotools- and configure-generated +/bin/dslc /Makefile.in /Makefile /aclocal.m4 diff --git a/bin/dslc.in b/bin/dslc.in new file mode 100644 index 00000000..e9dac7c1 --- /dev/null +++ b/bin/dslc.in @@ -0,0 +1,28 @@ +#!/bin/bash +# Listen for TAME commands (compilers, linker, etc) +# +# Copyright (C) 2018 R-T Specialty, LLC. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# @AUTOGENERATED@ +## + +declare -r mypath=$( dirname "$( readlink -f "$0" )" ) +declare -r dslc_jar="$mypath/../src/current/src/dslc.jar" + + +CLASSPATH="$CLASSPATH:@DSLC_CLASSPATH@:$dslc_jar" \ + "@JAVA@" @JAVA_OPTS@ \ + com.lovullo.dslc.DslCompiler diff --git a/bin/tame b/bin/tame new file mode 100755 index 00000000..be9fc612 --- /dev/null +++ b/bin/tame @@ -0,0 +1,220 @@ +#!/bin/bash +# Client for TAME daemon (tamed) +# +# Copyright (C) 2018 R-T Specialty, LLC. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +## + +set -euo pipefail + +declare -r mypath=$( dirname "$( readlink -f "$0" )" ) + +declare -ri EX_NOTAMED=1 # tried to start tamed but failed +declare -ri EX_USAGE=64 # incorrect usage; sysexits.h + + +# Send a single command to a runner and observe the result +# +# stdin will be directed to the runner. stdout of the runner will be +# echoed until a line beginning with "DONE" is found, after which this +# procedure will return with the exit code indicated by the runner. +command-runner() +{ + local -ri id="${1?Missing id}" + local -r root="${2?Missing root run path}" + shift 2 + + local -r base="$root/$id" + local -ri pid=$( cat "$base/pid" ) + + # TODO flock + + verify-runner "$base" "$pid" + + # all remaining arguments are passed to the runner + echo "$@" > "$base/0" + + # output lines from runner until we reach a line stating "DONE" + while read line; do + # don't parse words in the initial read because we may be + # dealing with a lot of lines + if [ "${line:0:5}" == "DONE " ]; then + read _ code _ <<< "$line" + return "$code" + fi + + echo "$line" + done < "$base/1" +} + + +# Verify that a runner is available +# +# If the runner is offline or not owned by $UID, then exit with +# a non-zero status. +verify-runner() +{ + local -r base="${1?Missing base}" + local -ri pid="${2?Missing pid}" + + ps "$pid" &>/dev/null || { + echo "error: runner $id ($pid) is offline!" >&2 + exit "$EX_NOTAMED" + } + + test -O "$base/0" || { + echo "error: runner $id ($pid) is not owned by $USER!" >&2 + exit "$EX_NOTAMED" + } +} + + +# Wait somewhat impatiently for tamed +# +# Assumes that tamed's runner 0 is running once the pidfile becomes +# available. Polls for a maximum of six seconds before giving up +# and exiting with a non-zero status. +wait-for-tamed() +{ + local -r base="${1?Missing base}" + + # we could use inotify, but that is not installed by default + # on Debian systems, so let's just poll rather than introduce + # another dependency (give up after 6 seconds) + local -i i=12 + while test $((i--)); do + test ! -f "$base/0/pid" || return 0 + sleep 0.5 + done + + # still not available + echo 'error: tamed still unavailable; giving up' >&2 + exit "$EX_NOTAMED" +} + + +# Start tamed if it is not already running +# +# If tamed is already running, nothing will happen; otherwise, start +# tamed and wait impatiently for the runner to become available. +# +# Even if tamed is started, wait for runner 0 to become available; +# this ensures that tamed is initialized even if this script is run +# after tamed is started but before it has fully come online (e.g +# parallel make). +start-tamed() +{ + local -r root="${1?Missing root}" + + local -ri pid=$( cat "$root/pid" 2>/dev/null ) + + ps "$pid" &>/dev/null || { + echo "starting tamed at $root..." + + # tell tamed to clean up so that we eliminate race conditions + # with wait-for-tamed (this will also kill any stray processes + # that a previous tamed may have spawned but didn't get the + # chance to clean up) + kill-tamed "$root" || true + + # start tamed and allow it to persist for future commands + "$mypath/tamed" "$root" & disown + } + + # wait for tamed even if it was already started (just in + # case this script was executed right after tamed started + # but before it is done initializing) + wait-for-tamed "$root" +} + + +# Kill tamed +# +# Ask tamed to kill itself. +kill-tamed() +{ + local -r root="${1?Missing root}" + + "$mypath/tamed" --kill "$root" +} + + +# Filter dslc output to essential information +# +# The original output of dslc is quite noisy; this filters it down +# to only errors and warnings. +# +# Eventually, dslc out to be modified to handle filtering its own +# output rather than wasting cycles doing this filtering. +saneout() +{ + awk ' \ + /^~~~~\[begin /,/^~~~~\[end / { next } \ + /^rm / { next } \ + /^Exception|^\t+at / { \ + if ( /^E/ ) { \ + print; \ + print "Stack trace written to .runlog"; \ + } \ + next; \ + } \ + /([Ww]arning|[Nn]otice)[: ]/ { printf "\033[0;33m"; w++; out=1; } \ + /[Ff]atal:/ { printf "\033[0;31m"; out=1; } \ + /!|[Ee]rror:/ { printf "\033[0;31m"; e++; out=1; } \ + /internal:/ { printf "\033[0;35m"; out=1; } \ + /internal error:/ { printf "\033[1m"; out=1; } \ + /^[^[]/ || out { print; printf "\033[0;0m"; out=0; } \ + ' +} + + +# Output usage information and exit +usage() +{ + cat <. +## + +set -euo pipefail + +declare -r mypath=$( dirname "$( readlink -f "$0" )" ) + +declare -ri EX_RUNNING=1 +declare -ri EX_USAGE=64 # incorrect usage; sysexits.h +declare -ri EX_CANTCREAT=73 # cannot create file; sysexits.h + +# set by `main', global for `cleanup' +declare root= + + +# Create FIFOs for runner +# +# The FIFOs are intended to be attached to stderr and stdout +# of the runner and will be created relative to the given +# root path ROOT. +# +# If a FIFO cannot be created, exit with EX_CANTCREAT. +mkfifos() +{ + local -r root="${1?Missing root path}" + + mkdir -p "$root" + + # note that there's no stderr; see `add-runner' + for n in 0 1; do + rm -f "$root-$n" + + mkfifo -m 0600 "$root/$n" || { + echo "fatal: failed to create FIFO at $in" + exit $EX_CANTCREAT + } + done +} + + +# Spawn a runner +# +# A new runner is created by spawning dslc and attaching +# new FIFOs under the given id ID relative to the given +# run path ROOT. The PID of the runner will be stored +# alongside the FIFOs in a pidfile `pid'. +spawn-runner() +{ + local -ri id="${1?Missing id}" + local -r root="${2?Missing root run path}" + + local -r base="$root/$id" + + mkfifos "$base" + + # TODO: should we separate back out std{out,err}? + # XXX: why does dslc quit (with a 0 exit code) occsionally? stdin? + while true; do + "$mypath/dslc" < <( persistent-cat "$base/0" ) \ + >"$base/1" \ + 2>&1 + echo "warning: runner $id exited with code $?; restarting" + done & + + echo "$!" > "$base/pid" + + echo "runner $id ($!): $base" +} + + +# Persistently read commands from FIFO IN +# +# This will continue to read from the FIFO as long as it is +# readable. This is necessary since SIGPIPE gets sent to +# processes reading/writing from/to the FIFO whenever a +# process detaches from it. +persistent-cat() +{ + local -r in="${1?Missing input path}" + + while test -r "$in"; do + read -r < "$in" || return + echo "$REPLY" + done +} + + +# Exit if tamed is already running at path ROOT +# +# If tamed is already running at ROOT, exit with status +# EX_RUNNING; otherwise, do nothing except output a warning +# if a stale pid file exists. +abort-if-running() +{ + local -r root="${1?Missing root rundir}" + + local -ri pid=$( cat "$root/pid" 2>/dev/null ) + + test "$pid" -gt 0 || return 0 + + ! ps "$pid" &>/dev/null || { + echo "fatal: tamed is already running at $root (pid $pid)!" + exit $EX_RUNNING + } + + test -z "$pid" || { + echo "warning: clearing stale tamed (pid $pid)" + } +} + + +# Kill running tamed at path ROOT +# +# If no pidfile is found at ROOT, do nothing. This sends a +# signal only to the parent tamed process, _not_ individual +# runners; the target tamed is expected to clean up itself. +# Consequently, if a tamed terminated abnormally without +# cleaning up, this will not solve that problem. +kill-running() +{ + local -r root="${1?Missing root}" + + local -r pid=$( cat "$root"/pid 2>/dev/null ) + + test -n "$pid" || return 0 + + echo "killing tamed at $root ($pid)..." + kill "$pid" +} + + +# Clean up child processes before exit +# +# This should be called before exit (perhaps by a trap). Kills +# the entire process group. +# +# Do not attach this to a SIGTERM trap or it will infinitely +# recurse. +cleanup() +{ + echo "killing remaining runners..." + + rm -rf "$root" + kill 0 +} + + +# Output usage information and exit +usage() +{ + cat < "$root/pid" + + # only a single runner for now + spawn-runner 0 "$root" + + wait -n +} + +main "$@" diff --git a/configure.ac b/configure.ac index a8db59ff..f115f9aa 100644 --- a/configure.ac +++ b/configure.ac @@ -40,6 +40,7 @@ AC_SUBST(REV, m4_argn(3, ver_split)) AC_SUBST(SUFFIX, m4_argn(4, ver_split)) AC_ARG_VAR([JAVA], [The Java executable]) +AC_ARG_VAR([JAVA_OPTS], [Java options]) AC_CHECK_PROGS(JAVA, [java]) AC_ARG_VAR([SAXON_CP], [Saxon class path]) @@ -52,7 +53,16 @@ AS_IF(test ! -d "$HOXSL", AC_MSG_ERROR([hoxsl path '$HOXSL' does not exist!])) AC_MSG_RESULT(found) +# BC with RATER_CLASSPATH +DSLC_CLASSPATH="${DSLC_CLASSPATH:-$RATER_CLASSPATH}" +AC_SUBST(DSLC_CLASSPATH, [$DSLC_CLASSPATH]) + +AC_SUBST([AUTOGENERATED], + ["THIS FILE IS AUTOGENERATED! DO NOT MODIFY! See *.in."]) + AC_CONFIG_FILES([Makefile doc/Makefile src/init.xsl VERSION]) +AC_CONFIG_FILES([bin/dslc], + [chmod +x bin/dslc]) AC_OUTPUT diff --git a/rater/README.md b/rater/README.md new file mode 100644 index 00000000..a51421e3 --- /dev/null +++ b/rater/README.md @@ -0,0 +1,6 @@ +# Compatibility Directory + +This directory exists for compatibility with earlier build scripts and path +assumptions before TAME was extracted into its own repository. A full +transition will remove this directory. + diff --git a/rater/c1map b/rater/c1map new file mode 120000 index 00000000..f63aa7ef --- /dev/null +++ b/rater/c1map @@ -0,0 +1 @@ +../src/current/c1map \ No newline at end of file diff --git a/rater/c1map.xsl b/rater/c1map.xsl new file mode 120000 index 00000000..e0f281d7 --- /dev/null +++ b/rater/c1map.xsl @@ -0,0 +1 @@ +../src/current/c1map.xsl \ No newline at end of file diff --git a/rater/calc.xsd b/rater/calc.xsd new file mode 120000 index 00000000..ffb2fa98 --- /dev/null +++ b/rater/calc.xsd @@ -0,0 +1 @@ +../src/current/calc.xsd \ No newline at end of file diff --git a/rater/compile.xsl b/rater/compile.xsl new file mode 120000 index 00000000..d7e1f1d8 --- /dev/null +++ b/rater/compile.xsl @@ -0,0 +1 @@ +../src/current/compile.xsl \ No newline at end of file diff --git a/rater/compiler b/rater/compiler new file mode 120000 index 00000000..b421e279 --- /dev/null +++ b/rater/compiler @@ -0,0 +1 @@ +../src/current/compiler \ No newline at end of file diff --git a/rater/dot.xsl b/rater/dot.xsl new file mode 120000 index 00000000..9309b8e4 --- /dev/null +++ b/rater/dot.xsl @@ -0,0 +1 @@ +../src/current/dot.xsl \ No newline at end of file diff --git a/rater/include b/rater/include new file mode 120000 index 00000000..5a4e1204 --- /dev/null +++ b/rater/include @@ -0,0 +1 @@ +../src/current/include/ \ No newline at end of file diff --git a/rater/link.xsl b/rater/link.xsl new file mode 120000 index 00000000..392e4936 --- /dev/null +++ b/rater/link.xsl @@ -0,0 +1 @@ +../src/current/link.xsl \ No newline at end of file diff --git a/rater/rater.xsd b/rater/rater.xsd new file mode 100644 index 00000000..d159e2d7 --- /dev/null +++ b/rater/rater.xsd @@ -0,0 +1,1987 @@ + + + + + + + + + + + + + + + + + + + + + + Name of a package/rater. Must match the name of the XML file, sans the + extension. If the package is in a subdirectory, then the name should be + a relative path (e.g. "rates/company"). + + + + + + + + + + + + + + + Name of a constant. + + Underscore prefixes should be reserved for system constants. + + + + + + + + + + + + + + + Name of a type (as would be defined via typedef). + + + + + + + + + + + + + + + Name of a mathematical function. + + Since the name will appear in equations, it has a restricted character + set and length. + + + + + + + + + + + + + + + Name of a parameter (global or local) + + + + + + + + + + + + + + Represents a value yielded by a calculation (e.g. a premium). + + The camelCase requirement as opposed to the snake_case requirement used + for other variables, such as params, is intended to provide a + distinction. + + + + + + + + + + + + + + + Single-character index variable + + + + + + + + + + + + + Template name; underscore prefix and suffix is mandatory to help ensure + distinctive names between other identifiers. + + + + + + + + + + + + + Template parameter name + + Template parameters are delimited by '@'s; this restriction is in place + to permit substring replacements with clear delimiters. + + + + + + + + + + + + + Documentation for a specific element. + + The documentation must not be sparse; please provide something + descriptive that will be useful to someone completely new to the code. + + + + + + + + + + + + + + Symbol used to represent an entity when rendered. + + The string should consist of TeX/LaTeX commands and should produce a + single symbol. + + + + + + + + + + + Types of sets (vectors or matrices) + + + + + + + + + + + + + + + + Permits the static declaration of a matrix; a set represents a vector + and sibling sets can be combined to create a matrix + + + + + + + + + + + + Description explaining what the set represents + + + + + + + + + + + Value of the constant; must be compatible with the + enumeration's @type. + + + + + + + Description explaining what the value represents + + + + + + + + + + Defines a single constant. + + Constants differ from other variables (such as parameters) in that their + values cannot change; they exist as an alternative to hard-coding values + and as a means of re-use (magic values are not permitted). + + The value of the constant must be compatiable with its type. + + + + + + + + + + + + Name of the constant. The name must always be used in place of the + value when referencing the constant. + + + + + + + Value of the constant; must be within the domain of its type. + + + + + + + Short-hand GNU Octave / MATLAB Style matrix specification. + + + + + + + Constant data type + + + + + + + Useful description of the constant that explains what it is used for + and provides a context + + + + + + + Optional LaTeX symbol for typesetting + + + + + + + + (CORE ONLY) Denotes a constant whose value may be determined by runtime + + This should prevent any compiler from inlining the constant value. + + + + + + + + + + + + Path to a package without the extension. + + + + + + + + + + + + + + + Declares the package that this package is a sub-topic of. + + + + + + + Path to package, sans the ``.xml'' extension. + + + + + + + + Parent section name; defaults to root. + + + + + + + + + + Permits importing package or template contents for use in the parent document. + + The @package attribute may be used for explicitly loading a package. + + @templates specifies a path for template auto-loading, but does not load any + templates, allowing the system to use only the templates that are needed. + + + + + + + Path to package to import, sans the ``.xml'' extension. + + + + + + + + Export the symbols imported by this package + + By default, all imported symbols are local, meaning that importing a + package will not include the symbols that the package itself has + imported. This is generally desirable from a maintainance standpoint, + but certain meta-packages (packages that exist simply to include + packages) may wish to make use of this feature. + + Use sparingly. + + + + + + + + Short-hand for a separate topic-of node; parent + section. "true" is equivalent to "root". + + + + + + + + Allow importing symbol tables that are not explicitly defined as + includable packages. + + + + + + + + Strip @keep flag from all imported symbols. + + + + + + + + Do not import symbols flagged as external to the classifier. + + This is of limited use outside of specialized settings, such as the + UI classifier. + + + + + + + + Keep all classifications, even if @ignore-keep is set. + + + + + + + + + + + + Defines a type that may be used to represent a restricted set of values. + + + + + + + + + + + + + + + Name by which the type may be referenced + + + + + + + Description of what the type may be used for + + + + + + + Optional LaTeX symbol for typesetting + + + + + + + + + + Merges multiple typedefs of the same type into a single type. + + Useful for categorizing types and sub-types in a semantic manner. + + + + + + + + + + + + + Defines an enumerated set of values. + + The type may accept any @value in the set. When referenced, @name must + be used. The name must be styled as a constant (since it is not a + variable). + + + + + + + + + + Name of enumerated value. This defines a constant and so the + name should be styled as such. + + + + + + + Value of the constant; must be compatible with the + enumeration's @type. + + + + + + + Description explaining what the value represents + + + + + + + + + + + Type of all enumerated values in a particular list + + + + + + + + + + + + Represents a parameter accepted by the rater or a function. + + Parameters accepted by the rater itself will be declared globally, + whereas parameters defined within functions will be local to that + function. + + Regardless of scope, parameter names must never conflict. + + + + + + + Name by which parameter can be identified + + + + + + + Parameter data type + + + + + + + Description of parameter + + + + + + + Whether or not the parameter is a set of values of type @type (an + array) + + + + + + + Default value for parameter if none is provided; must be within the + domain of its @type + + + + + + + Optional LaTeX symbol for typesetting + + + + + + + + + + Defines a mathematical function --- a reusable equation that optionally + accepts arguments. + + Functions also have access to the global argument list and any other + values; not everything must be passed in. Functions may contain only + a single calculation node (which itself may contain other calculations). + + + + + + + + + + + + Name of the function. Since the function is intended to be a function + in the mathematical sense and may be output as part of an equation, + the name is restricted to lowercase alpha characters. + + + + + + + Description of function and its purpose + + + + + + + Optional symbol to use in place of function name when typesetting + + + + + + + + + + + + String of classifications, space-delimited. + + + + + + + + + + + + + + + + + + + + + + Name of parameter to replace in template + + + + + + + + String with which template parameter should be replaced + + All template parameters are replaced by the preprocessor before + the XML document reaches any other system; this means that all + parameter replacements are performed as strings, just as if you + copied and pasted the template XML into place and did a + search-and-replace/regex on the XML. + + Consequently, variable replacements are not permitted. You may + replace the parameter with text representing the name of a + global parameter, for example, but you cannot pass in the + current value of of that parameter. + + + + + + + + + + This node will be entirely removed and replaced with the child nodes + of the referenced template. + + + + + + + + + + + Name of template to include in its place. + + + + + + + + + + + + + This node will be replaced with the processed template. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Classifications, delimited by spaces, that must be satisfied in order + to perform the premium calculation. + + If no classification is given, then the rating will always be + performed. + + + + + + + Classifications, delimited by commas, that must be not be + satisfied in order to perform the premium calculation. + + + + + + + Optional LaTeX symbol used to identify this premium (display only) + + + + + + + Always enter this rate block, even if the classification does not + match. This is useful if you wish to use the _CMATCH_ results + even on a non-match. + + + + + + + + + + + + Class name to apply to block + + + + + + + + Whether or not the classification should be considered as if it were + part of a @no attribute + + + + + + + + + + Represents a premium calculation to be performed based on a prior + classification (sans @yields) + + + + + + + + + + + + + + Precision of result (empty will use system default) + + + + + + + + Compile the rate block even if it does not contribute to the + final premium (that is---is outside the dependency tree of + lv:yields) + + This is useful for calculating supplemental data that does not + directly contribute to the premium. + + + + + + + + Rate calculation should be compiled external to the classifier (that + is, the classification should only be performed on-demand for rating + purposes). + + This has the benefit of removing the classifier from the classify() + method, which may be important for, say, asserting on final premium + amount. + + + + + + + + + + + + Represents a premium calculation to be performed based on a prior + classification + + + + + + + + + Variable in which to store the result of the calculation (will + default to 0 if calculation is not performed). + + + + + + + + + + + + Identical to lv:rate, except that it requires and index with which it + will automatically loop through the magic _CMATCH_ set and multiply the + calculation by its value; this creates a conditional effect. + + + + + + + + + Set the index to use for summing over the _CMATCH_ set. + + + + + + + + Optional variable in which to store the result of the calculation (will + default to 0 if calculation is not performed). + + If not provided, will prefix the value of @generates. + + + + + + + + Produces a generating function as vector @generates + + + + + + + + Symbol to use for display of generator + + + + + + + + Number of dimensions as integer or alias. + + + + + + + + + + + + Generates lv:rate-each, applying the given template (simply removes + boilerplate template application at the root level) + + The template is expected to accept an @index@ parameter. + + + + + + + + + + + + + + + + + + Template to apply + + + + + + + + Variable in which to store the result of the calculation (will + default to 0 if calculation is not performed). + + + + + + + + Produces a generating function as vector @generates + + + + + + + + Symbol to use for display of generator + + + + + + + + Compile the rate block even if it does not contribute to the + final premium (that is---is outside the dependency tree of + lv:yields) + + This is useful for calculating supplemental data that does not + directly contribute to the premium. + + + + + + + + The symbol associated with the rate block should never be exported + (similar to a private member in Object-Oriented languages, or + static definitions in C) + + + + + + + + + + + + Permits default value generation. + + + + + + + + + + + + + + + + + + + + + + Converts the first character of the value to uppercase + + + + + + + + Converts the string to uppercase + + + + + + + + Converts the string to lowercase + + + + + + + + Converts '-' to '_' + + + + + + + + Converts '-' to '' + + + + + + + + Converts spaces to dashes + + + + + + + + Strip all characters that do not constitute a valid + object identifier (for use in genrating names) + + + + + + + + + + + + + + + + + + + + Value to add to param (assumed to be a numeric param) + + + + + + + + + + Converts a class name to its @yields variable + + + + + + + + + + + + Retrieve symbol metadata. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Result of param copy should trigger template param expansion has if + the copied nodes were a part of the template itself. + + Without this option, param expansion is not performed on the copied + nodes for that pass, meaning that the copied nodes will be + unaffected by the template. + + + + + + + + + + + + + + + + + + + + + + Declares a parameter available for replacement within the template. + + Notice how, unlike parameters for raters and functions, this parameter + does not require a type; this is because all replacements are done by + the preprocessor and, as such, all replacements are done as strings. + + + + + + + + + + + Parameter name to be used for replacements + + + + + + + Parameter description + + + + + + + + + + Declares a template whose body may be referenced using lv:apply-template. + + Templates are a basic means of code reuse that act as macros: when + referenced by lv:apply-template, the body of the template will be put + in its place as if it were pasted by hand. Therefore, this achieves the + effect of copy-and-paste without the obvious downsides of actually + copying and pasting code. + + This permits the construction of lv:rate blocks in a more natural manner. Other + methods of re-use include referencing previously calculated premiums (by other + lv:rate blocks) and the use of functions; both have their downsides. Namely: + + - Premiums calculated by other lv:rate blocks yield a single float value, which + aggregates individual indexes that may have been used during rating. As such, + if you need those individual premiums per index, premiums from other lv:rate + blocks cannot be used. In such a case, functions may be used. + - Using a function requires verbose code for application and makes + the documentation and debugging more complicated. It does, however, + have the benefit of being able to accept arguments, which templates + cannot do (and as such should be used whenever variable reuse is + necessary outside the scope of the global parameter list). + - Templates were designed with the idea that a bunch of common calculations + could be defined that could then be applied to individual raters as a more + natural alternative to functions. That is---the developer is accustomed to + creating lv:rate blocks that contain calculations, not excessive function + calls joined together with other expressions. Templates eliminate the need + for boilerplate function application code and, because they are handled by + the preprocessor, also generate easy-to-understand documentation and make + debugging more natural for both developers and testers. + - While templates do not accept arguments, they *do* permit string-replacement + of parameters by the preprocessor. This has the benefit of being + able to replace text as if it were done in your editor. + Consequently, this means that the replacement can be anything that + is considered valid by the validator/compiler. + + + + + + + + + + + + Template name; will be used by lv:apply-template. + + + + + + + + Describe purpose of the template + + + + + + + + + + + + Classification identifier; will be used to refer to the classification. + + + + + + + + + + + + + + + Classifies data based on the provided argument list and other + classifications. Classifications are used during rating to determine + how premiums should be calculated in a declarative manner. + + If no classification criteria are provided, then the classification + will always take place (implying a direct "is a" relationship between + the rater and a particular classification). + + + + + + + + + + + Name of classification. Can be used to determine whether or not the + data has been classified as such. + + + + + + + Convert classification from a universal quantifier into an + existential + + + + + + + Description of classification + + + + + + + Optional variable in which to store a boolean set of matches (useful + if classifying against sets) + + As an example, consider classifying as vacant land by matching on a + set of class codes. The system will check each class code in the + provided set against valid class codes for vacant land. Should one + item in the set match any of the criteria, the + classification will succeed and its associated index in the @yields + identifier will be set to 1. Otherwise, the value will remain 0. + + This allows for performing conditional calculations by simply + multiplying by the boolean value. If the value is 0, that portion of + the equation will effectively have not happened, simulating a + conditional. + + + + + + + Always perform the classification, even if it is unused. + + Otherwise, the system may not compile unused classifications (and so + the classification would not occur). + + + + + + + Classification should result in termination (useful for eligibility + and error conditions) + + + + + + + Classification should be compiled external to the classifier (that + is, the classification should only be performed on-demand for rating + purposes). + + This has the benefit of removing the classifier from the classify() + method, which may be important for, say, asserting on final premium + amount. + + + + + + + + + + Criteria with which a classification may be matched. + + All criteria is driven off of the global argument list. + + + + + + + + + + + + + + + + + Succeeds if any of the child matches succeed (equivalent to an OR statement). + + + + + + + + + + + + + + + + + + + + + Succeeds if all of the child matches succeed (equivalent to an AND statement). + + This is implied by the root lv:classify node. + + + + + + + + + + + + + Perform a basic match against a given value or enumerated list. + + One of value or anyOf should be provided. If neither is provided, one + may provide any condition nodes accepted by c:when; multiple will be + combined with logical and. This provides additional flexibility + necessary for more complicated assertions that would otherwise rely on + convoluted regular expressions. + + + + + + + + + + + Name of global parameter to perform match on + + + + + + + Value to match against (must be within domain of parameter). Use only + one of this or @anyOf. + + + + + + + Value must match any value within an enumerated list. Enumeration to + match against must be within the domain of the parameter. USe only + one of this or @value. + + + + + + + JavaScript-compatible regular expression + + Forward slashes must be escaped with a backslash and opening/closing + delimiters should not be specified. + + + + + + + + + + Join matching classifiers into an lv:any block where they will be + matched on the value TRUE. + + Each matching classifier must have a @yields attribute. + + + + + + + Any classifier's @as attribute matching this prefix will be included + within an lv:any block. + + + + + + + + Univerisal quantifier (default is existential) + + + + + + + + + + + Yields a single value (premium) representing the entire result of the + rating process. + + + + + + + + + + + + + + Internal symbol types + + These are the strings used directly by the symbol map; it is + recommended that the user use some type of abstraction (e.g. a + template). + + + + + + + + + + + + + + + + + + + + Declares an external symbol + + This allows a symbol to be used in a package that does not either include + or define it. The symbol must be defined before linking. + + + + + + + Symbol name + + + + + + + + Symbol type + + + + + + + + Symbol data type + + + + + + + + Symbol dimensions (0 = scalar, 1 = vector, 2 = matrix, etc) + + + + + + + + Optional user-friendly message to output when extern is + missing (such as how to satisfy it). + + + + + + + + + + + Represents a single rater (calculator). This is a root node; there may be + only one rater per document. + + + + + + + + + + + + + + Denotes a group of common data. The section title will + become a heading in the documentation. + + + + + + + + + + + + + + + + + + + + Section title to appear in documentation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Base type that defines elements and attributes acceptable by any package + (note that a rater is considered to be a concrete package). + + + + + + + + + + + + + + + + + + + + + + + + + + + Entry point for a program package; yields final result. + + This will result in an error if the package is not a program. + + + + + + + + + + + + UNIX-style package name that may be used to identify the package. Must + match the name of the file, sans the ``.xml'' extension. + + + + + + + + + + Represents a single rater (calculator). This is a root node; there may be + only one rater per document. All raters yield a final premium. + + + + + + + + + + + + + + + Represents a reusable package that may be included in raters or other + packages. This is a root node; there may be only one per document. + + + + + + + + + + + Package title. This is used as a user-friendly package + name, and as the heading for generated documentation. + + This replaces the previous @desc attribute, + which existed prior to the literate implementation. + + + + + + + + Deprecated; use @title. + + + + + + + + Package contains an entry point can may be linked into an + executable. + + + + + + + + + Used to indicate that the package is contained within the rating + framework itself. Do not use for your own + packages. + + + + + + + + Setting this to "true" will enable pretty sweet debugging features that + will make your life more tolerable (and perhaps even pleasant). + + + + + + + + When importing @keep symbols from packages, ignore those flagged + as @extclass + + + + + + + + Automatically treat all symbols as if they had @keep set. + + This ensures that all imported symbols will be present in + the compiled output. This is generally not desired, since + it will inflate the output by including unused symbols. + + N.B.: Currently only keeps classifications and their + generators! + + This is of limited use outside of specialized settings, such + as the UI classifier. + + + + + + + + + Mark generated eligibility classification with @keep. + + + + + + + + + + + + + Templates may exist as the root node in their own file for auto-loading. + + + + + diff --git a/rater/standalone.xsl b/rater/standalone.xsl new file mode 120000 index 00000000..bda27878 --- /dev/null +++ b/rater/standalone.xsl @@ -0,0 +1 @@ +../src/current/standalone.xsl \ No newline at end of file diff --git a/rater/summary.xsl b/rater/summary.xsl new file mode 120000 index 00000000..fc558d76 --- /dev/null +++ b/rater/summary.xsl @@ -0,0 +1 @@ +../src/current/summary.xsl \ No newline at end of file diff --git a/rater/tame b/rater/tame new file mode 120000 index 00000000..b870225a --- /dev/null +++ b/rater/tame @@ -0,0 +1 @@ +../ \ No newline at end of file diff --git a/src/current/src/com/lovullo/dslc/DslCompiler.java b/src/current/src/com/lovullo/dslc/DslCompiler.java index 0c33abfb..27dd2383 100644 --- a/src/current/src/com/lovullo/dslc/DslCompiler.java +++ b/src/current/src/com/lovullo/dslc/DslCompiler.java @@ -105,12 +105,17 @@ public class DslCompiler new StreamResult( new File( dest ) ), params ); + + // TODO: more unique identifier + System.err.println( "DONE 0 " + dest ); } catch ( Exception e ) { // delete the output file; it's garbage destfile.delete(); + System.err.println( "DONE 1 " + dest ); + // be verbose and unprofessional. throw e; }