def minus(ctx, xs, ys): if len(xs) == 1 and len(ys) == 1: x = util.get_data(xs[0]) y = util.get_data(ys[0]) if util.is_number(x) and util.is_number(y): return x - y if isinstance(x, nodes.FP_TimeBase) and isinstance( y, nodes.FP_Quantity): return x.plus(nodes.FP_Quantity(-y.value, y.unit)) raise Exception("Cannot " + str(xs) + " - " + str(ys))
def ensure_number_singleton(x): data = util.get_data(x) if not util.is_number(data): if not isinstance(data, list) or len(data) != 1: raise Exception("Expected list with number, but got " + str(data)) value = util.get_data(data[0]) if not util.is_number(value): raise Exception("Expected number, but got " + str(x)) return value return data
def typecheck(a, b): """ Checks that the types of a and b are suitable for comparison in an inequality expression. It is assumed that a check has already been made that there is at least one value in a and b. Parameters: a (list) - the left side of the inequality expression (which should be an array of one value) b (list) - the right side of the inequality expression (which should be an array of one value) returns the singleton values of the arrays a, and b. If one was an FP_Type and the other was convertible, the coverted value will be retureed """ rtn = None check_length(a) check_length(b) a = util.get_data(a[0]) b = util.get_data(b[0]) lClass = a.__class__ rClass = b.__class__ areNumbers = util.is_number(a) and util.is_number(b) if lClass != rClass and not areNumbers: d = None # TODO refactor if lClass == str and (rClass == nodes.FP_DateTime or rClass == nodes.FP_Time): d = nodes.FP_DateTime(a) or nodes.FP_Time(a) if d is not None: rtn = [d, b] elif rClass == str and (lClass == nodes.FP_DateTime or lClass == nodes.FP_Time): d = nodes.FP_DateTime(b) or nodes.FP_Time(b) if d is not None: rtn = [a, d] if rtn is None: raise Exception('Type of "' + str(a) + '" (' + lClass.__name__ + ') did not match type of "' + str(b) + '" (' + rClass.__name__ + "). InequalityExpression") if rtn is not None: return rtn return [a, b]
def to_integer(ctx, coll): if len(coll) != 1: return [] value = util.get_data(coll[0]) if value == False: return 0 if value == True: return 1 if util.is_number(value): if int(value) == value: return value return [] if str(value): if re.match(intRegex, value) is not None: return int(value) raise Exception("Could not convert to ineger: " + value) return []
def plus(ctx, xs, ys): if len(xs) != 1 or len(ys) != 1: raise Exception("Cannot " + str(xs) + " + " + str(ys)) x = util.get_data(xs[0]) y = util.get_data(ys[0]) """ In the future, this and other functions might need to return ResourceNode to preserve the type information (integer vs decimal, and maybe decimal vs string if decimals are represented as strings), in order to support "as" and "is", but that support is deferred for now. """ if type(x) == str and type(y) == str: return x + y if util.is_number(x) and util.is_number(y): return x + y if isinstance(x, nodes.FP_TimeBase) and isinstance(y, nodes.FP_Quantity): return x.plus(y)
def polarity_expression(ctx, parentData, node): sign = node["terminalNodeText"][0] rtn = engine.do_eval(ctx, parentData, node["children"][0]) if len(rtn) != 1: # not yet in spec, but per Bryn Rhodes raise Exception("Unary " + sign + " can only be applied to an individual number.") if not util.is_number(rtn[0]): raise Exception("Unary " + sign + " can only be applied to a number.") if sign == "-": rtn[0] = -rtn[0] return rtn
def to_decimal(ctx, coll): if len(coll) != 1: return [] value = util.get_data(coll[0]) if value == False: return 0 if value == True: return 1.0 if util.is_number(value): return value if type(value) == str: if re.match(numRegex, value) is not None: return float(value) raise Exception("Could not convert to decimal: " + value) return []
def is_empty(x): if util.is_number(x): return False return util.is_empty(x)