diff --git a/Makefile.am b/Makefile.am index 90090f1b..e632d543 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,7 +22,9 @@ path_src = src path_test = test # all source files will be run through hoxsl; see `applies' target -apply_src := $(shell find "$(path_src)" "$(path_test)" -name '*.xsl') +apply_src := $(shell find "$(path_src)" "$(path_test)" \ + -name '*.xsl' \ + -a \! -path "$(path_src)"/current/\* ) apply_dest := $(apply_src:%.xsl=%.xsl.apply) # needed by test runner diff --git a/README.md b/README.md index 3a5dbdb4..6b562411 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,13 @@ TAME's core library, and [hoxsl](https://github.com/lovullo/hoxsl) was developed as a supporting library. +## "Current" +The current state of the project as used in production is found in +`src/current/`. The environment surrounding the development of this +project resulted in a bit of a mess, which is being refactored into +`src/` as it is touched. Documentation is virtually non-existent. + + ## License 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 diff --git a/doc/Makefile.am b/doc/Makefile.am index 6bd1f0c1..889824bc 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -21,7 +21,9 @@ path_src := ../src path_tools := ../tools -stylesheets := $(shell find "$(path_src)" -name '*.xsl') +stylesheets := $(shell find "$(path_src)" \ + -name '*.xsl' \ + -a \! -path "$(path_src)"/current/\* ) stexi := $(stylesheets:.xsl=.texi) info_TEXINFOS = tame.texi diff --git a/src/current/.gitignore b/src/current/.gitignore new file mode 100644 index 00000000..24600083 --- /dev/null +++ b/src/current/.gitignore @@ -0,0 +1 @@ +!Makefile diff --git a/src/current/Makefile b/src/current/Makefile new file mode 100644 index 00000000..dc6eb542 --- /dev/null +++ b/src/current/Makefile @@ -0,0 +1,8 @@ + +.PHONY: dslc clean + +dslc: + $(MAKE) -C src/ dslc + +clean: + $(MAKE) -C src/ clean diff --git a/src/current/c1map.xsl b/src/current/c1map.xsl new file mode 100644 index 00000000..660fdf75 --- /dev/null +++ b/src/current/c1map.xsl @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [c1map] + + + + + + fatal: c1-map node not found + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [c1map] - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + error: missing required template argument ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + error: cannot have @dict on static mapping ` + + ' + + + + + + + error: cannot have @default on static mapping ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [c1map] fatal: unexpected node + + : + + + + + + + + + + + + / + + + + diff --git a/src/current/c1map/c1nodes.xsl b/src/current/c1map/c1nodes.xsl new file mode 100644 index 00000000..da4470f2 --- /dev/null +++ b/src/current/c1map/c1nodes.xsl @@ -0,0 +1,95 @@ + + + + + + + + + + + + => + + + + + + + + + + array( + + ) + + + + + + + + => + + + + + , + + + + + + '[ + + ]' => + + , + + + + + + '[ + + ]' => + + , + + + + + + + + + diff --git a/src/current/c1map/render.xsl b/src/current/c1map/render.xsl new file mode 100644 index 00000000..c782a35a --- /dev/null +++ b/src/current/c1map/render.xsl @@ -0,0 +1,339 @@ + + + + + + + + + + <?php + + + + namespace lovullo\c1\interfaces\c1\contract\ + + ; + + + class + + { + + + public function compose( $contract ) { + + return array( + + + + + ); + + } + + + } + + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ' + + ' + + + + + $contract->checkDefaultValue( ' + + ', + + ) + + + + + null + + + + + + + + + + + + + + + $contract->getValueByContext( + + + + + + , ' + + + ' + + ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $contract->getValue( ' + + ', $contract->getValueIndex( ' + + ' ) + + + , + + + + ) + + + + + + + + + + + + + + + error: variable not within scope: + + / + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $contract->iterateValues( ' + + ', + function( $contract ) { + return array( + + ); + } + ) + + + + + + + + ' + + + + + > + + + ' + + + + + + + + + , + + + + + + + ( ( + $contract->isTruthy( + + ) + ) ? + + + + : null ), + + + + + + [c1map] fatal: unexpected node during render: + + + + + diff --git a/src/current/c1map/transform.xsl b/src/current/c1map/transform.xsl new file mode 100644 index 00000000..87936486 --- /dev/null +++ b/src/current/c1map/transform.xsl @@ -0,0 +1,53 @@ + + + + + + + + + + ucwords(strtolower( + + )) + + + + + + + + + + + + + + + + error: unknown transformation ` + + ' for ` + + ' + + + + + + + internal error: unexpected node for transformation: + + + + + + diff --git a/src/current/c1map/valparse.xsl b/src/current/c1map/valparse.xsl new file mode 100644 index 00000000..8c4ab1ff --- /dev/null +++ b/src/current/c1map/valparse.xsl @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ' + + + ' . + + + + + + + + + + + + + ' + + ' + + + + + . ' + + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/calc.xsd b/src/current/calc.xsd new file mode 100644 index 00000000..0030aa73 --- /dev/null +++ b/src/current/calc.xsd @@ -0,0 +1,883 @@ + + + + + + + + + Generic name reference restriction, intended to be generic enough to + work with most systems (supporting both C-style and Lisp-style + identifiers). + + The systems that implement this schema should perform their own, more + strict, type checks. + + + + + + + + + + + + + + + Valid value for constants. + + + + + + + + + + + + + + + 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. + + + + + + + + + + + + + Single-character index variable + + + + + + + + + + + + + Symbol used to represent an entity when rendered. + + The string should consist of TeX/LaTeX commands and should produce a + single symbol. + + + + + + + + + + + + + + Abstract operator type used to classify elements as operators. + + Operators are portions of the calculation that perform a portion of + the calculation. For example, a summation would classify as an + operation (operator), but value-of would not (as it is only + representing a value, but not performing a calculation). + + + + + + + + + Elements/attributes common to all operator types (see the operator + element for a description on what qualifies as an operator). + + All operators may include child calculations. Furthermore, they may + be labeled and may have an identifier associated with their result. + + + + + + + + + + + + + Optional identifier with which the result of the calculation may be + referenced. + + + + + + + Optional description of a calculation. @label is used in place of + @desc to ensure that it is not confused with the otherwise required + @desc attribute. + + + + + + + @desc should be used to describe a value that is generated by a + calculation and should not otherwise be used (e.g. with + lv:sum/@generate) + + This is different from @label, which provides a high-level + description of what the equation is doing. @desc describes what the + generated value is. + + + + + + + Allows for the definition of an index variable which will be + defined for all children of the operation. + + + + + + + + + + Represents a summation (addition) of a set of values. + + If @of is used, the equation defined by child elements will be + iterated using an index on the set provided by @of. If no equation is + given, all elements in the set identified by @of will be summed. + + If @of is omitted, the result of each child element will be summed. + + This operator should also be used for subtraction by summing negative + values. + + + + + + + + + + Iterate over all values of this set. Must be a set. + + + + + + + + Optional name of a set to generate from this expressions. + + Generators are compatible only with @of and a sub-expression. + + + + + + + + Symbol to use when typesetting the generator + + + + + + + + Yield precision + + + + + + + + + + + + + Represents the product (multiplication) of a set of values. + + If @of is used, the equation defined by child elements will be + iterated using an index on the set provided by @of. If no equation is + given, all elements in the set identified by @of will be multiplied. + + If @of is omitted, the result of each child element will be + multiplied. + + While this operator may also be used for division by multiplying by + the inverse of a number (n^-1), a limited quotient operator is + provided for clarity and convenience. + + + + + + + + + + Iterate over all values of this set. Must be a set. + + + + + + + + Optional name of a set to generate from this expressions. + + Generators are compatible only with @of and a sub-expression. + + + + + + + + Symbol to use when typesetting the generator + + + + + + + + Dot product of any number of vectors + + + + + + + + Yield precision + + + + + + + + + + + + + Represents the quotient (division) of two values. + + This operator is to be thought of as a fraction: the numerator is + identified by the first child element and the denominator the second. + + While the summation operator may also be used for division by + multiplying by the inverse of a number (n^-1), this limited operator + is provided for clarity and convenience. + + + + + + + + + + + + + + + + Exponent; the first child node is the base, the second is the order. + + + + + + + + + + + + + + + Construct a list using the given element and an existing list + + This is analogous to lisp's cons; the first argument is the car and + the second is the cdr. + + + + + + + + + + + + + + + + + + + + Retrieve the first element of a list + + Analogous to lisp's car. + + + + + + + + + + + + + + + + + + + + Return the list without its first element + + If the list contains only one element, then an empty list will be + returned. Analogous to lisp's cdr. + + + + + + + + + + + + + + + + + + + + Retrieves the length of a vector + + + + + + + + + + + + + + + + + + + + + Denotes a function application. + + The result of the function identified by @name will be used in + place of the call. The application may optionally accept an + argument list (if the function accepts arguments). + + + + + + + + + + + + + + Name of the function to apply + + + + + + + + + + + + + + + + Represents an argument to be applied to a function. + + + + + + + + + + + Name of the parameter to apply to the function + + + + + + + + + + Recursively applies the current function. + + All arguments are copied to the argument list of the function application unless overridden. + + + + + + + + + + + + + + + + + + + + + + + Converts the given value to an integer, rounding up if necessary (e.g. 0.1 => 1) + + + + + + + + + + Value precision to consider for rounding. + + + + + + + + + + + + + Converts the given value to an integer, rounding down if necessary (e.g. 0.9 => 0) + + + + + + + + + + Value precision to consider for rounding. + + + + + + + + + + + + Creates a set out of its siblings + + + + + + + + + + + + + + + + Outputs the result of the contained expression to the console and + returns its value. + + + + + + + + + + + + + + + + + Defines a condition under which the expression will yield one if + true, otherwise will be strongly zero (zero even if + undefined) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + More flexible alternative to the @index attribute on elements; supports + calculations for determining the index + + + + + + + + + + + + + Returns the value associated with the given identifier. + + + + + + + + + + + + An identifier for which the value should be retrieved + + + + + + + Allows for the definition of an index variable which will be + defined for all children of the operation. + + + + + + + Optional description of a calculation. @label is used in place of + @desc to ensure that it is not confused with the otherwise required + @desc attribute. + + + + + + + + + + Returns @value. This element simply enforces documentation and prevents + the use of magic values. + + + + + + + + + + + + Value of constant (must be within the domain of its @type) + + + + + + + Type (domain) of the constant (inferred when not provided) + + + + + + + Description of the value explaining its intent + + + + + + + Optional description of a calculation. @label is used in place of + @desc to ensure that it is not confused with the otherwise required + @desc attribute. + + + + + + + + + + Represents a list of cases for a calculation. + + + + + + + + + + + + + + + + + Optional description of the case + + + + + + + + + + + + + + + + + + Optional description of the case + + + + + + + + + + + Optional description of the case set + + + + + + + + + + Declares variables visible within the let block. + + This exists as a means of assignment for re-using values. + + + + + + + + + Declares a list of values to define for this block + + + + + + + + + + Declares a value that will remain in scope for the let block + + + + + + + + + + + Variable name + + + + + + + + Variable datatype + + + + + + + + + Vector/matrix; if omitted, implicitly scalar. + + + + + + + + Describe the purpose of the value + + + + + + + + + + + + + + + + + + + + Represents every element that can be used to perform a calculation. + Implementors may use this group to accept any type of calculation. + + + + + + + + + + + + + + + + + + Root calculation node; this should be the entry point for any type of + calculation. This helps to ensure that certain nodes are only used at + the beginning of a calculation (such as cases). + + + + + + + + + + diff --git a/src/current/compile.xsl b/src/current/compile.xsl new file mode 100644 index 00000000..2e8d561f --- /dev/null +++ b/src/current/compile.xsl @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + !!! preprocessor error: + + + + + + + + + + + + + + + + + + + + + + + + + fatal: source file is invalid: unexpected node + + + + + diff --git a/src/current/compiler/fragments.xsl b/src/current/compiler/fragments.xsl new file mode 100644 index 00000000..8ea60245 --- /dev/null +++ b/src/current/compiler/fragments.xsl @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [jsc] fatal: unknown symbol type for ` + + ': + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/compiler/js-calc.xsl b/src/current/compiler/js-calc.xsl new file mode 100644 index 00000000..8594d4f7 --- /dev/null +++ b/src/current/compiler/js-calc.xsl @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + : + + + + + + + + + + yes + + + + + + + + ( function() { var result = + + + + + + ; + ( debug[' + + '] || ( debug[' + + '] = [] ) ).push( result ); + + return result; + } )() + + + + + + + + ( + + ) + + + + + ( + + ( + + ) + + + * ( + + + * + + + + + ) + ) + + + + + + + + + + + + + + + 8 + + + + + + + + + + + + + + + + + _$i$_ + + + + + + ( function() { + + + var sum = 0; + + + + + + + + + + + + + + + + + consts[' + + '] + + + + args[' + + '] + + + + + + + var G = []; + + + + for ( var + + in + + ) { + + var result = +(+( + + + + + + + + + + [ + + ] + + + )).toFixed( + + ); + + + + G.push( result ); + + + + sum + + = +result; + + + } + + + + args[' + + '] = G; + + + return sum; + } )() + + + + + + ( function() { + + + var _$dlen$ = longerOf( + + + , + + + + + + ); + + + var _$dsum$ = 0; + + + for ( var _$d$ = 0; _$d$ < _$dlen$; _$d$++ ) { + _$dsum$ += + + + + * + + + ( ( + + || [] )[ _$d$ ] || 0 ) + + ; + } + + return _$dsum$; + + } )() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + * + + + + + + + + + + + + + + + + 8 + + + + + Math. + + ( +( + + ).toFixed( + + ) ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + )[__$$i] + + + + + + + + + + + + + + || 0 + + + + + + + + + + + + || 0 + + + + + + + + + + + + + + consts[' + + '] + + + + + + + + + + + + + + + consts[' + + '] + + + + + + + + || 0 + + + + + + + + + + + + + + + + + + + + + + + args[' + + '] + + + + + + + + + + + + + + + + || 0 + + + + + + + + + + + + ( + + ||[]) + + [ + + + + + + + + + + + + + + + + + + + + args[' + + '] + + + + ] + + + + + + + + + + + + + + + + + + + + + + + + + + + [ + + ] + + + + + + + + + ( + + + + + || 0 ) + + + + + + + + + + + + + + + + + / + + + + + + + Math.pow( + + , + + ) + + + + + + + + + + + + + ( args + + + + + + + , + + + + + + + + + + + + + + + + + + ) + + + + * + + + + + + + + + ( function() { + + return ( + ( + + + ) + + + + ) ? 1 : 0; + } )() + + + + + + + + + == + != + > + < + >= + <= + + + + + + + + + + + + + + + + ( function() { + + + + + else + + + if ( + + + + * + + + + + ) { return + + + ; } + + + + + + + + else + + + + if ( true ) + + + + { return + + ; } + + + } )() || 0 + + + + + + + + + + + + + [ + + + , + + + + + ] + + + + + + + + + (function(){ + + var cdr = Array.prototype.slice.call( + + , 0); + cdr.unshift( + + ); + + return cdr; + })() + + + + + ( + + [0]||0) + + + + + .slice(1) + + + + + + ( + + .length || 0 ) + + + + + + + + + + + + + + + + + ( + + + = + + function( + + + + , + + + + + ) { + + + return + + ; + } ) + + + ( + + + , + + + + ( + + ) + + ) + + + + + + + + func_ + + + + + + (function(){ + var result = + + ; + + + console.log( + + ' + + ', + + + result ); + return result; + })() + + + + + + ( function () { + throw Error( "Unknown calculation: + + " ); + } )() + + + diff --git a/src/current/compiler/js.xsl b/src/current/compiler/js.xsl new file mode 100644 index 00000000..55ea0299 --- /dev/null +++ b/src/current/compiler/js.xsl @@ -0,0 +1,1908 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + ' + + ':' + + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/compiler/linker.xsl b/src/current/compiler/linker.xsl new file mode 100644 index 00000000..f6a04783 --- /dev/null +++ b/src/current/compiler/linker.xsl @@ -0,0 +1,1442 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cannot link + + ; must link program + + + + + + + + + + + + + + + + + linking + + ... + + + + + + + + + building dependency tree... + + + + + + + + + + + + + + + + + + resolving dependency tree... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + l:mark-class found for non-existing symbol + + ; there is a bug in l:depgen-process-sym + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( + + ) + + p - + + s - + + r - + + [s:: + + ::s] [r:: + + ::r] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + unresolved extern + + (declared by ` + + ') + + + + + + + + + + + + + + + + + + + + + + + + could not resolve external symbol ` + + ' + + + + + + + + + + + + + ambiguous external symbol ` + + '; resolution failed (found + + + ; + + + + ); pulled in by: + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + symbol name is not unique: ` + + ' found in + + + + and + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + depends upon + + external + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + could not locate dependency list for + + / + + + + + + + + + + + + + + + + + + failed locating dependency symbol ` + + ' + from package + + + + + + + + + + + + + + + + internal error: unknown symbol for l:depgen-sym: + + + + + + + + + + + + + circular dependency + + ( + + ): + + + + - + + + + + + + + + + + + + + + + + + + compiling entry point... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + compiling exit... + + + + + + + + compilation complete. + + + + + + + + + + + + + + + + + + + + + fatal: missing exit fragment: + + + + + + + + + + + + + + + + + ** linking metadata... + + + + + + + + + + + + + + + + ** linking worksheet... + + + + + + + + + + + + + + + + ** linking classifier... + + + + + + + + + + + + + + + + + + + ** linking global params... + + + + + + + + + + + + + + + + + ** linking types... + + + + + + + + + + + + + + + + + ** linking functions... + + + + + + + + + + + + + + + + + ** linking rater... + + + + + + + + + + + + + + + + + + + + + + + + + + + linking + + ... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + missing object code for symbol + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + could not locate package for exit-fragment: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + generating input map... + + + + + + + + missing object code for input map head or tail + + + + + + + + + + + + + + + + + + + + + + + + generating return map... + + + + + + + + missing object code for return map head or tail + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + could not locate symbol dependencies: + + + + + + + + + + + + + + + + + + map + + + + is not a known + + field for + + ; ensure that it exists and is either used or has @keep set + + + + + + + + + + + + + + + diff --git a/src/current/compiler/linker/log.xsl b/src/current/compiler/linker/log.xsl new file mode 100644 index 00000000..9c8db608 --- /dev/null +++ b/src/current/compiler/linker/log.xsl @@ -0,0 +1,95 @@ + + + + + + + + + + + + [ + + ] + + + + + + + + + + + + + [ + + ] + + + + + + + + + + + + + [ + + ] warning: + + + + + + + + + + + + + + + [ + + ] error: + + + + + + + + + + + + + + + [ + + ] internal error: + + + + + + + + diff --git a/src/current/compiler/map.xsl b/src/current/compiler/map.xsl new file mode 100644 index 00000000..10d8c426 --- /dev/null +++ b/src/current/compiler/map.xsl @@ -0,0 +1,997 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (function(){ + + var result= + + + + + + + + + ; + + return (result === "") ? ' + + ' : result; + })() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/compiler/validate.xsl b/src/current/compiler/validate.xsl new file mode 100644 index 00000000..91cfd03a --- /dev/null +++ b/src/current/compiler/validate.xsl @@ -0,0 +1,771 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + [validate] prohibited; skipping + + + + ... + + + + + + [validate] validating + + + + ... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + for application of + + () + + + + + + + + + + + + + + + + + + + + + + + + + + + ` + + ' is unknown for classification + + + + + + + + + + + + + + + + + + + ` + + ' is unknown for classification + + + + + + + + + + + + + + + + + + + + + + + + + + + + is not used to classify + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + is + + + + undefined + + + + of type ' + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + internal warning: unresolved param + dimension: ` + + ' + + + + + + + Unexpected vector/matrix reference + + + + + (did you forget @index?) + + + + + + + + + + + + + + requires + + indexes (use c:index) unless being + passed as a function argument + + + + + + + + + + + + may only have + + index(s) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Argument ` + + ' is unknown for function ` + + ' + + + + + + + + + + + + + + + + + + + + + Expected type ' + + ' for + + , but found ' + + ' + + + + + + + + + + + + + + + unknown classification ' + + ' referenced by + + + + + + + + + + + + + missing or empty @yields; see document dump + + + + + + + + + + + + + Cannot create generator ' + + '; generating expressions must contain both @of + and a sub-expression. + + + + + + + + + + + + + + + @desc required when creating generator + + + + + + + + + + + + + + + / + + + + + + + + + [ + + ] + + + + + @yields= + + + + + @name= + + + + @label= + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/compiler/validate/domain.xsl b/src/current/compiler/validate/domain.xsl new file mode 100644 index 00000000..0d84a8cf --- /dev/null +++ b/src/current/compiler/validate/domain.xsl @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + internal error: no domain symbol provided; + caller: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + internal error: unexpected node for lvv:domain-chk: + + + + + + + + + + + + + + + + + + + + + + + + + + error: no domain found for + + / + + + + + + + + + diff --git a/src/current/compiler/validate/param.xsl b/src/current/compiler/validate/param.xsl new file mode 100644 index 00000000..1d18d7a8 --- /dev/null +++ b/src/current/compiler/validate/param.xsl @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + ' + + ' is undefined for param + + + + + + + + + + + + + + + + + + + + + + + + + + internal error: in limbo processing param ` + + ' @default + + + + + + + + param ` + + ' @default of ` + + ' is not within its domain of + + / + + + + + + + + + + + + + diff --git a/src/current/compiler/worksheet.xsl b/src/current/compiler/worksheet.xsl new file mode 100644 index 00000000..9149ddd4 --- /dev/null +++ b/src/current/compiler/worksheet.xsl @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/doc/.gitignore b/src/current/doc/.gitignore new file mode 100644 index 00000000..2fa45d09 --- /dev/null +++ b/src/current/doc/.gitignore @@ -0,0 +1,4 @@ +*.aux +*.pdf +*.log +*.toc diff --git a/src/current/doc/chapters/class.tex b/src/current/doc/chapters/class.tex new file mode 100644 index 00000000..82a2f624 --- /dev/null +++ b/src/current/doc/chapters/class.tex @@ -0,0 +1,372 @@ +\chapter{Classification System} +The classification system is one of the most powerful features of \lang, +allowing precise control over the classification and conditional processing of +large sets of data, whether it be external input or values generated from within +\lang\ itself. Virtually every conditional calculation is best represented +through use of the classification system. + + +\section{Classification Matcher} +Data classification is performed by the classification matcher (sometimes +referred to simply as the ``matcher''). Put simply, it is a function (defined by +\aref{cmatch}) that, given a vector of inputs, produces a boolean vector (which +may itself contain boolean vectors) determining if the given input conforms to a +set of stated rules. A set of rules operating on a set input vectors is +collectively known as a \term{classification}. The system that performs matching +based on classifications is referred to as a \term{classifier}. + +A single classification can be separated into a set of rules, often referred to +as \term{matches} within the context of \lang. A single rule attempts to match +on a vector of inputs.\footnote{Scalar inputs are a special condition defined in +\sref{cmatch-scalar}.} A simple example of such a match is shown in +\fref{cmatch-ex-single}. + +\begin{figure}[h] + $$ + I = \left[ + \begin{array}{c} + 1 \\ 3 \\ 4 \\ 1 + \end{array} + \right] + \qquad + M = \left[ + \begin{array}{c} + 1 \\ 4 + \end{array} + \right] + \quad + \to + \quad + R = \left[ + \begin{array}{c} + \top \\ \bot \\ \top \\ \top + \end{array} + \right]. + $$ + + \caption{A simple classification match $M$ on input $I$ and its result vector + $R$.} + \label{f:cmatch-ex-single} +\end{figure} + +In \fref{cmatch-ex-single}, the input vector $I$ is \term{matched} against the +rule $M$. The output is a boolean result vector $R$ which can be summarized with +the following rule: + +$$ + R_n = \exists m\in M(m = I_n). +$$ +\noindent +In other words, $R_n$ is $\top$ if $I_n\in M$ and is $\bot$ if $I_n\notin M$. +Under this definition, $M$ can be considered to be the \term{domain} under which +a given input $I_n$ is considered to be valid (a \term{match}). + +We say that a classification rule \term{matches} if \emph{any} input matches. +That is: + +$$ + \left[\textrm{The rule $M$ matches input $I$}\right] + \iff + \top\in R +$$ +\noindent +Another way to think of this concept is the reduction of the result vector $R$ +using a logical OR. Alternatively, one could assert that: + +$$ + \left[\textrm{The rule $M$ matches input $I$}\right] + \iff + \sum\limits_n R_n \geq 1, \qquad R \in \set{0,1}, +$$ +\noindent +if an implementation were willing to use the sets \boolset and \set{1,0} +interchangeably.\footnote{See \sref{cmatch-int}.} + +The following sections, however, serve to demonstrate that such a simple view of +the classification system, while useful for an introductory demonstration, is +not sufficient when considering the level of flexibility that is necessary to +handle more complicated data (in particular, when $I$ is a +matrix).\footnote{See $\Omega$-reductions, introduced in +\asref{cmatch}{omega-reduce}.} + +%TODO: More example sections + + +\subsection{Classification Match (cmatch) Algorithm} +\label{a:cmatch} + +The classification match (``cmatch'') algorithm is used to determine if a given +set of data matches a given set of classification criteria. + +Let $I$ be the vector of input values.\footnote{$I$ may be a matrix (a vector +of vectors).} Let $M$ be the vector of predicates to match against $I$ such +that a match will be considered successful if \emph{any} predicate is true. +Since $I$ shall always be a vector of values---even if the vector contains only +one element (see algorithm below for comments on scalar values)---$M$ should be +a vector of one element if the desire is to match against a scalar value (rather +than a vector of values). Let $c$ (clear) be a boolean value\footnote{$1$ or $0$ +when used within an integer context within the algorithm.} representing whether +the results of this operation should be logically AND'd together with the +prior cmatch result ($R'$ in the algorithm below); otherwise, the results will +be OR'd (see step \ref{a:cmatch-c} below). + +Let $A\!\left(M,I,c,R'\right)$ (the ``algorithm'') be defined as: + +\begin{enumerate} + \item + Let $R$ be the result vector. + + \item\label{a:cmatch-scalar} + If the given input vector $I$ is a scalar, it should be converted to a vector + of length 1 with the value of the single element being the original scalar + value of $I$---that is, let $s$ be the original scalar value of $I$; then: $I + = \left[ s \right]$. If $s$ is undefined, then an empty result vector should + be returned. + + \item\label{a:cmatch:input-vectorize} + Step \ref{a:cmatch-scalar} should also be done to the match vector $M$, + yielding $M = \left[ s \right]$ where $s$ is the original scalar $M$. If $s$ + is undefined, then it should be treated as if it were the integer + $0$.\footnote{Consistent with the behavior of the remainder of the DSL.} + + \item + Step \ref{a:cmatch-scalar} should also be done to the prior result vector + $R'$, yielding $R = \left[ s \right]$ where $s$ is the original scalar $R'$. + This situation may result from recursing at step \ref{a:cmatch-mrecurse} when + $R'_k$ is a scalar. If $s$ is undefined, then $R'$ should be initialized to an + empty vector, implying a fresh match (no prior results). + \goodbreak + + \item\label{a:cmatch-iter} + The length of the result vector $R$~($\#R$) shall be the larger of the length + of the input vector $I$~($\#I$) or the prior result vector $R'$~($\#R'$). + For each $I_k \in I$: + + \begin{enumerate} + \item\label{a:cmatch-mrecurse} + If $I_k$ is a vector, recurse, beginning at step 1. Let $r = + A(M_k,I_k,c,R'_k)$. + + \begin{align*} + u &= \left\{ + \begin{array}{ll} + \bot & \textrm{if }\#R' > 0, \\ + c & \textrm{otherwise.} + \end{array} + \right. \\ + % + R_k &= \left\{ + \begin{array}{ll} + r & \textrm{if $R'_k$ is a vector or undefined}, \\ + \Omega(r,u) & \textrm{otherwise}.\footnotemark + \end{array} + \right. + \end{align*} + + \footnotetext{\label{a:cmatch-order} If $R'_k$ is a scalar, we must ensure + consistency with step \ref{a:cmatch-c} to ensure that the algorithm is not + dependent on input or execution order. Note the use of $u$ in place of + $c$---this ensures that, if there are any $R'$, we are consistent with the + effects of step \ref{a:cmatch:fill} (but in reverse).} + + Continue with the next $I$ at step \ref{a:cmatch-iter}. + + \item + \label{a:cmatch:omega-reduce} + Otherwise, $I_k$ is a scalar. Let $t$ be a temporary (intermediate) scalar + such that $t = \exists m \in M m(I_k)$. + + \item\label{a:cmatch-c} + Let $v = \Omega\left(R'_k,c\right)$ and let + $$ + R_k = \left\{ + \begin{array}{ll} + v \wedge t & c = \top, \\ + v \vee t & c = \bot. + \end{array} + \right., + $$ + + where\footnote{$\Omega$ is simply the recursive reduction of a vector using + a logical OR. This function exists to resolve the situation where $R'_k$ is + a vector of values when $I_k$ is a scalar, which will occur when $M_k$ is + scalar for any $k$ during one application of the cmatch algorithm and $M_k$ + is a vector for another iteration, where $R'$ is the previous match using + scalars. Note also that $X$, according to the recursion rule, may only be + undefined on the first iteration (in effect initializing the value).} + + $$ + \Omega\left(X,u\right) = \left\{ + \begin{array}{ll} + u & \textrm{if X is undefined,} \\ + X & \textrm{if X is a scalar,} \\ + \exists x\in X \Omega(x,u) & \textrm{otherwise.} + \end{array} + \right. \> + \mbox{ + $X \in \left\{\textrm{undefined},\top,\bot\right\}$ + or a vector. + } + $$ + \end{enumerate} + + \item\label{a:cmatch:fill} + Let $v = \Omega\left(R'_k,c\right) \wedge \neg c$. If $\#R' > \#I$, + $$ + R_k = \left\{ + \begin{array}{ll} + v & \exists n\in I(n\textrm{ is a scalar}), \\ + \left[v\right] & \textrm{otherwise.}\footnotemark + \end{array} + \right. + k \in \left\{j : \#I \leq j < \#R' \right\}. + $$ + + \footnotetext{Note that step \ref{a:cmatch:fill} will produce results + inconsistent with the recursive step \ref{a:cmatch-mrecurse} if there exists + an $I_n$ that is a matrix; this algorithm is not designed to handle such + scenarios.} +\end{enumerate} + +Given a set of classification criteria $C$ such that $C_k = M$ for some integer +$k$ and some application of $A$, and a vectorized clear flag $c$ such that $c_k$ +is associated with $C_k$, the final result $F(\#C-1)$ shall be defined as + +$$ + F(k) = \left\{ + \begin{array}{ll} + A\left(C_k,I_k,c_k\right) & \textrm{k = 0,} \\ + A\bigl(C_k,I_k,c_k,F\!\left(k-1\right)\bigr) & \textrm{otherwise.} + \end{array} + \right. +$$ + +The order of recursion on $F$ need not be right-to-left; $A$ is defined such +that it will produce the same result when applied in any order. This is +necessary since the input may be provided in any order.\footnote{Ibid, +\ref{a:cmatch-order}.} + +\subsubsection{Boolean Classification Match} +\label{s:cmatch-boolean} +A scalar boolean classification match $b$ may be obtained simply as $b = +\Omega\left(F,\bot\right)$, where $F$ and $\Omega$ are defined in the algorithm +above. Consequently, note that an empty result set $F$ will be treated as +$\bot$, since index $0$ will be undefined. + +\subsubsection{Match Vector} +$M$ is defined to be a vector of predicates which serve to {\sl match} against a +vector of input values. Most frequently, predicates will likely be against scalar +values. In such a case, an implementation may choose to forego function +application for performance reasons and instead match directly against the +scalar value. However, this document will consider scalar matches in the context +of predicates as functions. As such, if $M$ is a matrix, then the results are +implementation-defined (since the value does not make sense within the algorithm +as defined). + +\subsubsection{Integer Results} +\label{s:cmatch-int} +$A$ defines $R$ to be a vector/matrix of boolean values. However, it may be +useful to use the cmatch results in calculations; as such, implementations that +make use of or produce cmatch results are required to do one or both of the +following where $b$ is a boolean scalar: + +\begin{enumerate} + \item + Implicitly consider $b$ to be $\textrm{int}\!\left(b\right)$ when used in + calculations, and/or + + \item + Perform the implicit conversion before $R$ is returned from $A$, +\end{enumerate} + +where the function {\sl int} is defined as + +$$ + \textrm{int}(b) = \left\{ + \begin{array}{ll} + 1 & \textrm{if }b = \top, \\ + 0 & \textrm{if }b = \bot. + \end{array} + \right.\qquad + b \in \left\{\top,\bot\right\}. +$$ + + +\subsection{Scalar Classification Matches} +\label{s:cmatch-scalar} +Implementations may find it convenient to support scalar inputs and scalar +classification matches to represent matching ``all'' indexes of a vector. +\aref{cmatch} defines both a classification match ($R$, and consequently $F$) +and an input ($I$) to be a vector, which is generally sufficient. However, in +the case where the number of indexes of the inputs and results of other matches +may be arbitrary, it may be useful to apply a certain classification across all +indexes, which cannot be done when $c = \top$ using \aref{cmatch}. + +The onus of such a feature is on the implementation---it should flag such input +($I$) as a scalar, which is necessary since $I$ is unconditionally converted to +a vector by step \asref{cmatch}{input-vectorize}. If an implementation decides +to support scalar classification matches, \emph{it must conform to this +section}. Let such a scalar flag be denoted $s_k \inbool$ respective to input +$I_k$. Handling of both $F$ and $I$ is discussed in the sections that follow. + +\subsubsection{Mixing Scalar And Vectorized Inputs} +\label{s:cmatch-scalar-mixed} +Under the condition that $\exists v\in s(v=\top)$, the compiler must: + +\begingroup + % this definition is local to this group + \def\siset{k \in\set{j : s_j = \top}} + + \begin{enumerate} + \item + Reorder inputs $I$ such that each scalar input $I_k, \siset$ be applied + after all non-scalar inputs have been matched using \aref{cmatch}. + \begin{enumerate} + \item + Consequently (and contrary to what was mentioned in \aref{cmatch}), + application order of $A$ with respect to inputs $I$ \emph{does} in fact + matter and implementations should ensure that this restriction holds + during runtime. + \end{enumerate} + + \item + Before application of a scalar input, the scalar $I_k$ should be vectorized + according to the following rule: + + $$ + I'_{k,l} = I_k, + \qquad \siset, + \; 0 \leq l < \#R', + $$ + + where $R'$ is the value immediately before the application of $I_k$ as + defined in \aref{cmatch}. + + \item + Application of \aref{cmatch} should then proceed as normal, using $I'$ in + place of $I$. + \end{enumerate} +\endgroup + +\subsubsection{Converting Vectorized Match To Scalar} +As defined by \aref{cmatch}, the result $R$ will always be a vector. An +implementation may \emph{only} convert a vectorized match to a scalar using the +method defined in this section under the condition that $\forall v\in +s(v=\top)$; otherwise, there will be a loss of data (due to the expansion rules +defined in \sref{cmatch-scalar-mixed}). The implementation also \emph{must not} +reduce the vectorized match to a scalar using $\Omega$. An implementation +\emph{may}, however, $\Omega$-reduce the match result $R$ into an +\emph{separate} value as mentioned in \sref{cmatch-boolean}. + +Under the condition that $\forall v\in s(v=\top)$, the system may post-process +$F$ (as defined in \aref{cmatch}) such that + +$$ + F' = F_0, +$$ + +and return $F'$ in place of $F$. + +Note also that $F'$ may be fed back into \aref{cmatch} as an input and that the +results will be consistent and well-defined according to +\sref{cmatch-scalar-mixed} (and, consequently, this section). diff --git a/src/current/doc/manual.sty b/src/current/doc/manual.sty new file mode 100644 index 00000000..b3524f49 --- /dev/null +++ b/src/current/doc/manual.sty @@ -0,0 +1,30 @@ +% manual style package + +% these margins ensure that the PDF can be easily scrolled vertically without +% worrying about alternating margins (good for viewing on screen, but not on +% paper) +\usepackage[margin=1.25in]{geometry} +\usepackage{amsmath} + +\setcounter{secnumdepth}{3} +\setcounter{tocdepth}{3} + +% no name yet +\def\lang{the DSL} + +\def\sref#1{Section \ref{s:#1}} +\def\fref#1{Figure \ref{f:#1}} +\def\aref#1{Algorithm \ref{a:#1}} +\def\asref#1#2{A\ref{a:#1}(\ref{a:#1:#2})} + +\def\set#1{% + \ifmmode% + \left\{#1\right\}% + \else + $\left\{#1\right\}$% + \fi% +} +\def\boolset{\set{\top,\bot}} +\def\inbool{\in\boolset} + +\def\term#1{{\sl #1}} diff --git a/src/current/doc/manual.tex b/src/current/doc/manual.tex new file mode 100644 index 00000000..9d1d80ec --- /dev/null +++ b/src/current/doc/manual.tex @@ -0,0 +1,19 @@ +\documentclass[10pt]{book} + +%%begin preamble + \usepackage{manual} + + \author{Mike Gerwitz\\LoVullo Associates} + \date{\today} +%%end preamble + +\begin{document} + +\title{Calc DSL: Design Specification and Programmer's Manual} +\maketitle + +\tableofcontents + +\include{chapters/class} + +\end{document} diff --git a/src/current/dot.xsl b/src/current/dot.xsl new file mode 100644 index 00000000..ed0bb39e --- /dev/null +++ b/src/current/dot.xsl @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + [dot] fatal: this is not an object/executable file: + no symbol dependencies found + + + + + + + /* dependency graph of + + */ + + digraph " + + " { + + graph [rankdir="LR", ranksep="2"]; + + + + + + } + + + + + diff --git a/src/current/dot/attr-color.xsl b/src/current/dot/attr-color.xsl new file mode 100644 index 00000000..4ef7c01d --- /dev/null +++ b/src/current/dot/attr-color.xsl @@ -0,0 +1,72 @@ + + + + + + + + + + #204a87 + + + + + + + #729fcf + + + + + + + #4e9a06 + + + + + + + #c4a000 + + + + + + + #888a85 + + + + + + + + + + diff --git a/src/current/dot/attr-extern.xsl b/src/current/dot/attr-extern.xsl new file mode 100644 index 00000000..318da4a6 --- /dev/null +++ b/src/current/dot/attr-extern.xsl @@ -0,0 +1,33 @@ + + + + + + + + + + dashed + + + + + + + + + + diff --git a/src/current/dot/attr-keep.xsl b/src/current/dot/attr-keep.xsl new file mode 100644 index 00000000..3a72af49 --- /dev/null +++ b/src/current/dot/attr-keep.xsl @@ -0,0 +1,33 @@ + + + + + + + + + + red + + + + + + + + + + diff --git a/src/current/dot/attr-shape.xsl b/src/current/dot/attr-shape.xsl new file mode 100644 index 00000000..f4bc289f --- /dev/null +++ b/src/current/dot/attr-shape.xsl @@ -0,0 +1,62 @@ + + + + + + + + + + box + + + + + + + octagon + + + + + + + component + + + + + + + note + + + + + + + + + + diff --git a/src/current/dot/defnode-attr.xsl b/src/current/dot/defnode-attr.xsl new file mode 100644 index 00000000..778835a0 --- /dev/null +++ b/src/current/dot/defnode-attr.xsl @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + /\n + + + + + + / + + + + + + + + + + + + + + + + + + , + + + + =" + + " + + + + diff --git a/src/current/dot/defnode.xsl b/src/current/dot/defnode.xsl new file mode 100644 index 00000000..c34c591b --- /dev/null +++ b/src/current/dot/defnode.xsl @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + " + + " [ + + + + + , + + + + href=" + + " + + ]; + + + + + + + + diff --git a/src/current/dot/depout.xsl b/src/current/dot/depout.xsl new file mode 100644 index 00000000..5b3dbdab --- /dev/null +++ b/src/current/dot/depout.xsl @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + [root=ctr,fontsize=24,style=bold,label="Yield"]; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + " + + " -> " + + " + + + [ + + ] + + + ; + + + + + + + + + error: what do I do!?: unexpected + + + + + + + + + + + + + diff --git a/src/current/dot/pkg-exec.xsl b/src/current/dot/pkg-exec.xsl new file mode 100644 index 00000000..1c934bfa --- /dev/null +++ b/src/current/dot/pkg-exec.xsl @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + error: cannot locate symbol dependencies for ` + + ' + + + + + + + + + diff --git a/src/current/dot/pkg-obj.xsl b/src/current/dot/pkg-obj.xsl new file mode 100644 index 00000000..d281cffd --- /dev/null +++ b/src/current/dot/pkg-obj.xsl @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/calc-display.xsl b/src/current/include/calc-display.xsl new file mode 100644 index 00000000..4f9f0fac --- /dev/null +++ b/src/current/include/calc-display.xsl @@ -0,0 +1,702 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \left( + + + + + + \right) + + + + + + + + + + + + + + + + + + + + + + k + + + + + + + + + + + + + + + + + + + + + + + + + =0 + + + + \sum \limits_{ + + } + + + + + ^{\grave\# + + } + + + + + + + + + + + + + + + + + + + + + + + ( + + + + + + \,\cdot\, + + + + + + \left( + + + + + + + \right) + + + + + ) + + + + + + + + + + + \frac{ + + + + }{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \left\l + + + + \right\r + + + + + + + + + + + + + + + + + + \left( + + + + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + \right) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \left[ + + + + + \text{ and } + + + + + + + + + + + + \right] + + + + + + \begin{cases} + + \end{cases} + + + + \;\;\; + + + + + + + + + + + + + + & + + + + [ + + + + + + + \text{if } + + + + + + + + + + \text{otherwise} + + + + + + + ] + + + + ; \\ + + + + . + + + + + + + + + + + + + + + + + + = + \not=\; + \gt + \lt + \geq + \leq + + + + + + + + + + + + \left[ + + + , + + + + + \right]^T + + + + + \left[\begin{array}\\ + + + + \\ + + + + + & + + + { + + } + + + + \end{array}\right] + + + + + \#\left( + + \right) + + + + \textrm{cons}\left( + + , + + \right) + + + + \left( + + \right)_0 + + + + \textrm{cdr}\left( + + \right) + + + diff --git a/src/current/include/depgen.xsl b/src/current/include/depgen.xsl new file mode 100644 index 00000000..d897c27d --- /dev/null +++ b/src/current/include/depgen.xsl @@ -0,0 +1,526 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [depgen] *determining symbol dependencies... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [depgen] internal error: + could not locate dependency symbol ` + + ' in local symbol table; needed by + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \textrm{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [depgen] error: unexpected symbol + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [depgen] warning: unknown symbol ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] !!! fatal: internal classification ` + + ' cannot pull in external classification ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/display.xsl b/src/current/include/display.xsl new file mode 100644 index 00000000..7296b560 --- /dev/null +++ b/src/current/include/display.xsl @@ -0,0 +1,551 @@ + + + + + + + + + + + + + + + + + + + + + + + scalar + + + + + + + + + + generator; vector + + + ( + + + + ) + + + + + + + + + + + + + + + + + + + + " + + " + classification + + + + scalar + + + + vector + + + + matrix + + + + [dim + + ] + + + + + + ( + + + + ) + + + + + + + + + + + + + + + + + + + ( + + + + ) + + + + + + + (!) + + + + + + + + + + + + + + + + + + + _{ + + } + + + + _{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fparam + + + + + + class + + + + generator + + + + + + + + + + + + + + + \textrm{ + + } + + + + + + + + + ( + + + + + + + + + + + + + + _ + + + + + + + + { + + + + + + + + } + + + + ) + + + + + _{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unknown @name reference: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [summary] !!! unknown let-list type + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +
  • + + + + + + + \( + + = + + + + + \) + + + ( + + ) + + + + + let \( + + \) = + + + + + + +
  • +
    + +
    diff --git a/src/current/include/dslc-base.xsl b/src/current/include/dslc-base.xsl new file mode 100644 index 00000000..53a31959 --- /dev/null +++ b/src/current/include/dslc-base.xsl @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/entry-form.xsl b/src/current/include/entry-form.xsl new file mode 100644 index 00000000..3d6b3c8b --- /dev/null +++ b/src/current/include/entry-form.xsl @@ -0,0 +1,323 @@ + + + + + + + + + + +
    +

    Rating Test Case

    + +
    +

    + +
    + + +
    + +
    + +
    + + +
    + +
    +

    Submit Test Case

    + +

    Submission comments (please describe what you were testing, the + desired result and, if the premium was incorrect, what went wrong):

    + + + +
    +

    Expected premium (if known; must be exact); this will allow us to + automatically re-run this test when we believe that the problem has been + fixed. Otherwise, you must re-test manually:

    + + (Only fill out if it does not hit the minimum premium.) +
    + +
    + + +
    + + + +
    +
    + +
    + + + + + +
    +
    + + +
    + + + + + + + + + + + + + + + [] + + + + + +
    + +
    + + + + matrix + + + + +
    +
    +
    + + + + + + + + + + +
    + + + + +
    + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + selected + + + + + + selected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [summary] warning: unknown param type ` + + / + + ' + + + + Unknown type: + + + + + + + + + + + + + + + + + + + + +
    diff --git a/src/current/include/exslt/str.tokenize.template.xsl b/src/current/include/exslt/str.tokenize.template.xsl new file mode 100644 index 00000000..6da270b3 --- /dev/null +++ b/src/current/include/exslt/str.tokenize.template.xsl @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/orderizer.xsl b/src/current/include/orderizer.xsl new file mode 100644 index 00000000..170bd2b9 --- /dev/null +++ b/src/current/include/orderizer.xsl @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [orderizer] recursively discovering param classes... + + + + + + + + + + + + + + + [orderizer] checking previous UI siblings: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/preproc/domain.xsl b/src/current/include/preproc/domain.xsl new file mode 100644 index 00000000..6dc436d3 --- /dev/null +++ b/src/current/include/preproc/domain.xsl @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + warning: union ` + + ' has no subdomains; something is probably wrong + + + + + + + + + + + + + + + + + + + + + + + + + + warning: typedef ` + + ' is empty; something is probably wrong + + + + + + + + + + + + + error: typedef ` + + ' must not contain both @value and non-@value items + + + + + + + + + error: malformed typedef ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + internal error: preproc:mkdomain on non-value item: + + + + + + + + + + + + + internal error: unknown domain source: + + + + + + diff --git a/src/current/include/preproc/eligclass.xsl b/src/current/include/preproc/eligclass.xsl new file mode 100644 index 00000000..8e78c09a --- /dev/null +++ b/src/current/include/preproc/eligclass.xsl @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/eligclass] generating eligibility class + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/eligclass] error: could not load ` + + ' object file + + + + + + + + + + [preproc/eligclass] internal: empty eligibility + class for ` + + '; skipping + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/preproc/expand.xsl b/src/current/include/preproc/expand.xsl new file mode 100644 index 00000000..57c68564 --- /dev/null +++ b/src/current/include/preproc/expand.xsl @@ -0,0 +1,691 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + . + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + matrix + + + + + + + + + vector + + + + + + + + __is + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + __is + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/preproc/macros.xsl b/src/current/include/preproc/macros.xsl new file mode 100644 index 00000000..4c4f8e6b --- /dev/null +++ b/src/current/include/preproc/macros.xsl @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + + + + + + + + !!! [preproc] error: + + + + + + + + + + + + [preproc] *REPASS* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cannot take index of scalar value: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] waiting to expand rate-each + + (immediate template(s) need expansion)... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + rate-each must provide either @yields or @generates + + + + + + + + + + + + + + + + + Set of individual + + premiums + + + + + + Zero if not + + , otherwise one + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/preproc/package.xsl b/src/current/include/preproc/package.xsl new file mode 100644 index 00000000..48536af4 --- /dev/null +++ b/src/current/include/preproc/package.xsl @@ -0,0 +1,817 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] error: missing random seed `__rseed' + + + + + [preproc] *beginning macro expansion... + + + + + + + + + + [preproc] *macro pass complete; expanding... + + + + + + + + + [preproc] *expansion complete; generating symbol table... + + + + + + + + + + + [preproc] *symbol table generated; checking for + unprocessed templates... + + + + + + + + + + + !!! [preproc] error: + + + + + + + + + + + + + + + + + + + + + + + !!! [preproc] error: + + + + + ~~~~[begin document dump]~~~~ + + ~~~~[end document dump]~~~~ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] compiling fragments... + + + + + + + + + + + + + + + + + + + + + + [preproc] fatal: unexpanded template parameter: + + + + + [preproc] fatal: reference node: + + + + ~~~~[begin document dump]~~~~ + + ~~~~[end document dump]~~~~ + + [preproc] notice: Document dumped. + + + + + + + [preproc] fatal: unexpanded template: + + + + + [preproc] fatal: reference node: + + + + + + ~~~~[begin document dump]~~~~ + + ~~~~[end document dump]~~~~ + + [preproc] notice: Document dumped. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] + + template(s) still need application: + + + + , + + + + + + + + + + + + + + + + + + + !!! [preproc] fatal: unable to locate symbols for + remaining templates: + + + + ; + + + + + + + + + + + !!! [preproc] fatal: terminating due to errors + + + + + + + + + + + + [preproc] *expansion complete (recursive) + + + + + + + + + + + + + !!! [preproc] fatal: expansion of remaining + templates aborted (have all been imported?): + + + + ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] template symbol not yet available: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] !!! recursion limit reached in resolving ` + + ' symbols + + + + + + + + + [preproc] *resolving symbol attributes... + + + + + + + + + + + + + + [preproc] *SYM REPASS* + + [preproc] The following + + symbol(s) are still unresolved: + + + + + [preproc] - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] !!! failed to look up symbol ` + + ' + + + + + + + + + + + + + + + + [preproc] deferring ` + + ' dimensions with unresolved dependencies + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + [preproc] !!! failed to determine dimensions of ` + + ' + + + + + + [preproc] resolved ` + + ' dimensions as ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + !!! + + + + ( + + ) + + + : + + + + + + + + Compilation failed due to validation errors. + + + + + + + + ~~~~[begin document dump]~~~~ + + ~~~~[end document dump]~~~~ + internal: document dumped. + + + + + + + diff --git a/src/current/include/preproc/path.xsl b/src/current/include/preproc/path.xsl new file mode 100644 index 00000000..469603d6 --- /dev/null +++ b/src/current/include/preproc/path.xsl @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + ../ + + + + + + + + + + + + + + + + + + + + + + ../ + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + + + diff --git a/src/current/include/preproc/symtable.xsl b/src/current/include/preproc/symtable.xsl new file mode 100644 index 00000000..9210c76c --- /dev/null +++ b/src/current/include/preproc/symtable.xsl @@ -0,0 +1,959 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/symtable] discovering symbols... + + + + + + + + + + + + + + + + + + + + [preproc/symtable] warning: symbol / + + / + + has @override set, but does not override anything + + + + + + + + + + + + + + [preproc/symtable] error: cannot override non-virtual symbol / + + / + + + + + + + + [preproc/symtable] error: duplicate symbol / + + / + + (defined in ./ + + + + + and ./ + + + + + ) + + + + ; did you forget @override? + + + + + + + + + ~~~~[begin document dump]~~~~ + + ~~~~[end document dump]~~~~ + + ~~~~[begin symbol dump]~~~~ + + ~~~~[end symbol dump]~~~~ + + + [preproc/symtable] fatal: aborting due to symbol errors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/symtable] done. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + extern mismatch: ' + + ' (imported from + + ) + + + + ; + + + = + + , + + expected + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + unresolved extern ' + + ' + + + + (required by + + ) + + + + + + + + + + + + + + + + + [preproc/symtable] processing symbol table... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/symtable] error: refusing to import non-package + + ; use @allow-nonpkg to force (if you know what you are doing) + + + + + + + + + + + + + + + [preproc/symtable] importing symbol table of + + ... + + + + + + [preproc/symtable] internal error: + failed to locate symbol table: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + + + + 1 + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/symtable] internal error: + failed to resolve type primitve of ` + + ' + + + + + + + + + + + + + + + + + + + + + + + + + + \textrm{ + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc/symtable] internal error: + failed to resolve type: + + + + + + + + + + + + + + + + + + + + + + 1 + + + + 2 + + + + 0 + + + + + diff --git a/src/current/include/preproc/template.xsl b/src/current/include/preproc/template.xsl new file mode 100644 index 00000000..e1e8edb9 --- /dev/null +++ b/src/current/include/preproc/template.xsl @@ -0,0 +1,1149 @@ + + + + + + + + + + + + + + + + + + + k + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Undefined template + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] expanding template parameters for + + ... + + + + + + + + + + + + + + + + + + + + + Undefined template + + + + + + + + + + + + + + + + + + + undefined template param + / + ; available params are + + + + ; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] preparing inline template + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] deferring application of unknown template + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [preproc] expanding param-copy... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + : + + + + + + + + + + + + + + + warning: + + : + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unknown template comparison attribute for + + in + + : + + + + + =" + + " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + error: unable to determine @yields for class ` + + ' (has the class been imported?) + + + + + + + + + + + + + + + + + + + + + + error: unknown param node content: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/preprocess.xsl b/src/current/include/preprocess.xsl new file mode 100644 index 00000000..b0d8cd53 --- /dev/null +++ b/src/current/include/preprocess.xsl @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + [preproc] [rater] + + + + + + + + + + + + + + diff --git a/src/current/include/symbol-map.xml b/src/current/include/symbol-map.xml new file mode 100644 index 00000000..9cf64218 --- /dev/null +++ b/src/current/include/symbol-map.xml @@ -0,0 +1,80 @@ + + + + \Theta + + + \theta + + + C + + + E + + \kappa + + + K + + + + + + + + \omega + + + G + + \sigma + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/include/util.xsl b/src/current/include/util.xsl new file mode 100644 index 00000000..0e0030fe --- /dev/null +++ b/src/current/include/util.xsl @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + " + + + + ": + + + + + [ + + + , + + + + + ] + + + + { + + + , + + + + + } + + + + " + + + + " + + + + [util] !!! invalid util:json + + + + + + + + + + + + diff --git a/src/current/link.xsl b/src/current/link.xsl new file mode 100644 index 00000000..1c984614 --- /dev/null +++ b/src/current/link.xsl @@ -0,0 +1,8 @@ + + + + + + diff --git a/src/current/map.xsd b/src/current/map.xsd new file mode 100644 index 00000000..d10d3ceb --- /dev/null +++ b/src/current/map.xsd @@ -0,0 +1,412 @@ + + + + + + + + + Classification name (lv:classify/@as) + + + + + + + + Classification should not add a match requiring that at least one + eligible supplier use it (if supported by implementation) + + + + + + + + + + String constant + + + + + + + + + + + Default complex value for a translation + + Concatenates each value. + + + + + + + + + + + + + + Defines a translation for a given value + + + + + + + + + + + + Source value to match against for translation + + + + + + + + Value to translate to + + + + + + + + Default value when the resulting translation is the + empty string + + + + + + + + + + Defines translation rules between source and destination fields; not + to be used with @from + + + + + + + + + + + + + Identifier of source field + + + + + + + + Optional default value if no source value is available + + + + + + + + Whether this field should be considered when generating eligibility + classes (if supported by implementation); default true + + + + + + + + + + + + + + + Maps a static value + + + + + + + + Static value to map to destination + + + + + + + + + + + Maps a source value to its destination by index + + + + + + + + Source field identifier + + + + + + + + Iterator variable or constant integer representing the source + value index + + + + + + + + + + + + + Translates source data into a set + + + + + + + + + + + Source field identifier to use as index for the iterator + + + + + + + + Variable to serve as a reference for the iterator index + + + + + + + + When true, if a transformation yields a value that is undefined, an + empty string, or the string "0", then omit it from the set + + + + + + + + + + Defines a map from a source field to a destination field with optional + transformation rules + + + + + + + + + + + + Identifier of destination field + + + + + + + + Identifier of source field if no data transformations are to be + performed; cannot be used with @value + + + + + + + + Constant value to be mapped to destination; cannot be used with @from + or from node + + + + + + + + Whether this field should be considered when generating eligibility + classes (if supported by implementation); default true + + + + + + + + Override mapping sharing the same destination identifier in an + imported package + + + + + + + + + + Maps from a source field to a destination field of the same name without + any translation; shorthand for identical @to and @from attributes on a + general map node + + + + + + + Identifier of the source (and consequently destination) field + + + + + + + + Do not validate that the field exists; useful for mapping data that is + not explicitly recognized as a field by the source + + + + + + + + Whether this field should be considered when generating eligibility + classes (if supported by implementation); default true + + + + + + + + Override mapping sharing the same destination identifier in an + imported package + + + + + + + + + + + + + + + + + + + Includes mappings from another source file + + + + + + + Path to source file + + + + + + + + + + Maps program data between two points + + + + + + + + + + + + + + + Source document to validate against (document root node must be + known to the implementation) + + + + + + + + + + + Specifies data transformations/filtering to be performed on data before + being returned to a caller + + + + + + + + + + + + diff --git a/src/current/pkg-dep.xsl b/src/current/pkg-dep.xsl new file mode 100644 index 00000000..64c6e9fa --- /dev/null +++ b/src/current/pkg-dep.xsl @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/scripts/entry-form.js b/src/current/scripts/entry-form.js new file mode 100644 index 00000000..b67d9a22 --- /dev/null +++ b/src/current/scripts/entry-form.js @@ -0,0 +1,2164 @@ +/** + * This file is used for direct interaction with the rater for testing purposes. + * As such, much of it is a rushed implementation; it's a bit of a kluge and + * could use some refactoring. + * + * Also, it is terriby stateful and difficult to work with. I have the utmost + * confidence in your ability to look away and pretend you never saw this + * script. + */ + +// intentionally global; developers can override +var program = document.location.pathname.match( '/raters/(.*?)/' )[1], + submit_url = '/raters/submit-test.php?program=' + program, + supplier = rater.supplier, + prior_url = '/raters/submit-test.php?retrieve=' + supplier + + '&program=' + program, + qdata_host = 'dev'; + +var client = ( function() +{ + // URL to which quote/result submissions should be POSTed + var form = document.querySelector( 'form.entry-form' ), + final_prem = form.querySelector( '.final-premium' ), + final_accept = form.querySelector( '.final-accept' ), + final_comments = form.querySelector( '.final-comments' ), + voi = document.getElementById( 'voi-list' ), + coview = document.getElementById( 'class-overview-list' ), + + final_good = document.getElementById( 'final-accept-good' ), + final_bad = document.getElementById( 'final-accept-bad' ), + + load_prior = document.getElementById( 'load-prior' ), + + workstatus = null, + + valspan = {}, + bucket = {}, + rate_result = {}, + + // used to overwrite existing test cases rather than create a new + save_id = '', + prior_result, + + rate_callback = function() {}, + + // whether to ignore user input (do not put in bucket) + ignore_input = false; + + + populateBucket(); + + + function setWorkStatus( message ) + { + if ( workstatus === null ) + { + workstatus = document.createElement( 'div' ); + workstatus.id = 'workstatus'; + + document.body.appendChild( workstatus ); + } + + workstatus.innerHTML = message; + workstatus.className = ( message ) ? 'show' : ''; + } + + function populateBucket() + { + Array.prototype.slice.call( form.querySelectorAll( '[name]' ) ).forEach( + function( field ) + { + var name = field.name.replace( /\[\]$/, '' ); + + if ( !name ) + { + return; + } + + // if the name does not match, then we removed the square + // brackets, meaning that this is a set + bucket[ name ] = ( name === field.name ) + ? field.value + : [ field.value ]; + } + ); + } + + + function overrideBucket( boverride ) + { + for ( var name in boverride ) + { + bucket[ name ] = boverride[ name ]; + } + + emptyBucket(); + } + + + function removeEntryFocus() + { + form.className = form.className.replace( /\bfocus\b/, '' ); + } + + document.body.addEventListener( 'mouseup', function( e ) + { + var overform = hasParent( form, e.target ); + + if ( overform === false ) + { + removeEntryFocus(); + } + } ); + + form.addEventListener( 'reset', function() + { + if ( ignore_input ) + { + return; + } + + // wait until *after* reset + setTimeout( function() + { + clearTestCase(); + + bucket = {}; + populateBucket(); + clearSummaryPremium(); + + setWorkStatus(); + }, 0 ); + } ); + + form.addEventListener( 'mouseover', function() + { + showEntryForm(); + } ); + + + function clearTestCase() + { + save_id = ''; + prior_result = undefined; + + // clear prior message + Prior.setPriorMessage( null ); + + // clear prior class from body + document.body.className = document.body.className.replace( + /\bprior\b/, '' + ); + } + + + function setTestCase( id, result ) + { + save_id = ''+( id ); + prior_result = result; + + // this really should be set... + if ( !( prior_result.vars ) ) + { + prior_result.vars = {}; + } + + // add prior class name to body + document.body.className += ' prior'; + } + + + function showEntryForm() + { + if ( form.className.match( /\bfocus\b/ ) ) + { + return; + } + + form.className += ' focus'; + } + + + // on field change, update bucket + form.addEventListener( 'change', function( e ) + { + if ( ignore_input ) + { + return; + } + + // if we changed something, then the displayed premium (if any) must be + // invalidated + clearSummaryPremium(); + + var target = e.target, + name = target.name.replace( /\[\]$/, '' ), + value = target.value.trim(); + + if ( !name ) + { + return; + } + + // if this is a set, we want to store every value + if ( name !== target.name ) + { + var toarr = Array.prototype.slice; + + // retrieve all the rows + var rows = toarr.call( + target.parentElement.parentElement.parentElement + .querySelectorAll( '.entry-row' ) + ); + + // determine if we're working with a matrix + var matrix = /\bmatrix\b/.test( rows[ 0 ].className ); + + value = []; + rows.forEach( function( row, i ) + { + var ref = value; + + // for matricies, add value to a sub-array; vectors, just keep + // appending to the original array + if ( matrix ) + { + ref = value[ i ] = []; + } + + // add each value + toarr.call( row.querySelectorAll( '[name]' ) ).forEach( + function( node ) + { + ref.push( node.value.trim() ); + } + ); + } ); + } + + bucket[ name ] = value; + } ); + + // update screen on submit + form.addEventListener( 'submit', function( e ) + { + // do not submit the form + e.preventDefault(); + rate( bucket ); + } ); + + form.addEventListener( 'click', function( e ) + { + if ( e.target.className === 'entry-add' ) + { + addRow( e.target.parentElement, e.target ); + e.preventDefault(); + } + else if ( e.target.className === 'entry-rm' ) + { + removeColumn( e.target ); + e.preventDefault(); + } + else if ( e.target.className === 'entry-add-matrix' ) + { + addColumn( e.target ); + e.preventDefault(); + } + } ); + + + + final_good.addEventListener( 'click', function( e ) + { + e.preventDefault(); + + showFinalComments( true, function( comment, _, waiting ) + { + var prem = rate_result.premium; + + hideFinalAccept(); + submitQuote( bucket, rate_result, comment, true, waiting, prem, save_id ); + } ); + } ); + + final_bad.addEventListener( 'click', function( e ) + { + e.preventDefault(); + + showFinalComments( false, function( comment, expect, waiting ) + { + hideFinalAccept(); + submitQuote( bucket, rate_result, comment, false, waiting, expect, save_id ); + } ); + } ); + + + function showFinalComments( looksgood, callback ) + { + final_comments.className += ' show'; + + var submit = document.getElementById( 'final-submit' ), + cancel = document.getElementById( 'final-cancel' ), + + expect_container = document.getElementById( + 'final-expect-container' + ), + + submit_new = document.getElementById( 'final-submit-new' ), + + listener; + + // we do not care about the expected value if the premium looks good + expect_container.style.display = ( looksgood ) + ? 'none' + : 'inline'; + + // if a test case is set, give them the option to clear it and submit it + // as a new test case + submit_new.style.display = ( save_id ) + ? 'inline' + : 'none'; + + // make it very clear what the user is about to do + submit.innerHTML = ( save_id ) + ? 'Update Existing Test Case' + : 'Submit'; + + // we won't use addEventListener becuase we only want one event to be + // attached + submit.onclick = function( e ) + { + e.preventDefault(); + + var comments = document.getElementById( 'final-comments' ), + expected = document.getElementById( 'final-expected' ), + waiting = document.getElementById( 'final-waiting' ); + + callback( + comments.value, + +( expected.value.replace( /^\$/, '' ) ), + !!waiting.checked + ); + + rmclass( final_comments, 'show' ); + }; + + submit_new.onclick = function( e ) + { + e.preventDefault(); + + // clear save id and trigger normal submit + save_id = ''; + submit.onclick( e ); + }; + + cancel.onclick = function( e ) + { + e.preventDefault(); + rmclass( final_comments, 'show' ); + }; + + // give focus to final comments + document.getElementById( 'final-comments' ).focus(); + } + + + function hideFinalAccept() + { + // replace all shows since there may be multiple + final_accept.className = final_accept.className.replace( + /\bshow\b/, + '' + ); + } + + + function getXhrJsonSync( method, url, data ) + { + var xhttp = new XMLHttpRequest(); + + xhttp.open( method, url, false ); + + if ( method.toLowerCase() === 'post' ) + { + xhttp.setRequestHeader( 'Content-type', + 'application/x-www-form-urlencoded' + ); + } + + xhttp.send( ( data ) ? 'data=' + JSON.stringify( data ) : null ); + + if ( xhttp.status !== 200 ) + { + throw Error( 'Submit failed; status: ' + xhttp.status ); + } + + // this will fail if the response is crap, but will be caught by the + // exception + return JSON.parse( xhttp.responseText ); + } + + + function getXhrJson( method, url, data, callback ) + { + var xhttp = new XMLHttpRequest(); + xhttp.open( method, url, true ); + + if ( method.toLowerCase() === 'post' ) + { + xhttp.setRequestHeader( 'Content-type', + 'application/x-www-form-urlencoded' + ); + } + + xhttp.onload = function() + { + if ( xhttp.status !== 200 ) + { + callback( null, + Error( 'Submit failed; status: ' + xhttp.status ) + ); + return; + } + + callback( JSON.parse( xhttp.responseText ) ); + } + + xhttp.send( ( data ) ? 'data=' + JSON.stringify( data ) : null ); + } + + + function submitQuote( + bucket, result, comment, looksgood, waiting, expected, caseid, success_callback + ) + { + // we don't want to modify the original result (could use + // Object.create() here, but they may be using IE) + var tmpresult = function() {}; + tmpresult.prototype = result; + + // it is absolutely pointless to store debug information since the ids + // change at any time and are dependent on the XSL processor + var submit_result = new tmpresult(); + + // so that it's property serialized + for ( var name in result ) + { + submit_result[ name ] = result[ name ]; + } + + // we do not need the debug information (there's a lot of it and it + // changes frequently) + submit_result.debug = undefined; + + // nor do we need constants (especially large ones)! + submit_result.consts = undefined; + + var data = { + bucket: bucket, + result: submit_result, + looksgood: !!looksgood, + waiting: !!waiting, + comment: encodeURIComponent( comment ), + expected: expected, + supplier: supplier, + + // will cause an existing test case to be overwritten, if set + caseid: caseid, + }; + + getXhrJson( 'POST', submit_url, data, function( response, err ) + { + // check the response of the actual save (just because we + // got a HTTP 200 doesn't mean we successfully saved to the + // server; we could have also hit the wrong page + // (misconfigured)!) + if ( err ) + { + alert( + 'Ah, crap! Quote submission failed! Contact IT before ' + + 'you do anything else.\n\n' + + 'Here are the boring details:\n' + + ' ' + err.message + ); + + return; + } + + success_callback && success_callback(); + } ); + } + + + + function addRow( parent, before ) + { + before = before || parent.querySelector( '.entry-add' ); + + // get the row to duplicate + var dup = parent.querySelector( '.entry-row' ) + .cloneNode( true ); + + parent.insertBefore( dup, before ); + + // trigger change so that its value can be recorded + triggerChange( dup.querySelector( '[name]' ) ); + } + + + function addColumn( event_target ) + { + // get the field to duplicate + var dup = event_target.parentElement.querySelector( '.entry-field' ) + .cloneNode( true ); + + event_target.parentElement.insertBefore( dup, event_target ); + + // trigger change so that its value can be recorded + triggerChange( dup.querySelector( '[name]' ) ); + } + + + function removeColumn( event_target ) + { + var rm = event_target.parentElement, + parent = rm.parentElement, + rowParent = parent.parentElement, + + rows = rowParent.querySelectorAll( '.entry-row' ).length, + cols = parent.querySelectorAll( '.entry-field' ).length; + + // do not remove last column of last row + if ( ( rows + cols ) === 2 ) + { + return; + } + + // remove the element + parent.removeChild( rm ); + + // if there are no more columns, remove the row + if ( cols === 1 ) + { + rowParent.removeChild( parent ); + } + + // re-gather values in bucket to accomodate missing value (we can do so + // simply by triggering a change on one of the elements of the same + // name) + triggerChange( rowParent.querySelector( '[name]' ) ); + } + + + function triggerChange( element ) + { + if ( !element ) + { + return; + } + + // create change event + var event = document.createEvent( 'Event' ); + event.initEvent( 'change', true, true ); + + // trigger event + element.dispatchEvent( event ); + } + + + function rate( args, showresults, exception ) + { + showresults = ( showresults === undefined ) ? true : !!showresults; + exception = !!exception; + + var rater = window.rater; + + if ( !( window.rater ) ) + { + alert( 'fatal: rater unavailable.' ); + return; + } + + setWorkStatus( 'Performing rating...' ); + + try + { + var result = rater( args ); + + // XXX: ewwww + rate_result = result; + + if ( !( showresults ) ) + { + return; + } + + // log result to the console in case we want to peeky peeky + console.log( result ); + + rate_callback( result ); + + setWorkStatus( 'Updating premium...' ); + updateSummaryPremium( result.premium ); + + // VOIs are referenced immediately, so render them first + updateVois( result.vars, function() + { + // classes are faster to process than the other summary values + updateSummaryClasses( + result.classes, + result.vars, + undefined, + + function() + { + updateSummaryValues( result.vars ); + } + ); + } ); + } + catch ( e ) + { + setWorkStatus( 'Rating error occurred.' ); + + console && console.log( e ); + + if ( exception ) + { + throw e; + } + else + { + alert( 'fatal: ' + e.message ); + } + } + } + + + function updateSummaryPremium( premium ) + { + final_prem.innerHTML = premium; + final_prem.className += ' show'; + + final_accept.className += ' show'; + + setPlaceholderValue( 'yields_premium', '', premium ); + } + + + function clearSummaryPremium() + { + final_prem.innerHTML = ''; + + rmclass( final_prem, 'show' ); + rmclass( final_accept, 'show' ); + } + + + function getValueDisplay( value ) + { + if ( Array.isArray( value ) ) + { + return joinValues( value ); + } + + return ( value === undefined ) + ? '' + : ''+( value ); + } + + + function updateVois( vars, callback ) + { + setWorkStatus( 'Processing VOIs...' ); + voi.innerHTML = ''; + + var queue = []; + for ( var name in vars ) + { + queue.push( name ); + } + + var vois = {}, + qlen = queue.length, + i = qlen; + + dequeueSetsOf( 10, function( c ) + { + if ( i-- === 0 ) + { + // display the VOIs + processVois( vois ); + document.getElementById( 'voi-container' ).className += ' show'; + + setWorkStatus(); + callback && callback(); + + return; + } + + setWorkStatus( + 'Processing VOIs (' + + Math.floor( ( ( qlen - i ) / qlen ) * 100 ) + + '%)...' + ); + + var name = queue[ i ], + value = vars[ name ]; + + if ( value + && /^prem|^min|^surcharge|^cov(erage)?|^credit|^factor|^rate|Prem|[tT]otal/ + .test( name ) + && !( /^_/.test( name ) ) + ) + { + var display = getValueDisplay( value ), + prior = ( prior_result && prior_result.vars[ name ] ) + ? getValueDisplay( prior_result.vars[ name ] ) + : ''; + + // update values of interest (voi) + if ( display !== '[]' ) + { + vois[ name ] = [ display, prior ]; + } + } + + // continue + c(); + } )(); + } + + + function updateSummaryValues( vars, placeid, callback ) + { + var queue = []; + + for ( var name in vars ) + { + queue.push( name ); + } + + var qlen = queue.length; + + // repaint frequently; this is intensive + dequeueSetsOf( 10, function( c ) + { + if ( queue.length === 0 ) + { + setWorkStatus(); + return; + } + + name = queue.pop(); + + setWorkStatus( + 'Formatting summary values (' + + Math.floor( ( ( qlen - queue.length ) / qlen ) * 100 ) + + '%)...' + ); + + var value = vars[ name ], + display = getValueDisplay( value ), + prior = ( prior_result && prior_result.vars[ name ] ) + ? getValueDisplay( prior_result.vars[ name ] ) + : ''; + + + setPlaceholderValue( name, '', display ); + + if ( prior ) + { + setPlaceholderValue( name, '-prior', prior ); + } + + setLetListPlaceholders( name, display, prior ); + + // continue + c(); + } )(); + } + + + function dequeueSetsOf( n, c ) + { + return function dq( i ) + { + i = i || 0; + + c( function() + { + if ( i === 0 ) + { + setTimeout( function() + { + dq( n ) + }, 0 ); + } + else + { + dq( i - 1 ); + } + } ); + } + } + + + function processVois( vois ) + { + // add the vois to the screen in the proper order (reversed) + var i = window.voi_order.length; + while ( i-- ) + { + var data = window.voi_order[ i ], + name = data[ 0 ], + depth = data[ 1 ], + href = data[ 2 ]; + + if ( vois[ name ] ) + { + var voi = vois[ name ]; + addVoi( name, voi[ 0 ], voi[ 1 ], href, depth ); + } + } + } + + + function addVoi( name, value, prior, href, depth ) + { + depth = depth || 0; + + // if the VOI has a value other than 0 (our poor-man check is using a + // regex to remove anything and see if we have a non-empty string left) + if ( ( value.replace( /[\[\]0,]/g, '' ) === '' ) + && ( prior.replace( /[\[\]0,]/g, '' ) === '' ) + ) + { + return; + } + + var depthstr = '', + i = depth; + while ( i-- ) + { + if ( i === 0 ) + { + depthstr += '|-'; + } + + depthstr += '  '; + } + + // if href is not given, then use name + href = href || name; + + // got lazy. + var tr = document.createElement( 'tr' ); + tr.className = 'depth' + depth; + tr.innerHTML = ( + '' + + '' + + depthstr + name + + '' + + '' + + '' + depthstr.replace( /-/, '' ) + value + '' + + ( ( !prior ) ? '' : + '' + prior + '' + ) + ); + + tr.addEventListener( 'click', function( e ) + { + // ignore link clicks + if ( e.target.nodeName === 'A' ) + { + return; + } + + var val = JSON.parse( value ); + if ( Array.isArray( val ) ) + { + var t = 0; + for ( var i in val ) + { + t += val[ i ]; + } + + val = t; + } + + voiPainterAdd( tr, val ); + } ); + + voi.appendChild( tr ); + } + + + function addClassOverview( name, value ) + { + var prior = ( prior_result && prior_result.vars[ name ] ) + ? getValueDisplay( prior_result.vars[ name ] ) + : ''; + + // got lazy. + var tr = document.createElement( 'tr' ); + tr.innerHTML = ( + '' + + '' + + name + + '' + + '' + ); + + coview.appendChild( tr ); + } + + + function joinValues( values ) + { + var ret = '['; + + if ( Array.isArray( values[ 0 ] ) ) + { + var subvals = []; + + for ( var i in values ) + { + subvals.push( joinValues( values[ i ] ) ); + } + + ret += subvals.join( ', ' ); + } + else + { + ret += ( Array.isArray( values ) ) + ? values.join( ', ' ) + : values; + } + + return ret + ']'; + } + + + function updateSummaryClasses( classes, vars, placeid, callback ) + { + coview.innerHTML = ''; + + var queue = []; + + for ( var name in classes ) + { + queue.push( name ); + } + + var qlen = queue.length; + + dequeueSetsOf( 10, function( c ) + { + if ( queue.length === 0 ) + { + setWorkStatus(); + callback && callback(); + + return; + } + + var name = queue.pop(); + + setWorkStatus( + 'Formatting class summary values (' + + Math.floor( ( ( qlen - queue.length ) / qlen ) * 100 ) + + '%)...' + ); + + // output the classification and the total premium for the class + setPlaceholderValue( 'class-' + name, placeid, + ( + ''+( classes[ name ] ) + + ' -> ' + + vars[ name ] + ), + classes[ name ] + ); + + if ( prior_result + && prior_result.classes + && prior_result.classes[ name ] + ) + { + // XXX: duplicate + setPlaceholderValue( 'class-' + name, '-prior', + ( + ''+( prior_result.classes[ name ] ) + + ' -> ' + + prior_result.vars[ name ] + ), + classes[ name ] + ); + } + + // if this class was a match, add it to the overview with its + // accumulator value + if ( classes[ name ] ) + { + addClassOverview( name, vars[ name ] ); + } + + c(); + } )(); + + document.getElementById( 'class-overview' ).className += ' show'; + } + + + function updateSummaryDebug( debug, parent, callback ) + { + var queue = []; + + // do nothing if debug data is not yet available + if ( !debug ) + { + return; + } + + // loop through each element on the DOM, *not* each debug id returned to + // us, since we want to clear any that may be missing + Array.prototype.slice.call( parent.querySelectorAll( '.debugid' ) ) + .forEach( function( element ) + { + queue.push( element.id ); + } ); + + var qlen = queue.length; + + dequeueSetsOf( 10, function( c ) + { + if ( queue.length === 0 ) + { + setWorkStatus(); + callback && callback(); + + return; + } + + setWorkStatus( + 'Processing breakdown values (' + + Math.floor( ( ( qlen - queue.length ) / qlen ) * 100 ) + + '%)...' + ); + + var id = queue.pop(), + did = id.replace( /^ubd-/, '' ); + + try + { + setPlaceholderValue( id, '', ( debug[ did ] ) + ? JSON.stringify( debug[ did ] ) + : '' + ); + } + catch ( e ) + { + console.error( + 'Debug (stringify debug ' + did + ' ): ' + + e.message + ); + } + + c(); + } )(); + } + + + var getPlaceholder = ( function() + { + var domcache = {}; + + function getPlaceholder( name, placeid ) + { + var classname = ( 'entry-value' + ( placeid || '' ) ); + + var current = domcache[ name + placeid ]; + if ( current ) + { + return current; + } + + // ignore system vars + if ( name.match( /^___/ ) ) + { + return null; + } + + var parent = document.getElementById( name ); + + if ( !parent ) + { + return null; + } + + var legend = parent.getElementsByTagName( 'legend' ), + dest = ( legend.length ) ? legend[ 0 ] : parent; + + var element = document.createElement( 'span' ); + element.className = classname; + dest.appendChild( element ); + + // rather than re-scanning the DOM each time + domcache[ name + placeid ] = element; + + return element; + } + + return getPlaceholder; + } )(); + + + function setPlaceholderValue( name, placeid, value, hasval ) + { + var p = getPlaceholder( name, placeid ); + if ( p === null ) + { + return; + } + + p.innerHTML = value; + + // do not handle prior flagging + if ( placeid === '-prior' ) + { + return; + } + + // get fieldset + var fs = p.parentNode.parentNode; + if ( fs.nodeName === 'FIELDSET' ) + { + fs.className = fs.className.replace( /\Bhasval\B/, '' ); + if ( ( hasval !== undefined && hasval ) + // progressively more time-consuming checks + || ( ( hasval === undefined ) + && value + && +value !== 0 + && value.replace( /[\[\],0]/g, '' ) + ) + ) + { + fs.className += ' hasval'; + } + } + } + + + function setLetListPlaceholders( name, value, prior ) + { + if ( name.match( /^___/ ) ) + { + return; + } + + // certainly room for improvement here (especially performance-wise), + // but this is a quick implementation + var elements = document.querySelectorAll( '.letlist-' + name ); + Array.prototype.slice.call( elements ).forEach( function( element ) + { + if ( !( element.id ) ) + { + // prefix with alpha so as not to cause a syntax error on query + element.id = 'll' + Math.floor( + ( new Date() ).getTime() * Math.random() + ); + } + + setPlaceholderValue( element.id, '', value ); + + // include prior values, if available + if ( prior ) + { + setPlaceholderValue( element.id, '-prior', prior ); + } + } ); + } + + + function rmclass( element, name ) + { + element.className = element.className.replace( + new RegExp( '\\b' + name + '\\b', 'g' ), + '' + ); + } + + + function hasParent( parent, element ) + { + var parentElement = element.parentElement; + + if ( parentElement === parent ) + { + return true; + } + + return ( parentElement ) + ? hasParent( parent, parentElement ) + : false; + } + + + // XXX: This is a mess. THIS IS WHAT TIME CONSTRAINTS DO TO CODE QUALITY! + // LET ME HACK IN PEACE! >:@ (What? Unconstrained development is a fantasy? + // Is unlimited time unreasonable? Phf. Maybe that Time Weaver frog person + // knows how to help with that. If you don't know that reference and you're + // in here hacking this code, then that implies that you are new; it then + // begs the question: why has it persisted for so long!!! Of course it has, + // though. That's how TODOs/XXXs work: they don't get fixed; they just turn + // text in your editor pretty [obnoxious] colors.) + function resetFields() + { + // XXX: gahhhhhh!!!!!!! + ignore_input = true; + + function rowquery( name ) + { + return document.querySelectorAll( + '#param-input-' + name + ' > .entry-row' + ); + } + + for ( var field in bucket ) + { + // may happen if we're loading data from another source + if ( bucket[ field ] === undefined ) + { + continue; + } + + var fdata = bucket[ field ], + elements = rowquery( field ), + + length = ( fdata.length > elements.length ) + ? fdata.length + : elements.length; + + if ( elements.length === 0 ) + { + continue; + } + + // not everything is an array of values + if ( Array.isArray( fdata ) ) + { + // add/clear fields on the form as necessary to accomdate bucket + // data + for ( var i = 0; i < length; i++ ) + { + // field exists in bucket but not on the form + if ( ( fdata[ i ] !== undefined ) && !( elements[ i ] ) ) + { + addRow( elements[ 0 ].parentNode ); + } + // field exists on form but not in the bucket + else if ( elements[ i ] && ( fdata[ i ] === undefined ) ) + { + // TODO: remove field instead + elements[ i ].querySelector( '[name]' ).value = ''; + } + + // if we have a matrix of values, we must also add columns + // for each + if ( Array.isArray( fdata[ i ] ) ) + { + var element = rowquery( field )[ i ], + cols = element.querySelectorAll( + '.entry-field' + ), + + len = ( fdata[ i ].length > cols.length ) + ? fdata[ i ].length + : cols.length; + + // check each column + for ( var j = 0; j < len; j++ ) + { + if ( ( fdata[ i ][ j ] !== undefined ) + && !( cols[ j ] ) + ) + { + // re-query in case we just added a row + addColumn( element.querySelector( + '.entry-add-matrix' + ) ); + } + else if ( cols[ j ] + && ( fdata[ i ][ j ] === undefined ) + ) + { + // TODO: remove field instead + cols[ i ].querySelector( '[name]' ).value = ''; + } + } + } + } + } + } + + form.reset(); + ignore_input = false; + } + + + function emptyBucket() + { + resetFields(); + + // prevent form updates from propagating to the bucket + ignore_input = true; + + for ( var field in bucket ) + { + var fdata = bucket[ field ]; + + // not everything is an array; if not, simply set the value and move + // on + if ( !( Array.isArray( fdata ) ) ) + { + var element = document.querySelector( + '[name="' + field + '"]' + ); + + if ( element ) + { + element.value = fdata; + } + + continue; + } + + var elements = document.querySelectorAll( + '[name="' + field + '[]"]' + ); + + var total = 0; + for ( var i = 0, l = fdata.length; i < l; i++ ) + { + if ( !( elements[ i ] ) ) + { + continue; + } + + // if a matrix, update each value + if ( Array.isArray( fdata[ i ] ) ) + { + for ( var j = 0, jl = fdata[ i ].length; j < jl; j++ ) + { + elements[ total++ ].value = fdata[ i ][ j ]; + } + } + else + { + // not a matrix + elements[ total++ ].value = fdata[ i ]; + } + } + } + + // re-allow input + ignore_input = false; + } + + + function getUserFromHostname( hostname ) + { + // strip off any domain, remove number from username and strip anything + // after a dash (e.g. gerwitm-ubuntu2.lovullo.local => gerwitm) + return hostname.split( '.' )[ 0 ].replace( /[0-9]+$/, '' ) + .split( '-' )[ 0 ]; + } + + + /** + * Prior module: load prior quotes (test cases) + * + * Not to be confused in speech with the Friar module, which would have your + * premiums divinely calculated and communicated through a deep meditation. + */ + var Prior = ( function ___loadprior( dom ) + { + var exports = {}, + + // current set of loaded test cases + curset = {}; + + var getLoadDialog = function() + { + // URL with fragment to automatically display this dialog + var url = document.location.href.replace( /#.*$/, '' ) + '#prior'; + + var dialog = dom.createElement( 'div' ); + dialog.id = 'prior'; + dialog.className = 'load-dialog'; + dialog.innerHTML = + "

    Load Prior Quotes

    " + + "

    " + + "Below is a list of all prior saved quotes; choose one " + + "to load it into the test area." + + "

    " + + "

    " + + "To load this dialog automatically on page load, you " + + "may use the following link: " + + url + "" + "

    "; + + // re-test button + var retest = dom.createElement( 'button' ); + retest.innerHTML = 'Regression Test'; + retest.addEventListener( 'click', function( e ) + { + e.preventDefault(); + e.target.disabled = 'disabled'; + + retestAll( function() + { + e.target.disabled = ''; + } ); + } ); + + // load quote number + var loadquote = dom.createElement( 'button' ); + loadquote.innerHTML = 'Load Quote #'; + loadquote.addEventListener( 'click', function( e ) + { + e.preventDefault(); + + var qid = prompt( 'Enter quote #:' ); + + if ( !qid ) + { + return; + } + + exports.hideLoad(); + + loadQuote( qid, qdata_host ); + } ); + + dialog.appendChild( retest ); + dialog.appendChild( loadquote ); + dialog.appendChild( getPriorTable() ); + + dom.body.appendChild( dialog ); + + // reassign the function to always return the instance + getLoadDialog = function() + { + return dialog; + }; + + return getLoadDialog(); + }; + + + var getPriorTable = function() + { + var table = dom.createElement( 'table' ), + headings = [ + "Date", "Description", "User", "Premium", "Expected" + ]; + + // add headings + for ( var head in headings ) + { + var th = dom.createElement( 'th' ); + th.innerHTML = headings[ head ]; + th.className = headings[ head ].toLowerCase(); + + table.appendChild( th ); + } + + // add count + var count = dom.createElement( 'caption' ); + count.innerHTML = + 'Total Count: 0'; + table.appendChild( count ); + + table.clear = function() + { + var rows = table.querySelectorAll( 'tr' ); + for ( var i = 0; i < rows.length; i++ ) + { + table.removeChild( rows[ i ] ); + } + }; + + table.addRow = function( looksgood, waiting /*, ... */ ) + { + var tr = dom.createElement( 'tr' ); + + // the first argument is the id + var id = arguments[ 0 ]; + tr.id = '_testcase_' + id; + + // the second argument will determine the row color (looksgood) + tr.className = + ( ( arguments[ 1 ] ) + ? 'good' + : 'bad' + ) + + ( ( arguments[ 2 ] ) + ? ' waiting' + : '' + ); + + // all other arguments will be cells + for ( var i = 3; i < arguments.length; i++ ) + { + var td = dom.createElement( 'td' ); + td.innerHTML = arguments[ i ]; + td.className = headings[ i - 3 ].toLowerCase(); + + // first cell will contain a hyperlink for auto-loading on + // visit + if ( i === 3 ) + { + var a = dom.createElement( 'a' ); + a.href = ( '#prior/' + id ); + a.innerHTML = td.innerHTML; + + td.innerHTML = ''; + td.appendChild( a ); + + a.addEventListener( 'click', function( e ) + { + doLoad( id ); + } ); + } + + tr.appendChild( td ); + } + + table.appendChild( tr ); + }; + + table.setCount = function( count ) + { + table.querySelector( '.count' ).innerHTML = +count; + }; + + table.mark = function( id, type ) + { + table.querySelector( '#_testcase_' + id ).className = type; + }; + + table.changePremium = function( id, premium ) + { + var element = table.querySelector( + '#_testcase_' + id + ' .premium' + ); + + // add the value and retain the previous value + element.innerHTML = '$' + premium + + '
    (was ' + element.innerHTML + + ')
    '; + }; + + table.changeComment = function( id, comment ) + { + var element = table.querySelector( + '#_testcase_' + id + ' .description' + ); + + element.innerHTML = comment.replace( /\n/g, '
    ' ); + }; + + function doLoad( id ) + { + exports.hideLoad(); + + // give them an indication that something is happening + setTimeout( function() + { + loadPriorTestCase( id ); + }, 0 ); + } + + // when a row is clicked, trigger the load + table.addEventListener( 'click', function( e ) + { + // we care only of row clicks + if ( e.target.nodeName.toLowerCase() !== 'td' ) + { + return; + } + + // get the unique id for this test case + var id = e.target.parentNode.id.replace( /^_testcase_/, '' ); + doLoad( id ); + } ); + + getPriorTable = function() + { + return table; + }; + + return getPriorTable(); + }; + + + function loadPrior() + { + // first, clear out any existing results + getPriorTable().clear(); + + // load prior data from server + var response = getXhrJsonSync( 'GET', prior_url ), + table = getPriorTable(), + results = response.results; + + // store the current set of test cases + curset = results; + + // add test test case to the table + for ( testcase in results ) + { + var result = results[ testcase ]; + + table.addRow( + result.id, + result.looksgood, + result.waiting, + result.date, + + // comment + ( result.comment.replace( /\n/g, '
    ' ) + || '(no comment)' + ), + + // username (from hostname) + getUserFromHostname( result.hostname ), + + // premium + ( '$' + ( result.premium || 0.00 ) ), + + // expected premium + ( ( result.expected ) + ? '$' + result.expected + : ( result.looksgood ) + ? '$' + result.premium + : '-' + ) + ); + } + + table.setCount( results.length ); + } + + + function getTestCaseData( id ) + { + return getXhrJsonSync( 'GET', prior_url + '&id=' + id ); + } + + + function getQuoteData( id, qdata_host ) + { + try + { + return getXhrJsonSync( + 'GET', prior_url + '&host=' + qdata_host + '&qid=' + id + ); + } + catch ( e ) + { + return { error: 'Invalid response from server.' }; + } + } + + + function showRatingResultPage() + { + dom.location.hash = 'test-data'; + } + + + function loadQuote( qid, host, bucket_override ) + { + var data = getQuoteData( qid, host ); + if ( data.error !== 'OK' ) + { + alert( data.error ); + return; + } + + rater.fromMap( data.results.bucket, function( data ) + { + bucket = data; + emptyBucket(); + + if ( bucket_override ) + { + overrideBucket( bucket_override ); + } + + showRatingResultPage(); + rate( bucket ); + } ); + } + + + function loadPriorTestCase( id ) + { + var casedata = getTestCaseData( id ); + + if ( casedata.status !== 200 ) + { + alert( 'Could not load test case.\n\n' + casedata.error ); + } + + var data = casedata.results; + + // display the message so that they know what they're looking at + exports.setPriorMessage( + data.hostname, data.comment, data.looksgood, id + ); + + // overwrite the bucket + bucket = data.bucket; + emptyBucket(); + + // set this test case so that our next save overwrites it + setTestCase( id, data.result ); + + // make it obvious to the user that the data has been loaded + clearSummaryPremium(); + showEntryForm(); + + // prefill the comment and expected data on the submission form, + // leaving room at the top for additional comments + document.getElementById( 'final-comments' ) + .innerHTML = ( + "\n\n\n" + + getPrevSubmitCommentText( + data.hostname, + data.comment + ) + ); + document.getElementById( 'final-expected' ).value = data.expected; + + // let the browser catch up and then perform rating + setTimeout( function() + { + // switch to test data and rate + document.location.hash = '#test-data'; + rate( bucket ); + }, 0 ); + } + + + function getPrevSubmitCommentText( hostname, comment ) + { + return "Previously submitted by " + + getUserFromHostname( hostname ) + ": " + comment; + } + + + function retestAll( callback ) + { + var queue = [], + skipped = 0, + + // regression test results, which may or may not be submitted to + // the server + history = {}; + + // queue each of the test cases + for ( var testcase in curset ) + { + queue.push( curset[ testcase ] ); + } + + var count = failures = changed = 0, + start = ( new Date() ).getTime(); + + var run = function() + { + // do not pop(); we want to do them in order so it doesn't look + // too odd to the user + var test = queue.shift(); + + // all done + if ( !( test ) ) + { + var time = ( new Date() ).getTime() - start; + + var msg = ( + 'Test complete. Re-ran ' + count + ' test(s) with ' + + failures + ' failure(s) in ' + ( time / 1000 ) + 's.' + + "\n\n" + + + ( ( skipped ) + ? skipped + " test(s) premium checks " + + "were skipped because they " + + "have no expected premium; please aid in the " + + "automated testing of these by selecting " + + "them and entering an expected premium when " + + "re-submitting it (by clicking Incorrect). " + + "These skipped tests are still noted if " + + "their premiums changed (in italics), but " + + "their success statuses are left untouched." + : '' + ) + + + ( ( failures === 0 ) + ? ( !skipped ) + ? "\n\nYou should feel pretty sweet right now." + : '' + : "\n\nSomeone's got some splainin' to do." + ) + + + ( ( !changed ) ? "\n\nNo test cases have changed." : + "\n\n" + changed + " case(s) changed." + + "\n\nWould you like the results of this regression " + + "to be recorded? This will cause the status of each " + + "test case to be updated as shown. If unsure, click " + + "'Cancel'." + ) + ); + + // if we have changes, show a box asking if the changes + // should be uploaded to the server; otheriwse, just alert + // (which will return undefined and cast to false) + var submit = !!( changed && confirm || alert ) + .call( window, msg ); + + if ( submit ) + { + saveRegression( history ); + } + + callback && callback( count, failures, time ); + + return; + } + + var table = getPriorTable(); + table.mark( test.id, 'testing' ); + + setTimeout( function() + { + var testdata = getTestCaseData( test.id ).results; + + try + { + // rate, but do not update the screen + rate( testdata.bucket, false, true ); + } + catch ( e ) + { + console.log( e ); + table.mark( test.id, 'skip' ); + + // abort! abort! + //alert( 'An error occurred. Aborting.' ); + run(); + return; + } + + // determine what premium we're expecting (default to + // existing premium) + var expected = testdata.expected || testdata.result.premium, + skipme = !( testdata.looksgood || testdata.expected ); + + var correct = ( + rate_result.premium + && ( rate_result.premium == expected ) + ); + + // add to changed count if the status changed + var has_changed = ( testdata.looksgood !== correct ); + changed += ( +has_changed && !skipme ); + + skipped += +skipme; + + // only add to the total count if the premium was actually + // compared + if ( !skipme ) + { + count++; + + if ( !( correct ) ) + { + failures++; + } + + // store in case the user decides to save to the server + if ( has_changed ) + { + history[ test.id ] = { + looksgood: correct, + bucket: testdata.bucket, + result: rate_result, + expected: expected, + comment: testdata.comment, + hostname: testdata.hostname, + previous: testdata.result, + }; + + // show the comment that would be saved to the + // server, should they choose to do so + table.changeComment( + test.id, + genRegressionComment( history[ test.id ] ) + ); + } + } + + // update table + table.changePremium( test.id, rate_result.premium ); + table.mark( + test.id, + ( + ( ( correct ) + ? 'good' + : 'bad' + ) + + ( ( has_changed ) + ? ' changed' + : '' + ) + + ( ( rate_result.premium !== testdata.result.premium ) + ? ' premchanged' + : '' + ) + + ( ( skipme ) + ? ' skipped' + : '' + ) + ) + ); + + // continue + run(); + }, 0 ); + } + + // run 'em one by one + setTimeout( run, 0 ); + } + + + function genRegressionComment( item ) + { + return "[Regression Test: " + + ( ( item.looksgood ) ? "Pass" : "Fail" ) + + "] Expected $" + item.expected + "; calculated $" + + item.result.premium + "; previously $" + + item.previous.premium + "\n\n" + + getPrevSubmitCommentText( item.hostname, item.comment ); + } + + + function saveRegression( history ) + { + for ( var id in history ) + { + var item = history[ id ]; + + // generate comment + var comment = genRegressionComment( item ); + + submitQuote( + item.bucket, + item.result, + comment, + item.looksgood, + ( item.waiting || false ), + item.expected, + id, + function() {} + ); + } + } + + + exports.initHtml = function() + { + getLoadDialog(); + } + + + exports.showLoad = function() + { + removeEntryFocus(); + + getLoadDialog().className += ' show'; + loadPrior(); + } + + + exports.hideLoad = function() + { + var dialog = getLoadDialog(); + dialog.className = dialog.className.replace( /\bshow\b/g, '' ); + } + + + exports.setPriorMessage = function( host, message, good, id ) + { + var container = document.getElementById( 'prior-message' ); + + if ( !container ) + { + return; + } + + container.style.display = ( message ) ? 'inline-block' : 'none'; + container.className = ( good ) ? 'good' : 'bad'; + container.innerHTML = ( + '' + getUserFromHostname( host ) + ': ' + + message + .replace( /^\n+|\n+$/g, '' ) + .replace( / /g, '  ' ) + .replace( /\t/g, '    ' ) + .replace( /\n/g, '
    ' ) + .replace( + /(Previously submitted by [^:]+:)/g, + '$1' + ) + + '

    [Direct Link]' + ); + }; + + exports.loadQuote = loadQuote; + exports.loadPriorTestCase = loadPriorTestCase; + + return exports; + } )( document ); + + + function begin() + { + // initialize prior div + Prior.initHtml(); + + // allow linking to test cases + var pmatch; + if ( pmatch = document.location.href.match( /#prior(?:\/(.*))?$/ ) ) + { + var id = pmatch[ 1 ]; + + if ( !( id ) ) + { + // no id given; let them choose + Prior.showLoad(); + } + else + { + // we were given an id; load it! + console.log( 'Loading ' + id + '...' ); + Prior.loadPriorTestCase( id ); + } + } + + // allow settings params from the URL (very basic parsing; barely used); we + // use a colon rather than ? because ? is not included in the location + // object + var pdata; + var bucket_override = []; + if ( pdata = document.location.hash.match( /:(.*)$/ ) ) + { + try + { + // params delimited by & + var params = pdata[1].split( '&' ); + for ( var param in params ) + { + // values delimited from the name by = + var valdata = params[ param ].split( '=' ), + val = JSON.parse( valdata[ 1 ] ); + + bucket_override[ valdata[ 0 ] ] = val; + bucket[ valdata[ 0 ] ] = val; + + console.log( 'Bucket override: ' + valdata[ 0 ] + '=' + val ); + } + + overrideBucket( bucket_override ); + } + catch ( e ) + { + alert( 'Failed setting param values from URL.\n\n' + e.message ); + } + } + + // allow loading of quote ids + var mdata; + if ( mdata = document.location.hash.match( /#load\/([a-z]+)\/([0-9]+)/ ) ) + { + var host = mdata[1], + id = mdata[2]; + + // load the quote + Prior.loadQuote( id, host, bucket_override ); + } + } + + + var vpt = [ 0, 0, 0 ], + vpt_cur = 0; + function voiPainterAdd( tr, value ) + { + var c = 'sel' + vpt_cur; + tr.classList.toggle( c ); + + vpt[ vpt_cur ] += ( value * ( tr.classList.contains( c ) ? 1 : -1 ) ); + vpt[ vpt_cur ] = +( vpt[ vpt_cur ].toFixed( 6 ) ); + + showVoiPainter( vpt[ vpt_cur ] ); + } + + + var vp_element = null, + vpt_dest = []; + function showVoiPainter( val ) + { + if ( !vp_element ) + { + vp_element = document.createElement( 'div' ); + vp_element.id = 'voi-painter'; + + for ( var i in vpt ) + { + vpt_dest[ i ] = document.createElement( 'div' ); + vpt_dest[ i ].classList.add( 'sel' + i ); + vpt_dest[ i ].innerHTML = '0'; + vp_element.appendChild( vpt_dest[ i ] ); + + ( function( i ) + { + vpt_dest[ i ].addEventListener( 'click', function() + { + vpt_cur = i; + } ); + } )( i ); + } + + document.getElementById( 'test-data' ).appendChild( vp_element ); + } + + vpt_dest[ vpt_cur ] .innerHTML = val; + } + + + return { + updateSummaryDebug: updateSummaryDebug, + + onRate: function( callback ) + { + rate_callback = callback; + }, + + begin: begin, + Prior: Prior, + }; +} )(); diff --git a/src/current/src/.gitignore b/src/current/src/.gitignore new file mode 100644 index 00000000..fd9d5a65 --- /dev/null +++ b/src/current/src/.gitignore @@ -0,0 +1,6 @@ +# may be copied into the cwd for testing, since it is a dep +saxon8.jar + +*.class +*.jar +*.manifest diff --git a/src/current/src/Makefile b/src/current/src/Makefile new file mode 100644 index 00000000..2b9d08e6 --- /dev/null +++ b/src/current/src/Makefile @@ -0,0 +1,18 @@ + +dslc_src := $(wildcard com/lovullo/dslc/*.java) +dslc_bin := $(dslc_src:.java=.class) + +.PHONY: dslc clean + +dslc: dslc.jar + +%.class: %.java + javac $< + +# we explicitly specify a glob on the path because inner classes are compiled +# into their own files +dslc.jar: $(dslc_bin) + jar cfm $@ dslc.manifest com/lovullo/dslc/*.class + +clean: + rm -f $(dslc_bin) dslc.jar diff --git a/src/current/src/com/lovullo/dslc/DslCompiler.java b/src/current/src/com/lovullo/dslc/DslCompiler.java new file mode 100644 index 00000000..8747b566 --- /dev/null +++ b/src/current/src/com/lovullo/dslc/DslCompiler.java @@ -0,0 +1,303 @@ + +package com.lovullo.dslc; + +import java.io.*; +import java.util.Map; +import java.util.HashMap; +import javax.xml.XMLConstants; +import javax.xml.transform.stream.StreamSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.*; +import javax.xml.validation.*; +import javax.xml.transform.sax.SAXTransformerFactory; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +public class DslCompiler +{ + private static class _DslCompiler + { + private Validator _xsd; + private HashMap _xsl; + + + public _DslCompiler() + { + _xsd = _createXsd(); + _xsl = new HashMap(); + } + + + public void compile( + Source doc, + String cmd, + String src, + String dest, + HashMap params + ) throws Exception + { + if ( cmd.equals( "validate" ) ) + { + _xsd.validate( doc ); + return; + } + else if ( cmd.equals( "rm" ) ) + { + // remove file (purposely uncaught) + ( new File( src ) ).delete(); + + return; + } + + if ( dest.equals( "" ) ) + { + System.err.printf( + "fatal: no destination path provided\n" + ); + + System.exit( 4 ); + } + + // transform to dest + File destfile = new File( dest ); + try + { + _transform( + src, + doc, + cmd, + new StreamResult( new File( dest ) ), + params + ); + } + catch ( Exception e ) + { + // delete the output file; it's garbage + destfile.delete(); + + // be verbose and unprofessional. + throw e; + } + } + + + private void _transform( + String src, + Source doc, + String cmd, + StreamResult dest, + HashMap params + ) throws Exception + { + // load the stylesheet if it has not been already (we load lazily in + // case the stylesheet is never needed) + if ( !( _xsl.containsKey( cmd ) ) ) + { + _xsl.put( cmd, _createXslt( cmd ) ); + } + + // since XSL's abstraction does not provide a means to retrieve the + // document path (nor does it make sense to), we will pass it in + // ourselves, stripped of the file extension + String srcpkg = src.substring( 0, src.lastIndexOf( '.' ) ); + + // similarily, quickly resolve the relative root path + Integer dircount = srcpkg.replaceAll( "[^/]", "" ).length(); + String relroot = new String( new char[ dircount ] ).replace( "\0", "../" ); + + Transformer t = _xsl.get( cmd ); + t.setParameter( "__srcpkg", srcpkg ); + t.setParameter( "__relroot", relroot ); + t.setParameter( "__rseed", (int)( Math.random() * 10e6 ) ); + + _setTemplateParams( t, params ); + + t.transform( doc, dest ); + } + + + private void _setTemplateParams( + Transformer t, + HashMap params + ) throws Exception + { + for ( Map.Entry param : params.entrySet() ) + { + t.setParameter( param.getKey(), param.getValue() ); + } + } + + + private Validator _createXsd() + { + final SchemaFactory factory = SchemaFactory.newInstance( + XMLConstants.W3C_XML_SCHEMA_NS_URI + ); + + // we must disable Unique Particle Attribution (UPC) checking; the + // validator used during development did not check for this and it + // currently does not pass this test (note that disabling this also + // improves the speed of the validator) + try + { + factory.setFeature( + "http://apache.org/xml/features/validation/schema-full-checking", + false + ); + } + catch ( Exception e ) + { + System.err.println( + "fatal: cannot disable UPA checking; " + + e.getMessage() + ); + + System.exit( 1 ); + } + + try + { + final Schema schema = + factory.newSchema( new File( "rater/rater.xsd" ) ); + + return schema.newValidator(); + } + catch ( SAXException e ) + { + System.err.printf( + "fatal: %s\n", + e.getMessage() + ); + + System.exit( 1 ); + } + + return null; + } + + + private Transformer _createXslt( String src ) + { + try + { + final TransformerFactory factory = TransformerFactory.newInstance( + "net.sf.saxon.TransformerFactoryImpl", null + ); + + final Source xsl = new StreamSource( "rater/" + src + ".xsl" ); + + return factory.newTransformer( xsl ); + } + catch ( Exception e ) + { + System.err.printf( + "fatal: compilation failed; %s\n", + e.getMessage() + ); + + System.exit( 2 ); + } + + return null; + } + } + + + + public static void main( String[] args ) throws Exception + { + BufferedReader stdin = new BufferedReader( + new InputStreamReader( System.in ) + ); + + String src = ( args.length > 0 ) ? args[0] : ""; + + _DslCompiler dslc = new _DslCompiler(); + + try + { + if ( src != "" ) + { + compileSrc( dslc, src ); + } + else + { + while ( ( src = stdin.readLine() ) != null ) + { + compileSrc( dslc, src ); + } + } + } + catch ( IOException e ) + { + System.err.println( + "fatal: I/O error while reading input files: " + + e.getMessage() + ); + + System.exit( 1 ); + } + catch ( Exception e ) + { + System.err.printf( + "fatal: `%s': %s\n", + src, + e.getMessage() + ); + + // generic exception..ruh roh + throw e; + } + } + + + private static void compileSrc( _DslCompiler dslc, String cmdline ) throws Exception + { + System.err.println( cmdline ); + String[] args = cmdline.split( " " ); + String dest = ""; + + if ( args.length < 2 ) + { + System.err.printf( "fatal: invalid command: %s\n", cmdline ); + System.exit( 3 ); + } + else if ( args.length >= 3 ) + { + dest = args[2]; + } + + String cmd = args[0]; + String src = args[1]; + + HashMap params = _getXslParams( args ); + + Source doc = new StreamSource( src ); + dslc.compile( doc, cmd, src, dest, params ); + } + + + private static HashMap _getXslParams( String[] args ) + throws Exception + { + HashMap params = new HashMap(); + + for ( int i = 3; i < args.length; i++ ) + { + String[] keyval = args[ i ].split( "=" ); + + if ( keyval.length < 2 ) + { + throw new Exception( + "Invalid template param assignment: " + + args[ i ] + ); + } + + params.put( keyval[ 0 ], keyval[ 1 ] ); + } + + return params; + } +} diff --git a/src/current/standalone.xsl b/src/current/standalone.xsl new file mode 100644 index 00000000..8ce7f36d --- /dev/null +++ b/src/current/standalone.xsl @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + var rater = + + ; + + + + + + + rater.fromMap = + + + + + + + + + function(d,c){c(d);} + + + ; + + + rater._retmap = + + + + + + + + + function(d,c){c(d);} + + + ; + + + module.exports = function( args_base ) { + var ret; rater.fromMap( args_base, function( args ) { + + var rater_result = rater( args ); + + // perf counter + var start = ( new Date() ).getTime(); + + rater._retmap( rater_result.vars, function( result ) + { + // add the final premium + result.premium = rater_result.premium; + result.__classes = rater_result.classes; + + // process the rating worksheet + try + { + result.__worksheet = process_worksheet( + rater.worksheet, + rater_result.vars, + rater_result.consts, + rater_result.debug, + rater_result.premium + ); + } + catch ( e ) + { + result.__worksheet = [ 'Failed: ' + e.message ]; + } + ret = result; + } ); + + // add performance data + var end = ( new Date() ).getTime(), + time = ( ( new Date() ).getTime() - start ); + + ret.__perf = { + time: { + start: start, + end: end, + total: time + } + }; + + } ); + + return ret; + }; + + + function process_worksheet( worksheet, vars, consts, debug, premium ) + { + var ret = {}; + + for ( var name in worksheet ) + { + var data = Array.prototype.slice.call( worksheet[ name ] ), + disp = data[0], + calc = data[1], + always = data[2]; + + ret[ name ] = [ + disp, + process_wdisplay_set( [calc], vars, consts, debug ), + + ( ( name === 'yield' ) + ? premium + : ( vars[ name ] || consts[ name ] ) + ), + + ( always === 'true' ) + ]; + } + + return ret; + } + + function process_wdisplay( data, vars, consts, debug ) + { + if ( data === null ) + { + return null; + } + + var name = data[ 0 ], + desc = data[ 1 ], + sub = data[ 2 ], + val = data[ 3 ]; // may not exist + + return [ + name, + desc, + process_wdisplay_set( sub, vars, consts, debug ), + val || process_wval( name, desc, vars, consts, debug ) + ]; + } + + + function process_wval( type, desc, vars, consts, debug ) + { + if ( desc.runtime ) + { + type = 'runtime'; + } + + switch ( type ) + { + case 'apply': + case 'cases': + case 'case': + case 'otherwise': + case 'runtime': + return ( debug[ desc._id ] ); + + case 'value-of': + return ( vars[ desc.name ] || consts[ desc.name ] ); + + default: + return ''; + } + } + + + function process_wdisplay_set( sub, vars, consts, debug ) + { + var ret = [], + i = sub.length; + + while ( i-- ) + { + if ( sub[ i ] === undefined ) + { + continue; + } + + ret[ i ] = process_wdisplay( sub[ i ], vars, consts, debug ); + } + + return ret; + } + + + + module.exports.rater = rater; + + + diff --git a/src/current/summary.css b/src/current/summary.css new file mode 100644 index 00000000..cc878f2b --- /dev/null +++ b/src/current/summary.css @@ -0,0 +1,835 @@ +/** + * Rater XML summary stylesheet + */ + +body { + /* menu width * menu em + 1 */ + margin: 0em 0em 0em 13em; +} + +.menu +{ + position: fixed; + overflow: scroll; + + background-color: #ad7fa8; + border-right: 1px solid black; + + top: 0px; + left: 0px; + bottom: 0px; + width: 15em; + + padding: 0.25em; + + font-size: 0.8em; + + resize: horizontal; + z-index: 10; +} + +.menu h1 +{ + font-size: 1.4em; + margin-bottom: 0.15em; + border-bottom: 1px solid #75507b; +} +.menu h1:not(:first-child) +{ + margin-top: 2em; +} + +.menu h2 +{ + font-size: 1.2em; + margin-left: 0.5em; + margin-bottom: 0.15em; +} + +.menu ul +{ + margin: 0px; + padding-left: 1.25em; + list-style: none; +} + +fieldset, +.container-param, +.tcontent +{ + display: none; +} +fieldset:target, +.container-param:target, +.tcontent:target +{ + display: block; +} + +fieldset fieldset +{ + display: block; +} + + +#xml-raw:not(.show) +{ + display: none; +} + +table > caption +{ + font-weight: bold; +} + +dt +{ + font-size: 1.1em; + font-weight: bold; + + margin-top: 0.5em; +} + +dt.param.classifies { + color: green; +} +dt.param > .type +{ + font-size: 0.8em; + font-weight: normal; +} + +dl.params > .default +{ + font-size: 0.8em; +} + +table +{ + border: 1px solid #888a87; + margin: 1em 0px 0px 0px; +} +table th +{ + border-bottom: 2px solid #888a87; + padding: 0.5em; +} +table tr > td +{ + padding: 0.5em; +} +table tr:not(:last-child) > td +{ + border-bottom: 1px solid #888a87; +} + +fieldset +{ + border: 0px; + margin: 0px; +} + +.class .requires, +.class .name, +.class .usedby, +.typedef .type, +.typedef .name, +.params .usedby, +.rate .yields, +.rate .param, +.func .param, +.func .usedby +{ + font-size: 0.8em; +} + +.usedby a +{ + text-decoration: none; +} + +.calc-order, +.classifier-calcs +{ + max-height: 20em; + overflow-y: scroll; +} + +#workstatus +{ + position: fixed; + display: none; + + background-color: #eeeeec; + + left: 0px; + top: 0px; + right: auto; + padding: 0.25em; + + font-size: 0.9em; + border-bottom: 1px solid #babdb6; + border-right: 1px solid #babdb6; + + /* entry-form is 2000 */ + z-index: 1999; +} + +#workstatus.show +{ + display: block; +} + +.package +{ + background-color: #eeeeec; + + border: 1px solid #babdb6; + border-radius: 1em; + + padding: 1em; + + margin-bottom: 3em; + + clear: both; +} +.package.devsummary +{ + background-color: #ad7fa8; + border-color: #75507b; +} + +.package > .title +{ + position: relative; + + background-color: #d3d7cf; + + border-bottom: 1px solid #babdb6; + border-radius: 1em 1em 0px 0px; + + margin: -1em -1em 0px -1em; + padding: 1em; +} +.package > .title > h2 +{ + margin: 0; + padding: 0; +} + +.package > h3, +.package > div > h3 +{ + border-width: 0px 0px 2px 0px; + border-style: solid; + border-color: #babdb6; + + margin: 1em -0.9em; + padding: 0.1em 0.5em; +} + +.package.us > .title, +.package.devsummary > .title +{ + background-color: #ad7fa8; +} +.package.devsummary > .title, +.package.devsummary > h3, +.package.devsummary > div > h3 +{ + border-bottom-color: #75507b; +} + +.package h4.rate-group +{ + border-bottom: 1px dashed #babdb6; + margin-top: 3em; + margin-left: -0.5em; +} +.rate-groups .generates +{ + font-size: 0.9em; +} + +.package > .title > .imports +{ + position: absolute; + top: 0px; + right: 0px; + + margin: 1.25em; +} +.package > .title > .imports::before +{ + content: 'Imports: '; + font-weight: bold; +} + +body > fieldset +{ + position: relative; + padding: 5em 0em 0em 0em; +} + +body > fieldset > legend +{ + position: absolute; + background-color: #eeeeec; + + border-top: 1px solid #babdb6; + border-bottom: 1px solid #babdb6; + + padding: 0.5em; + left: -0.5em; + top: 0em; + right: 0px; + + font-size: 1.5em; + letter-spacing: 0.1em; +} + +body > fieldset > legend > a.pkg +{ + float: right; + font-size: 0.5em; + line-height: 2.5em; + + color: inherit; + border: none; + text-decoration: none; +} + +body > fieldset > legend + p.desc +{ + margin-top: 0em; + font-size: 1.1em; +} + +fieldset.rate > legend > a +{ + text-decoration: none; + border-bottom: 1px dotted black; +} + +fieldset.rate .classes +{ + display: inline-block; + + margin: -1em 0em 2em 0em; + padding-bottom: 0.25em; + + font-size: 0.9em; + border-bottom: 1px dotted black; +} + +fieldset.rate .classes > .prefix +{ + font-variant: small-caps; +} + +/* more than just .rate */ +fieldset .calc-yields +{ + font-variant: small-caps; +} + + +ul.let +{ + list-style: none; + margin: 0; + padding: 0; +} + +ul.let li.letequ +{ + margin-top: 1em; +} + +ul.let .letdesc +{ + font-size: 0.9em; + margin-left: 1em; +} + + +.rate .body, +.func .body, +.yield .body +{ + float: left; +} +.rate .right, +.func .right, +.yield .right +{ + float: right; + padding: 0; + margin: 0; + + max-width: 40%; +} +.rate .body +{ + /** give room for accumulators, depends, etc **/ + margin-bottom: 5em; +} +.right h4 +{ + border-bottom: 1px solid black; + + + margin-top: 0; + margin-bottom: 0.5em; +} +.right > div:not(:first-child) +{ + margin-top: 1em; +} +.right > .parts.many +{ + -webkit-columns: 2; + -moz-columns: 2; +} +.right > .parts > .part, +.right > .generators > .generator +{ + text-align: center; + margin-top: 2em; +} +.right > .parts > .part:first-child +{ + margin-top: 0em; +} +.right > .parts.many > .part +{ + /** FF, Webkit and W3C respectively */ + display: table; + -webkit-column-break-inside: avoid; + break-inside: avoid-column; +} +.right > .parts > .part > .label, +.right > .generators > .generator > .desc +{ + font-size: 0.9em; +} +.accum +{ + position: absolute; + bottom: 1em; + + font-size: 0.9em; + + max-width: 60%; +} + +.error +{ + font-weight: bold; + color: red; +} + + +/** entry form **/ +#test-data +{ + position: relative; +} +#test-data:not(:target) +{ + display: none; +} + +form.entry-form +{ +} + +form.entry-form.focus +} + +form.entry-form > dl +} + +form.entry-form.focus > dl +{ +} + +form.entry-form dt +{ + clear: left; +} + +form.entry-form .matrix +{ + display: inline-block; + border: 1px inset; + padding: 0.25em; + + float: left; + clear: left; +} + +form.entry-form .entry-add +{ + float: left; + clear: left; +} + +form.entry-form > .foot +{ +} + +form.entry-form > .foot > .ratemsg +{ + display: inline-block; + + font-weight: bold; + font-size: 1.2em; +} + +form.entry-form .final-accept:not(.show), +form.entry-form .final-premium:not(.show) +{ + display: none; +} + +form.entry-form .final-premium +{ + margin: 0.25em; + + font-size: 3em; + font-weight: bold; + color: green; + + text-shadow: 1px 1px 1px black; +} + + +form.entry-form .final-premium:before +{ + content: '$'; + + min-height: 0em; + + white-space: nowrap; +} + + +form.entry-form input[type="reset"] +{ + /* help protect against accidental clicks */ + margin-left: 1em; +} + +form .final-comments +{ + background-color: rgba( 255, 255, 255, 0.90 ); + + display: none; + + text-align: left; + + padding: 1em; +} +form .final-comments.show +{ + position: fixed; + display: block; + + border: 0.25em solid black; + + top: 0.25em; + right: 0.25em; + bottom: 0.25em; + left: 12.7em; +} + +form .final-comments textarea +{ + width: 95%; + height: 20em; +} + +form .final-comments button +{ + padding: 0.5em 1em; + margin-right: 1em; +} + +form .final-comments #final-submit +{ + font-weight: bold; +} + + +/** load dialog **/ +#prior:not(:target) +{ + display: none; +} + +.load-dialog td +{ + cursor: pointer; +} + +.load-dialog > button +{ + margin-top: 0.5em; + padding: 0.5em 1em; + font-size: 1.1em; +} + +.load-dialog tr > td:first-child, +.load-dialog tr > td.premium +{ + white-space: nowrap; +} + +.load-dialog tr > td.premium, +.load-dialog tr > td.expected +{ + text-align: right; +} + +.load-dialog tr.good +{ + background-color: #c0ffc0; +} +.load-dialog tr.bad +{ + background-color: #ffc0c0; +} +.load-dialog tr.good.waiting +{ + background-color: #edd400; +} +.load-dialog tr.bad.waiting +{ + background-color: #f57900; +} +.load-dialog tr.changed:not(.skipped) +{ + font-weight: bold; + font-style: normal !important; +} +.load-dialog tr.premchanged +{ + font-style: italic; +} +.load-dialog tr.skipped +{ + background-color: gray; +} + + +.load-dialog.show +{ + display: block; +} + + + +.entry-value, +.entry-value-prior +{ + background-color: yellow; + + padding: 0.1em; + margin-left: 1em; + + font-weight: bold; + color: green; +} +.entry-value-prior +{ + background-color: purple; + + font-weight: normal; + font-size: 0.9em; + color: white; +} +body:not(.prior) .entry-value-prior +{ + display: none; +} + + +/** validation errors **/ +.validation-errors +{ + position: fixed; + background-color: #FFAFAF; + + border: 0.5em solid rgba( 255, 0, 0, 0.75 ); + border-bottom: none; + + bottom: -30.5em; + left: 0px; + right: 0px; + + padding: 0px 0px 0px 0.5em; + + z-index: 9000; +} + +.validation-errors:hover +{ + background-color: white; + + bottom: 0px; +} + +.validation-errors ol +{ + height: 30em; + + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; + + overflow-y: scroll; +} + +.validation-errors li > .content +{ + font-weight: normal; +} + +.nb +{ + border-top: 1px solid #babdb6; + padding-top: 1em; +} + + + +.ultra-breakdown +{ + display: block; + + font-size: 0.9em; + clear: both; +} + +.ultra-breakdown > h2 +{ + margin-top: 3em; +} + +.ultra-breakdown + .yields +{ + margin-top: 2em; +} + +.ultra-breakdown legend > .uid +{ + font-size: 0.8em; +} + +.ultra-breakdown fieldset +{ + margin-top: 1em; + + border: 1px solid #babdb6; + border-radius: 0.5em; +} + +.ultra-breakdown fieldset:hover +{ + border-color: black; +} + + +.test-summary +{ + float: right; +} +.test-summary table +{ + float: right; + clear: both; +} + +#voi-container, +#class-overview +{ + display: none; + margin: 0em 0.5em 2em 0em; +} +#class-overview td.prior +{ + font-size: 0.9em; + color: purple; +} +body:not(.prior) #class-overview td.prior +{ + display: none; +} + +#voi-container.show, +#class-overview.show +{ + display: inline; +} + +#voi-container td.prior +{ + font-size: 0.9em; + color: purple; +} +body:not(.prior) #voi-container td.prior +{ + display: none; +} + +.sel0 +{ + background-color: #ccccff; +} +.sel1 +{ + background-color: #ccffcc; +} +.sel2 +{ + background-color: #ffcccc; +} + +#voi-painter +{ + position: fixed; + display: block; + + background-color: white; + border: 3px solid #eeeeec; + border-radius: 0.25em; + + top: -3px; + left: 30em; + + font-weight: bold; + font-size: 1.3em; + + padding: 0.25em; +} + +#prior-message +{ + background-color: #c0ffc0; + display: none; + + border: 0.25em solid #4e9a06; + width: 50%; + + font-family: monospace; + + padding: 0.5em; +} + +#prior-message.bad +{ + background-color: #ffc0c0; + border-color: #c00000; +} diff --git a/src/current/summary.xsl b/src/current/summary.xsl new file mode 100644 index 00000000..a59510cb --- /dev/null +++ b/src/current/summary.xsl @@ -0,0 +1,2107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [summary] processing + + + + ... (please be patient) + + + + + + + + + + + + + + + + + + + + + + + <!DOCTYPE html> + + + + + + + + + + + + + + rater/ + + + + + + + <xsl:value-of select="$title" /> + + + + + + [summary] typsetting self... + + + + + + + + + [summary] typesetting package + + ... + + + + + + + + + + + + +
    + +
    + + + + + + + + +
    Values of Interest
    NameValue
    + + + + + + +
    Classification Overview
    +
    + + + + +
    + + + + + + + + +
    + + + + + + + [summary] building package list... + + + + + + + + + + + + + + + + + + + +

    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    Rate Blocks

    +
      + + + + + + + + !!! failed to locate + + source document + + + + + +
    • + +
    • +
      + + + + + + +
    • + + + +
    • +
      +
      +
    +
    +
    + + + + + + + + + + + + +
  • + + + + ( + + ) + + + : + + + +
  • +
    + + +
  • + Preprocessor error + + + ( + + ) + + + : + + + +
  • +
    + + + + + + + + [summary] [] + + + + pkg- + + + +

    + +

    + + +
    + + + + + + + + + + + + + [summary] + + for + + + + + + + + + + + + + + + + + / + + + + + + + + + param + + + + classifies + + + + + + processing + + + + + + + + +
    + + + + + + + + + + + + + \( + + \) + + + + + + + + + + + + + + \(\in + + + + \) + + + ( + + + # + + + + + + + + + + + + ) + + + + + + + +

    + +

    + + + +
    + Default: + + + + { + + + + + + + + + + \(\epsilon\) + + + + + } + +
    +
    + + + + + + +
    + Value: +
    +
    + + + + + Too many values; not typesetting. + + + + + +
    + Values: + \(\left[\begin{array}\\ + + + + \\ + + + + + + \end{array}\right]\) +
    +
    + + +
    + Values: + \( \left[ \begin{array}\\ + + + \\ + + + + + & + + + + + + \end{array} \right] \) +
    +
    +
    +
    + + + +

    Defined by type + + + +

    +
    +
    +
    + + + + + + + + + + + + + + + + processing rate group " + + " + + + + + + + + + + + + + + + + + + + + + + + (final premium) + + + + + + + + + + + + + processing typedefs + + + + +
    + + + + + + + + + + ( + + ) + + + + + + + +
    + Type: + + + + + + + + + ( + + ) + +
    + + +
    + + + +
    + + + + +
    + + + + + + + + + + ( + + ) + + + + + + +

    Union of:

    + + +
    + + + + + +
    + + + + + + + + + + + + + + + + + + + + +
    NameValueDescription
    + + + +
    +
    + + + + +

    Base type declaration (defined internally)

    +
    + + + + + + + + + + + + + + + + + processing classifications + + + + +
    + + + :class: + + + + + + + ( + + ) + + + + + + +
    +
    + +
    +
    + + +
    + + + + + Yields: + +
    +
    +
    +
    + + + + + +

    + + + + or + + + + and + + + +

    + + +
    + + + + + + + + + + + + + + + + + + warning: failed to locate generated class ref ` + + ' + + + +
    + +
    +
    + + + + + + + +

    + + ubd- + + + + + + # + + + + + + + + + + + + + + + + + + + ( + + ) + + + must + + + + + , assuming that: + +

    + +

    +
    + + + + is ignored during classification + + + + + has the value + + + + + + + + + + + + match any value in + + + + + + + \( + + \) ( + + + + + # + + + + + + + + ) + + + + + + + [Undefined type: + + ] + + + + + + + + match the pattern: + + + + + + + + + = + + + + + + + + + be + + \( + + \) + + + + + + + + + + + + processing functions + + + + + + +
    + + + + + + + \( + + + + + \; + + + + \textrm{ + + } + + + + \) + + + + ( + + ) + + + + + + +
    +

    + + + + +
    + Yields: + \( + + + + + + + + \) +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + + + + + +
    + + + + + + + + + + + \( + + \) + + + + + + + + + + + +
    + +
    + Applicability: + + + Always applicable. + + + + + + + + + + + , + + + + + + + but not + + + + nor + + + + + + + + [summary] fatal: empty lv:class/@ref! + + + + + + + + + + + + +
    + + + + + + + +
    + Yields: + \( + + + + + + + + \) +
    + +
    + +
    + + + +
    +
    + + + + + + + + + + { + + + + + + + + [summary] internal: missing TeX symbol for ` + + ' within the context of ` + + ' + + + ~~~~[begin symbol dump]~~~~ + + ~~~~[end symbol dump]~~~~ + + ?^! + + + + + + + ( + + ) + + + + + + + + + } + + + + + + + + + + + + + + + + + + + + + + +
    +

    Calculation Breakdown

    + +
    +
    + + + + + + + + + + + + + + + +
    + Scope boundary (let) + + Each of the "let" statements below are only present + within this scope boundary and exist to simplify the equation. + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + let \( + + \) = + + + + + + + + + +
    + + + ubd- + + + + + + + + + + ( + + ) + + + + +
    +
    + + + + + + + + \( + + + + + \) + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    Context-Specific Constants

    +
      + +
    • + + = + +
    • +
      +
    +
    +
    + + + + +

    Summary Breakdown

    +
    + + parts + + + + many + + + + + + + + +
    + + \( + + + + + \) + + + + + + +
    + +
    +
    +
    +
    +
    + + + + + +
    +

    Generators

    + + +
    + + \( + \theta_{ + + } + + + = + + \) + + + + + + +
    + + ( + + ) +
    +
    +
    +
    +
    +
    + + + + +
    +
    + + + +
    + \( + + \) + + + +
    + +
    + +
    + +
    +
    +
    + + + + + + + + + + + + + + + + + + #:class: + + + + + + + + + + + [Undefined classification: + + ] + + + + + + + + +
    +

    N.B.

    +
    +
    Iverson's Convention
    +
    +

    + As is customary for many mathematical notations in CS, this system uses + Iverson's convention (Iverson's brackets) to denote certain conditional + expressions. It should be understood that the notation will produce a + value of \( 1 \) if the expression is true; otherwise, it will be + strongly \( 0 \) --- that is, even if the expression would + be undefined, it will still yield \( 0 \). +

    +

    + \( [ 1 \gt 0 ] = 1 \); \( [ 0 = 1 ] = 0 \); \( [ 5 \textrm{ is prime} ] = 1 \); +

    +

    + \( \sum \limits_{1 \leq k \leq 5} k = \sum \limits_k k [ 1 \leq k \leq 5 ] \) +

    +
    + +
    Sets
    +
    +

    + In the equations represented above, it is to be assumed that undefined + values in a set are implicitly 0; this simplifies the representations of + the various summations; they are not intended to be vigorous. +

    +

    + For example: let \( x \) = \( \{ 1, 2, 3 \} \). Given the equation \( + \sum_k x_k \), it is assumed that the solution is \( 1 + 2 + 3 = 6 \), + not undefined. Formally, the former sum is to be interpreted as: \( + \sum_{k=0}^n x_k \) where \( n \) is the length of set \( x \), or \( + \sum_k x_k [x_k \textrm{ is defined}] \) using Iverson's convention (the + latter of which our first notation is based upon by simply omitting the + brackets and implying their existence). +

    +
    + +
    Counting Sets
    +
    + Let \(N(S)\) = the number of values within the set \(S\); this notation is + used within certain summations. You may also see the following notations: + +
      +
    • + \(\sum_{k} S_k\) to count the number of one-values in boolean set + \(S\) (e.g. if \(S\) denotes properties with swimming pools, we can + count the number of swimming pools). +
    • +
    • + \(\sum_{k=0}^{N(S)} 1\) to count the number of values in set \(S\). +
    • +
    +
    + +
    Vector Arithmetic
    +
    + Only one type of vector arithmetic (dot products) is currently supported, + but others may be done manually using sums and products. Dot products are + denoted by \(a\cdot b\), where \(a\) and \(b\) are vectors. +
    + +
    Subscript Precedence
    +
    + Subscripts should be applied from right to left. That is: + \(S_{x_{y_z}}\) = \(S_{(x_{(y_z)})}\). In the event where a notation may + be ambiguous (e.g. \(\theta_{1_x}\), since \(1_x\) could not possibly make + sense in the context of this system), parenthesis will always be added to + clarify intent. +
    +
    +
    +
    + + + + + + + + + + [' + + ', + 0 + + + + + ,' + + ' + + + ], + + + + [' + + ', + 0 + + ], + + + + + + + + + + + + + + + +

    + Calculation Order ( + + ) +

    + +
      + +
    1. + + + +
    2. +
      +
    +
    + + + + + + + + + + + + +
    diff --git a/src/current/tools/csv2xml b/src/current/tools/csv2xml new file mode 100755 index 00000000..3a5d1b83 --- /dev/null +++ b/src/current/tools/csv2xml @@ -0,0 +1,110 @@ +#!/usr/bin/awk -f +# +# Compiles the given CSV into a table definition + + +function columngen( header ) +{ + # output a field constant for each field in the header + i = 0 + while ( field = header[ ++i ] ) + { + printf " \n", + field, + ( i - 1 ), + ( seq[ i ] ) ? "true" : "false" + } +} + + +function seqchk( last ) +{ + # if there's no last row, then do not bother + i = 0 + while ( i++ < NF ) + { + if ( seq[ i ] == "" ) seq[ i ] = 1 + + # this field is sequential if it is greater than or equal to the last field + # (we don't check for descending [yet]); note that on the first check, last + # will be empty and therefore this check will succeed (properly + # initializing seq[i] to 1) + seq[ i ] = seq[ i ] && ( $(i) >= last[ i ] ) + } +} + + +# header +BEGIN { + rootpath = "../../../" + file = ARGV[1] + + # grab only the filename (remove all preceding directories and the file ext) + name = gensub( /^.*\/|\.[^.]+$/, "", "g", file ) + + + # output package header + printf \ + "\n" \ + "\n\n" \ + " \n\n" \ + " \n" \ + " \n\n", \ + rootpath, name + + # the first row of the CSV is the header representing the column identifiers + getline + split( $0, header, /,/ ) + + # table constant identifier + tconst = toupper( gensub( /-/, "_", "g", name ) ) "_RATE_TABLE" + + # generate the header for the table constant + printf " \n", name + + printf "%s", " 1 ) ? "," : "" ) $(i) + } + + print ";" + + seqchk( last ) + split( $0, last ) +} + + +# footer +END { + # end of table-rows node + print "\" />" + + # columns can't be generated until after we know which ones represent + # sequential data + columngen( header ) + + print " " + print "" +} diff --git a/src/current/tools/csvi b/src/current/tools/csvi new file mode 100755 index 00000000..08d80e2a --- /dev/null +++ b/src/current/tools/csvi @@ -0,0 +1,124 @@ +#!/usr/bin/awk -f +# +# Performs interpolation for columns in a CSV and outputs the result +# +# Configurable values (use -vname=value from command line): +# step - use predeterminated step instead of calculating from first two rows +# +# # + +function storeline() +{ + for ( i = 1; i <= hlen; i++ ) { + prev[i] = $i + } +} + +function clearline() +{ + for ( i = 1; i <= hlen; i++ ) { + prev[i] = 0 + } +} + +function getprev() +{ + for ( i = 1; i <= hlen; i++ ) { + $i = prev[i] + } +} + + +function interpolate() +{ + lastval = prev[1] + + curval = $1 + diff = curval - lastval + + # does this value fall in line with the requested step? + if ( diff == step ) + { + storeline() + + # we're good; continue + print + next + } + + # if we do not yet have a value large enough to reach our step, then continue + # until we do (do not store this line) + n = int( diff / step ) + if ( n <= 0 ) { + next + } + + # determine interpolation values + for ( i = 2; i <= hlen; i++ ) { + ival[i] = ( ( $i - prev[i] ) / n ) + } + + getprev() + + # let us interpolate values that are divisible by the step + do + { + # increase the last value by our step + $1 += step + + # interpolate each column value (notice that we skip the first column, which + # was handled directly above) + for ( i = 2; i <= hlen; i++ ) { + $i += ival[i] + } + + # print the new line + print + } while ( ( diff -= step ) > 0 ) + + # anything remaining does not fit into our step and will be ignored; we'll + # continue with our next step at the next line + + # consider this to be our last line + storeline() +} + + +BEGIN { + # the first row of the CSV is the header representing the column identifiers + getline + hlen = split( $0, header, /,/ ) + + # output the header + print $0 + + # delimit fields by commas (the field separator for CSVs); note that this + # won't work properly if strings contain commas + FS = OFS = "," + + clearline() + getline + + # if no step was provided, then calculate one based on the first two rows + if ( step == 0 ) { + # output the first row, which does not need to be interpolated + print + + # compute the step + vala = $1 + getline + valb = $1 + step = valb - vala + + # since the second line is used to determine the step, then it must match the + # step and therefore is good to output + print + + # begin. + storeline() + } +} + + +# for each row +{ interpolate() } diff --git a/src/current/tools/csvm2csv b/src/current/tools/csvm2csv new file mode 100755 index 00000000..410d9fac --- /dev/null +++ b/src/current/tools/csvm2csv @@ -0,0 +1,112 @@ +#!/usr/bin/awk -f +# +# Compiles a "magic" CSV file into a normal CSV +# +# "Magic" CSVs simply exist to make life easier: they permit comments, blank +# lines, variables, sub-delimiter expansion, and any number of ranges per line. +# Ranges will be expanded in every combination, making rate tables highly +# maintainable. +# +# Variables are also supported when defined using :var=val. Variables may expand +# into ranges, 'cause they're awesome. Multiple variables may be delimited by +# semi-colons, as may multiple values. +# +# For example: +# :foo=1--3 +# $foo;7;9--10:$foo, 5--10 +# +# Would generate: +# 1, 5 +# 1, 6 +# ... +# 5, 10 +# 2, 5 +# ... +# 9, 5 +# ... +# 1, 5 +# 1, 6 +# ... + + +function rangeout( i, m, j, me, orig ) +{ + if ( i > NF ) + { + print + return + } + + orig = $i + + # check first for delimiters + if ( match( $i, /^([^;]+);(.*)$/, m ) ) + { + # give it a shot with the first value + $i = m[1] + rangeout( i ) + + # strip off the first value and process with following value(s) + $i = m[2] + rangeout( i ) + + # we've delegated; we're done + $i = orig + return + } + + # attempt to parse variable (may expand into a range) + if ( match( $i, /^\$([a-zA-Z_-]+)$/, m ) ) + { + $i = vars[ m[1] ]; + } + + # parse range + if ( match( $i, /^([0-9]+)--([0-9]+)$/, m ) ) + { + j = m[1] + me = m[2] + do + { + $i = j + rangeout( i + 1 ) + } while ( j++ < me ) + } + else + { + rangeout( i + 1 ); + } + + # restore to original value + $i = orig +} + + +BEGIN { + # we're parsing CSVs + FS = " *, *" + OFS = "," +} + + +# skip all lines that begin with `#', which denotes a comment, or are empty +/^#|^$/ { next; } + +# lines that begin with a colon are variable definitions +/^:/ { + match( $0, /^:([a-zA-Z_-]+)=(.*?)$/, m ) + vars[ m[1] ] = m[2] + next +} + +# lines containing ranges (denoted by `--', the en dash, which is a typesetting +# convetion for ranges), sub-delimiters, or variables must be expanded +/--|;|\$[a-zA-Z_-]/ { rangeout( 1 ); next; } + +# all other lines are normal; simply output them verbatim +{ + # this assignment will ensure that awk processes the output, ensuring that + # extra spaces between commas are stripped + $1=$1 + print +} diff --git a/src/current/tools/gen-make b/src/current/tools/gen-make new file mode 100755 index 00000000..3f59bfea --- /dev/null +++ b/src/current/tools/gen-make @@ -0,0 +1,96 @@ +#!/bin/bash +# +# Generates Makefile containing dependencies for each package +# # + +# windows machines may not have the tools to resolve a path, so let's do so +# ourselves (TODO: there's better (and more performant) ways of doing this than +# repeated string replacements); TODO: ./ +resolv-path() +{ + # no need to do anything if the string does not contain a parent dir reference + # (we use this convoluted string replacement check for woe32/64 to prevent + # additional spawns (e.g. sed) that would slow us down and because =~ is not + # properly supported in msys + [[ "$1" != "${1/..\//}"a ]] || { + echo "$1" + return + } + + local path= + while read name; do + if [ "$name" == .. ]; then + [ -n "$path" ] || { + echo "warning: will not resolve $1" >&2 + return 5 + } + + path="${path%/*}" + continue + fi + + path="$path/$name" + done <<< "${1//\//$'\n'}" + + # echo path without leading / + echo -n "${path:1}" +} + + +# rule for building +[ -z "$GEN_MAKE" ] && { + echo "%.xmlo:: %.tmp" + echo -e "\t@rm -f \$@ \$<" + [ -n "$xmlo_cmd" ] \ + && echo -e "\t$xmlo_cmd" \ + || echo -e "\ttouch \$@" + + echo "%.xmlo:: %.xml | prexmlo" + [ -n "$xmlo_cmd" ] \ + && echo -e "\t$xmlo_cmd" \ + || echo -e "\ttouch \$@" + + export GEN_MAKE="$( pwd )/$0" + exec "$GEN_MAKE" "$@" +} + +until [ $# -eq 0 ]; do ( + path="${1%%/}" + echo "[gen-make] scanning $path" >&2 + + cd "$( basename $path )/" || exit $? + + deps=$( find -maxdepth 1 -iname '*.dep' ) + for dpath in $deps; do + # equivalent to basename command; use this since spawning processes on + # windoze is slow as shit (originally we did find -exec bashename) + d="${dpath##*/}" + + echo "[gen-make] found $path/$d" >&2 + echo -n "$path/${d%.*}.xmlo:" + + # output deps + while read dep; do + # if the first character is a slash, then it's relative to the project + # root---the resolution has already been done for us! + if [ "${dep:0:1}" == '/' ]; then + echo -n " ${dep:1}.xmlo" + continue + fi + + echo -n ' ' + resolv-path "$path/$dep.xmlo" + done < "$d" + + echo + done + + # recurse on every subdirectory + for p in */; do + [ "$p" == ./ -o "$p" == ../ ] && continue + [ ! -d "$p" ] || "$GEN_MAKE" "$path/$p" || { + echo "fatal: failed to recurse on $( pwd )/$path/$p" >&2 + exit 1 + } + done +); shift; done diff --git a/src/current/tools/lib/zipre.php b/src/current/tools/lib/zipre.php new file mode 100644 index 00000000..b4f22e1a --- /dev/null +++ b/src/current/tools/lib/zipre.php @@ -0,0 +1,124 @@ + 3 ) && is_seq( $digits ) ) + { + return sprintf( '[%d-%d]', + $digits[ 0 ], + $digits[ count( $digits ) - 1 ] + ); + } + elseif ( count( $digits ) === 1 ) + { + // if there's only one digit, then that's all we need to return + return $digits[ 0 ]; + } + + return '[' . implode( '', $digits ) . ']'; + }, $re ); +} + +function is_seq( $digits, $last = '' ) +{ + // stop recursing once we're out of digits + if ( count( $digits ) === 0 ) + { + return true; + } + + // grab the current digit and remove it from the list (this has the effect + // of both cons and cdr) + $digit = (int)( array_shift( $digits ) ); + + // consider this a sequence if this digit is one more than the last (or if + // there is no last digit) and if the following digit is sequential + return ( ( $last === '' ) || ( $digit === ( $last + 1) ) ) + && is_seq( $digits, $digit ); +} diff --git a/src/current/tools/tdat2xml b/src/current/tools/tdat2xml new file mode 100755 index 00000000..db4e9b15 --- /dev/null +++ b/src/current/tools/tdat2xml @@ -0,0 +1,274 @@ +#!/usr/bin/env php + +' . "\n"; + } + + return sprintf( + '' . + "\n%s" . + " %s\n" . + "\n\n", + $name, + gen_identifier( $id ), + $desc, + $yields, + $prev_value, + gen_any_block( $queue, $or ) + ); +} + + +function gen_any_block( $queue, $or ) +{ + $any = gen_zip_re( $queue ) . + gen_on_class( $or ); + + return ( $any ) + ? '' . $any . '' + : ''; +} + + +function gen_zip_re( $data ) +{ + if ( count( $data ) === 0 ) + { + return ''; + } + + return sprintf( + '', + gen_re_quick( $data ) + ); +} + +function gen_on_class( $data ) +{ + if ( count( $data ) === 0 ) + { + return ''; + } + + $cur = array_shift( $data ); + + return sprintf( + '%s', + $cur, + gen_on_class( $data ) + ); +} + +function gen_identifier( $id ) +{ + return is_numeric( $id ) + ? $id + : '-' . strtolower( $id ); +} + +function gen_identifier_value( $id ) +{ + // for non-numeric identifiers, return ascii value + // of character to represent our value + return is_numeric( $id ) + ? $id + : ord( $id ); +} + +$file = $argv[ 1 ]; +$fdat = explode( '.', basename( $file ) ); +$name = $fdat[ 0 ]; + +$cur = ''; +$queue = array(); +$or = array(); + +$fh = fopen( $file, 'r' ); + +echo 'name="rates/territories/', $name, '" ', "\n", + 'desc="', ucfirst( $name ), ' territory classifications">' . "\n\n"; + +echo "\n\n"; + +$ids = array(); +$params = array(); +$imports = array(); +$prev_yields = ''; +$prev_yields_all = array(); +$classes = ''; + +$param_type = 'terrType' . ucfirst( $name ); + +while ( true ) +{ + // read the line within the loop so that we do not terminate until after we + // treat eof as an empty line + $line = str_replace( array( "\n", "\r" ), '', fgets( $fh ) ); + + if ( !$cur ) + { + if ( substr( $line, 0, 12 ) === '@import-pkg ' ) + { + $imports[] = substr( $line, 12 ); + continue; + } + + // we expect this line to be a territory descriptor + try + { + list ( $id, $desc ) = parse_tdesc( $line ); + } + catch ( Exception $e ) + { + fwrite( STDERR, 'Invalid territory descriptor: ' . $line ); + exit( 1 ); + } + + $ids[] = $id; + $cur = $id; + } + elseif ( ( $line === '' ) || feof( $fh ) ) + { + // generate param for typedef + $params[ $id ] = $desc; + + // if there's nothing in the queue, then treat this as an 'ROS' (this + // should appear as the *last* territory, or it will not function as + // expected) + if ( count( $queue ) === 0 ) + { + $prev = $prev_yields_all; + } + else + { + $prev = array( $prev_yields ); + } + + // generate the classification + $classes .= gen_classification( $id, $name, $desc, $prev, $queue, $or ); + + // this accomplishes two things: (1) avoids regexes if there's a + // previous match and (2) ensures that we cannot possibly match multiple + // territories + $prev_yields = gen_yields( $id, $name ); + $prev_yields_all[] = $prev_yields; + + $cur = ''; + $queue = array(); + $or = array(); + + if ( feof( $fh ) ) + { + break; + } + } + elseif ( $line[0] === '=' ) + { + // =foo means match on classification @yields "foo" + $or[] = substr( $line, 1 ); + } + else + { + $queue[] = $line; + } +} + +$param_name = 'territory_' . $name; +?> + + + + + + + + + + + + + + + + + $desc ) { ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/current/tools/zipre b/src/current/tools/zipre new file mode 100755 index 00000000..4e6966f2 --- /dev/null +++ b/src/current/tools/zipre @@ -0,0 +1,23 @@ +#!/usr/bin/env php + + + + + + + + + Root node for rating worksheets + + + + + + + + + + + + + + Package for which worksheet is being generated + + + + + + +