forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			155 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from __future__ import absolute_import, print_function, unicode_literals
 | 
						|
 | 
						|
import math
 | 
						|
from .shared import string, to_str, fromNow, JSONTemplateError
 | 
						|
 | 
						|
 | 
						|
class BuiltinError(JSONTemplateError):
 | 
						|
    pass
 | 
						|
 | 
						|
 | 
						|
def build():
 | 
						|
    builtins = {}
 | 
						|
 | 
						|
    def builtin(name, variadic=None, argument_tests=None, minArgs=None, needs_context=False):
 | 
						|
        def wrap(fn):
 | 
						|
            if variadic:
 | 
						|
                def invoke(context, *args):
 | 
						|
                    if minArgs:
 | 
						|
                        if len(args) < minArgs:
 | 
						|
                            raise BuiltinError(
 | 
						|
                                'invalid arguments to builtin: {}: expected at least {} arguments'.format(name, minArgs)
 | 
						|
                            )
 | 
						|
                    for arg in args:
 | 
						|
                        if not variadic(arg):
 | 
						|
                            raise BuiltinError('invalid arguments to builtin: {}'.format(name))
 | 
						|
                    if needs_context is True:
 | 
						|
                        return fn(context, *args)
 | 
						|
                    return fn(*args)
 | 
						|
 | 
						|
            elif argument_tests:
 | 
						|
                def invoke(context, *args):
 | 
						|
                    if len(args) != len(argument_tests):
 | 
						|
                        raise BuiltinError('invalid arguments to builtin: {}'.format(name))
 | 
						|
                    for t, arg in zip(argument_tests, args):
 | 
						|
                        if not t(arg):
 | 
						|
                            raise BuiltinError('invalid arguments to builtin: {}'.format(name))
 | 
						|
                    if needs_context is True:
 | 
						|
                        return fn(context, *args)
 | 
						|
                    return fn(*args)
 | 
						|
 | 
						|
            else:
 | 
						|
                def invoke(context, *args):
 | 
						|
                    if needs_context is True:
 | 
						|
                        return fn(context, *args)
 | 
						|
                    return fn(*args)
 | 
						|
 | 
						|
            invoke._jsone_builtin = True
 | 
						|
            builtins[name] = invoke
 | 
						|
            return fn
 | 
						|
 | 
						|
        return wrap
 | 
						|
 | 
						|
    def is_number(v):
 | 
						|
        return isinstance(v, (int, float)) and not isinstance(v, bool)
 | 
						|
 | 
						|
    def is_string(v):
 | 
						|
        return isinstance(v, string)
 | 
						|
 | 
						|
    def is_string_or_number(v):
 | 
						|
        return is_string(v) or is_number(v)
 | 
						|
 | 
						|
    def is_array(v):
 | 
						|
        return isinstance(v, list)
 | 
						|
 | 
						|
    def is_string_or_array(v):
 | 
						|
        return isinstance(v, (string, list))
 | 
						|
 | 
						|
    def anything_except_array(v):
 | 
						|
        return isinstance(v, (string, int, float, bool)) or v is None
 | 
						|
 | 
						|
    def anything(v):
 | 
						|
        return isinstance(v, (string, int, float, list, dict)) or v is None or callable(v)
 | 
						|
 | 
						|
    # ---
 | 
						|
 | 
						|
    builtin('min', variadic=is_number, minArgs=1)(min)
 | 
						|
    builtin('max', variadic=is_number, minArgs=1)(max)
 | 
						|
    builtin('sqrt', argument_tests=[is_number])(math.sqrt)
 | 
						|
    builtin('abs', argument_tests=[is_number])(abs)
 | 
						|
 | 
						|
    @builtin('ceil', argument_tests=[is_number])
 | 
						|
    def ceil(v):
 | 
						|
        return int(math.ceil(v))
 | 
						|
 | 
						|
    @builtin('floor', argument_tests=[is_number])
 | 
						|
    def floor(v):
 | 
						|
        return int(math.floor(v))
 | 
						|
 | 
						|
    @builtin('lowercase', argument_tests=[is_string])
 | 
						|
    def lowercase(v):
 | 
						|
        return v.lower()
 | 
						|
 | 
						|
    @builtin('uppercase', argument_tests=[is_string])
 | 
						|
    def lowercase(v):
 | 
						|
        return v.upper()
 | 
						|
 | 
						|
    builtin('len', argument_tests=[is_string_or_array])(len)
 | 
						|
    builtin('str', argument_tests=[anything_except_array])(to_str)
 | 
						|
    builtin('number', variadic=is_string, minArgs=1)(float)
 | 
						|
 | 
						|
    @builtin('strip', argument_tests=[is_string])
 | 
						|
    def strip(s):
 | 
						|
        return s.strip()
 | 
						|
 | 
						|
    @builtin('rstrip', argument_tests=[is_string])
 | 
						|
    def rstrip(s):
 | 
						|
        return s.rstrip()
 | 
						|
 | 
						|
    @builtin('lstrip', argument_tests=[is_string])
 | 
						|
    def lstrip(s):
 | 
						|
        return s.lstrip()
 | 
						|
 | 
						|
    @builtin('join', argument_tests=[is_array, is_string_or_number])
 | 
						|
    def join(list, separator):
 | 
						|
        # convert potential numbers into strings
 | 
						|
        string_list = [str(int) for int in list]
 | 
						|
 | 
						|
        return str(separator).join(string_list)
 | 
						|
 | 
						|
    @builtin('split', variadic=is_string_or_number, minArgs=1)
 | 
						|
    def split(s, d=''):
 | 
						|
        if not d and is_string(s):
 | 
						|
            return list(s)
 | 
						|
 | 
						|
        return s.split(to_str(d))
 | 
						|
 | 
						|
    @builtin('fromNow', variadic=is_string, minArgs=1, needs_context=True)
 | 
						|
    def fromNow_builtin(context, offset, reference=None):
 | 
						|
        return fromNow(offset, reference or context.get('now'))
 | 
						|
 | 
						|
    @builtin('typeof', argument_tests=[anything])
 | 
						|
    def typeof(v):
 | 
						|
        if isinstance(v, bool):
 | 
						|
            return 'boolean'
 | 
						|
        elif isinstance(v, string):
 | 
						|
            return 'string'
 | 
						|
        elif isinstance(v, (int, float)):
 | 
						|
            return 'number'
 | 
						|
        elif isinstance(v, list):
 | 
						|
            return 'array'
 | 
						|
        elif isinstance(v, dict):
 | 
						|
            return 'object'
 | 
						|
        elif v is None:
 | 
						|
            return 'null'
 | 
						|
        elif callable(v):
 | 
						|
            return 'function'
 | 
						|
 | 
						|
    @builtin('defined', argument_tests=[is_string], needs_context=True)
 | 
						|
    def defined(context, s):
 | 
						|
        if s not in context:
 | 
						|
            return False
 | 
						|
        else:
 | 
						|
            return True
 | 
						|
 | 
						|
    return builtins
 |