#! /usr/bin/env python3

"""
Take a math expression not handled well by C++11 constexpr and produce a
raw floating point value with provenance via code that can be pasted into
fortran and C++.
"""

import argparse, sys, os
from math import *

###############################################################################
def parse_command_line(args, description):
###############################################################################
    parser = argparse.ArgumentParser(
        usage="""\n{0} <varname> '<expression>'
OR
{0} --help

\033[1mEXAMPLES:\033[0m
    \033[1;32m# Get code for log10(3.)*2.0 \033[0m
    > {0} myconst 'log10(3.)*2.0'
""".format(os.path.basename(args[0])),
        description=description,
        formatter_class=argparse.ArgumentDefaultsHelpFormatter
    )

    parser.add_argument("varname", help="The name of the variable")

    parser.add_argument("expr", help="The expression to evaluate")

    args = parser.parse_args(args[1:])

    return args

###############################################################################
def const_maker(varname, expr):
###############################################################################
    val = eval(expr)

    # Note: fortran sci-notation literals need a 'd' instead of 'e' to make
    # them double-precision. The assignment to real(rtype) will truncate if
    # necessary.
    print("Fortran:")
    s = "real(rtype), public, parameter :: {} = {:22.15e} ! {}".format(varname, val, expr)
    s = s.replace('e+','d+')
    s = s.replace('e-','d-')
    print(s)

    print("C++:")
    print("static constexpr Scalar {} = {:22.15e}; // {}".format(varname, val, expr))

    return True

###############################################################################
def _main_func(description):
###############################################################################
    success = const_maker(**vars(parse_command_line(sys.argv, description)))

    sys.exit(0 if success else 1)

###############################################################################

if (__name__ == "__main__"):
    _main_func(__doc__)
