<commit_before>'''Layout of math expressions.

   A layout is hiercharcal structure of special objects that can represent
   the calculations commonly performed in chemistry/physics. These objects
   can then be serialized to a json-compatible format with the intent that
   a corresponding javascript library can render them in a browser.
'''

from __future__ import absolute_import

import operator
from decimal import Decimal

from jamenson.runtime.multimethod import MultiMethod, defmethod
from jamenson.runtime.atypes import anytype, Seq, as_optimized_type, IsType, typep, eq_types, union
from jamenson.runtime.struct import make_struct, BaseStruct, no_default

from .types import lossless_number_type
from .sigfig import SigFig
from . import units
from .physnum import PhysNum, as_physnum
from .dne import DNEType

class BaseML(object):

    pass

class BaseMLStruct(BaseML, BaseStruct):
    pass

ml_type = as_optimized_type((BaseML, units.BaseUnit))
ml_seq_type = as_optimized_type(Seq(ml_type))

as_ml = MultiMethod('as_ml')

get_ml_json =  MultiMethod('get_ml_json')

json_ml = MultiMethod('json_ml')

@defmethod(as_ml, [ml_type])
def meth(ml):
    return ml

def defml(names, *decs):
    if isinstance(names, str):
        names = [names]
    for name in names:
        globals()[name] = struct = make_struct(name, base=BaseMLStruct, *decs)
        # set proper module to be pickleable
        struct.__module__ = __name__

@defmethod(get_ml_json, [object])
def meth(o):
    return get_ml_json(as_ml(o))

@defmethod(get_ml_json, [BaseMLStruct])
def meth(ml):
    data = json_ml(ml)
    assert isinstance(data, dict), 'bad data for %s; %r' % (ml.__class__.__name__, data)
    assert 'cls' not in data
    data['cls'] = ml.__class__.__name__
    return data

@defmethod(json_ml, [ml_type])
def meth(a):
    data = {}
    for n,d,tp in a._properties:
        v = getattr(a, n)
        if eq_types(tp, ml_type):
            assert typep(v, ml_type), 'invalid value %r for %s of %s w/ tp %s' % (v, n, a.__class__.__name__, tp)
            v = get_ml_json(v)
        elif tp == ml_seq_type:
            assert typep(v, ml_seq_type)
            v = map(get_ml_json, v)
        elif typep(v, ml_type):
            v = get_ml_json(v)
        data[n] = v
    return data


# # # # #
# null  #
# # # # #

defml("null")

@defmethod(as_ml, [IsType(None)])
def meth(n):
    return null()


# # # # #
# units #
# # # # #

unit_json_cache = {}
@defmethod(get_ml_json, [units.BaseUnit])
def meth(unit):
    try:
        return unit_json_cache[unit]
    except KeyError:
        json = unit_json_cache[unit] = make_unit_json(unit)
        return json

make_unit_json = MultiMethod('make_unit_json')

primitive_unit_unicode = {
    units.temperatures.C : [u"\u00B0C", "centigrade"],<commit_msg>Used memorize decorator in place of explicit cache for unit-specialized get_ml_json<commit_after>'''Layout of math expressions.

   A layout is hiercharcal structure of special objects that can represent
   the calculations commonly performed in chemistry/physics. These objects
   can then be serialized to a json-compatible format with the intent that
   a corresponding javascript library can render them in a browser.
'''

from __future__ import absolute_import

import operator
from decimal import Decimal

from hlab.memorize import memorize

from jamenson.runtime.multimethod import MultiMethod, defmethod
from jamenson.runtime.atypes import anytype, Seq, as_optimized_type, IsType, typep, eq_types, union
from jamenson.runtime.struct import make_struct, BaseStruct, no_default

from .types import lossless_number_type
from .sigfig import SigFig
from . import units
from .physnum import PhysNum, as_physnum
from .dne import DNEType

class BaseML(object):

    pass

class BaseMLStruct(BaseML, BaseStruct):
    pass

ml_type = as_optimized_type((BaseML, units.BaseUnit))
ml_seq_type = as_optimized_type(Seq(ml_type))

as_ml = MultiMethod('as_ml')

get_ml_json =  MultiMethod('get_ml_json')

json_ml = MultiMethod('json_ml')

@defmethod(as_ml, [ml_type])
def meth(ml):
    return ml

def defml(names, *decs):
    if isinstance(names, str):
        names = [names]
    for name in names:
        globals()[name] = struct = make_struct(name, base=BaseMLStruct, *decs)
        # set proper module to be pickleable
        struct.__module__ = __name__

@defmethod(get_ml_json, [object])
def meth(o):
    return get_ml_json(as_ml(o))

@defmethod(get_ml_json, [BaseMLStruct])
def meth(ml):
    data = json_ml(ml)
    assert isinstance(data, dict), 'bad data for %s; %r' % (ml.__class__.__name__, data)
    assert 'cls' not in data
    data['cls'] = ml.__class__.__name__
    return data

@defmethod(json_ml, [ml_type])
def meth(a):
    data = {}
    for n,d,tp in a._properties:
        v = getattr(a, n)
        if eq_types(tp, ml_type):
            assert typep(v, ml_type), 'invalid value %r for %s of %s w/ tp %s' % (v, n, a.__class__.__name__, tp)
            v = get_ml_json(v)
        elif tp == ml_seq_type:
            assert typep(v, ml_seq_type)
            v = map(get_ml_json, v)
        elif typep(v, ml_type):
            v = get_ml_json(v)
        data[n] = v
    return data


# # # # #
# null  #
# # # # #

defml("null")

@defmethod(as_ml, [IsType(None)])
def meth(n):
    return null()


# # # # #
# units #
# # # # #

@defmethod(get_ml_json, [units.BaseUnit])
@memorize
def meth(unit):
    return make_unit_json(unit)

make_unit_json = MultiMethod('make_unit_json')

primitive_unit_unicode = {
    units.temperatures.C : [u"\u00B0C", "centigrade"],
{'fraction_non_alphanumeric': 0.10806916426512968, 'fraction_numerical': 0.001080691642651297, 'mean_word_length': 3.6275, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '438557', 'n_tokens_mistral': 1908, 'n_tokens_neox': 1899, 'n_words': 521}