#!/usr/bin/env bash # # mktheorytraits # Morgan Deters for CVC4 # Copyright (c) 2010-2013 The CVC4 Project # # The purpose of this script is to create theory_traits.h from a template # and a list of theory kinds. # # Invocation: # # mktheorytraits template-file theory-kind-files... # # Output is to standard out. # copyright=2010-2014 filename=`basename "$1" | sed 's,_template,,'` cat <&2 exit 1 fi # this script doesn't care about the theory class information, but # makes does make sure it's there seen_theory=true if [ "$1" = THEORY_BUILTIN ]; then if $seen_theory_builtin; then echo "$kf:$lineno: error: \"builtin\" theory redefined" >&2 exit 1 fi seen_theory_builtin=true elif [ -z "$1" -o -z "$2" -o -z "$3" ]; then echo "$kf:$lineno: error: \"theory\" directive missing class or header argument" >&2 exit 1 elif ! expr "$2" : '\(::*\)' >/dev/null; then echo "$kf:$lineno: warning: theory class \`$2' isn't fully-qualified (e.g., ::CVC4::theory::foo)" >&2 elif ! expr "$2" : '\(::CVC4::theory::*\)' >/dev/null; then echo "$kf:$lineno: warning: theory class not under ::CVC4::theory namespace" >&2 fi theory_id="$1" theory_class="$2" theory_header="$3" theory_includes="${theory_includes}#include \"$theory_header\" " } function alternate { # alternate ID name T header lineno=${BASH_LINENO[0]} if $seen_theory; then echo "$kf:$lineno: error: multiple theories defined in one file !?" >&2 exit 1 fi seen_theory=true seen_endtheory=true theory_header="$4" theory_includes="${theory_includes}#include \"$theory_header\" " } function rewriter { # rewriter class header lineno=${BASH_LINENO[0]} check_theory_seen rewriter_class="$1" rewriter_header="$2" theory_includes="${theory_includes}#include \"$2\" " } function endtheory { # endtheory lineno=${BASH_LINENO[0]} check_theory_seen seen_endtheory=true theory_constructors="${theory_constructors} case $theory_id: \$alternate_for_$theory_id engine->addTheory< $theory_class >($theory_id); return; " theory_traits="${theory_traits} template<> struct TheoryTraits<${theory_id}> { // typedef ${theory_class} theory_class; typedef ${rewriter_class} rewriter_class; static const bool isStableInfinite = ${theory_stable_infinite}; static const bool isFinite = ${theory_finite}; static const bool isPolite = ${theory_polite}; static const bool isParametric = ${theory_parametric}; static const bool hasCheck = ${theory_has_check}; static const bool hasPropagate = ${theory_has_propagate}; static const bool hasPpStaticLearn = ${theory_has_ppStaticLearn}; static const bool hasNotifyRestart = ${theory_has_notifyRestart}; static const bool hasPresolve = ${theory_has_presolve}; static const bool hasPostsolve = ${theory_has_postsolve}; };/* struct TheoryTraits<${theory_id}> */ " # warnings about theory content and properties dir="$(dirname "$kf")/../../" if [ -e "$dir/$theory_header" ]; then for function in check propagate ppStaticLearn notifyRestart presolve postsolve; do if eval "\$theory_has_$function"; then grep '\<'"$function"' *\((\|;\)' "$dir/$theory_header" | grep -vq '^ */\(/\|\*\)' || echo "$kf: warning: $theory_class has property \"$function\" in its kinds file but doesn't appear to declare the function" >&2 else grep '\<'"$function"' *\((\|;\)' "$dir/$theory_header" | grep -vq '^ */\(/\|\*\)' && echo "$kf: warning: $theory_class does not have property \"$function\" in its kinds file but appears to declare the function" >&2 fi done else echo "$me: warning: theory header \"$theory_header\" does not exist or is unreadable" >&2 fi theory_has_check="false" theory_has_propagate="false" theory_has_ppStaticLearn="false" theory_has_notifyRestart="false" theory_has_presolve="false" theory_has_postsolve="false" theory_stable_infinite="false" theory_finite="false" theory_polite="false" theory_parametric="false" rewriter_class= rewriter_header= theory_id= theory_class= type_constants= type_kinds= lineno=${BASH_LINENO[0]} } function enumerator { # enumerator KIND enumerator-class header lineno=${BASH_LINENO[0]} check_theory_seen type_enumerator_includes="${type_enumerator_includes} #include \"$3\"" if expr "$type_constants" : '.* '"$1"' ' &>/dev/null; then mk_type_enumerator_type_constant_cases="${mk_type_enumerator_type_constant_cases} case $1: return new $2(type, tep); " elif expr "$type_kinds" : '.* '"$1"' ' &>/dev/null; then mk_type_enumerator_cases="${mk_type_enumerator_cases} case kind::$1: return new $2(type, tep); " else echo "$kf:$lineno: error: don't know anything about $1; enumerator must appear after definition" >&2 echo "type_constants: $type_constants" >&2 echo "type_kinds : $type_kinds" >&2 exit 1 fi } function typechecker { # typechecker header lineno=${BASH_LINENO[0]} check_theory_seen } function typerule { # typerule OPERATOR typechecking-class lineno=${BASH_LINENO[0]} check_theory_seen } function construle { # construle OPERATOR isconst-checking-class lineno=${BASH_LINENO[0]} check_theory_seen } function properties { # properties property* lineno=${BASH_LINENO[0]} check_theory_seen while (( $# )); do property="$1" case "$property" in finite) theory_finite="true";; stable-infinite) theory_stable_infinite="true";; parametric) theory_parametric="true";; polite) theory_polite="true";; check) theory_has_check="true";; propagate) theory_has_propagate="true";; ppStaticLearn) theory_has_ppStaticLearn="true";; presolve) theory_has_presolve="true";; postsolve) theory_has_postsolve="true";; notifyRestart) theory_has_notifyRestart="true";; *) echo "$kf:$lineno: error: unknown theory property \"$property\"" >&2; exit 1;; esac shift done } function sort { # sort TYPE cardinality [well-founded ground-term header | not-well-founded] ["comment"] lineno=${BASH_LINENO[0]} check_theory_seen if [ "$3" = well-founded ]; then register_sort "$1" "$2" "$6" else register_sort "$1" "$2" "$4" fi } function cardinality { # cardinality TYPE cardinality-computer [header] lineno=${BASH_LINENO[0]} check_theory_seen } function well-founded { # well-founded TYPE wellfoundedness-computer [header] lineno=${BASH_LINENO[0]} check_theory_seen } function variable { # variable K ["comment"] lineno=${BASH_LINENO[0]} check_theory_seen register_kind "$1" 0 "$2" } function operator { # operator K #children ["comment"] lineno=${BASH_LINENO[0]} check_theory_seen register_kind "$1" "$2" "$3" } function parameterized { # parameterized K1 K2 #children ["comment"] lineno=${BASH_LINENO[0]} check_theory_seen register_kind "$1" "$3" "$4" } function constant { # constant K T Hasher header ["comment"] lineno=${BASH_LINENO[0]} check_theory_seen register_kind "$1" 0 "$5" } function nullaryoperator { # nullaryoperator K ["comment"] lineno=${BASH_LINENO[0]} check_theory_seen register_kind "$1" 0 "$2" } function register_sort { id=$1 cardinality=$2 comment=$3 type_constant_to_theory_id="${type_constant_to_theory_id} case $id: return $theory_id; break; " type_constants="${type_constants} $1 " } function register_kind { r=$1 nc=$2 comment=$3 kind_to_theory_id="${kind_to_theory_id} case kind::$r: return $theory_id; break; " type_kinds="${type_kinds} $1 " } function check_theory_seen { if $seen_endtheory; then echo "$kf:$lineno: error: command after \"endtheory\" declaration (endtheory has to be last)" >&2 exit 1 fi if ! $seen_theory; then echo "$kf:$lineno: error: no \"theory\" declaration found (it has to be first)" >&2 exit 1 fi } function check_builtin_theory_seen { if ! $seen_theory_builtin; then echo "$me: warning: no declaration for the builtin theory found" >&2 fi } while [ $# -gt 0 ]; do kf=$1 seen_theory=false seen_endtheory=false b=$(basename $(dirname "$kf")) source "$kf" if ! $seen_theory; then echo "$kf: error: no theory content found in file!" >&2 exit 1 fi if ! $seen_endtheory; then echo "$kf:$lineno: error: no \"endtheory\" declaration found (it is required at the end)" >&2 exit 1 fi shift done check_builtin_theory_seen ## output eval "theory_constructors=\"$theory_constructors\"" text=$(cat "$template") for var in \ theory_traits \ theory_includes \ theory_constructors \ template \ type_enumerator_includes \ mk_type_enumerator_type_constant_cases \ mk_type_enumerator_cases \ ; do eval text="\${text//\\\$\\{$var\\}/\${$var}}" done error=`expr "$text" : '.*\${\([^}]*\)}.*'` if [ -n "$error" ]; then echo "$template:0: error: undefined replacement \${$error}" >&2 exit 1 fi echo "$text"