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; }