jbe/bsw@0: local digit_set = { jbe/bsw@0: ["0"] = true, ["1"] = true, ["2"] = true, ["3"] = true, ["4"] = true, jbe/bsw@0: ["5"] = true, ["6"] = true, ["7"] = true, ["8"] = true, ["9"] = true jbe/bsw@0: } jbe/bsw@0: jbe/bsw@0: function parse.decimal(str, dest_type, options) jbe/bsw@0: local str = parse._pre_fold(str) jbe/bsw@0: local dest_type = dest_type or atom.number jbe/bsw@0: local options = options or {} jbe/bsw@0: if str == "" then jbe/bsw@0: return nil jbe/bsw@0: else jbe/bsw@0: local decimal_shift = options.decimal_shift or 0 jbe/bsw@0: if decimal_shift == true then jbe/bsw@0: decimal_shift = options.precision jbe/bsw@0: end jbe/bsw@0: local decimal_point = locale.get("decimal_point") or "." jbe/bsw@0: local negative = nil jbe/bsw@0: local int = 0 jbe/bsw@0: local frac = 0 jbe/bsw@0: local precision = 0 jbe/bsw@0: local after_point = false jbe/bsw@0: for char in string.gmatch(str, ".") do jbe/bsw@0: local skip = false jbe/bsw@0: if negative == nil then jbe/bsw@0: if char == "+" then jbe/bsw@0: negative = false jbe/bsw@0: skip = true jbe/bsw@0: elseif char == "-" then -- real minus sign already replaced by _pre_fold jbe/bsw@0: negative = true jbe/bsw@0: skip = true jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: if not skip then jbe/bsw@0: if digit_set[char] then jbe/bsw@0: if after_point then jbe/bsw@0: if decimal_shift > 0 then jbe/bsw@0: int = 10 * int + tonumber(char) jbe/bsw@0: decimal_shift = decimal_shift - 1 jbe/bsw@0: else jbe/bsw@0: frac = 10 * frac + tonumber(char) jbe/bsw@0: precision = precision + 1 jbe/bsw@0: end jbe/bsw@0: else jbe/bsw@0: int = 10 * int + tonumber(char) jbe/bsw@0: end jbe/bsw@0: elseif char == decimal_point then jbe/bsw@0: if after_point then jbe/bsw@0: return dest_type.invalid jbe/bsw@0: else jbe/bsw@0: after_point = true jbe/bsw@0: end jbe/bsw@0: elseif char ~= " " then -- TODO: ignore thousand seperator too, when supported by format.decimal jbe/bsw@0: return dest_type.invalid jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: int = int * 10 ^ decimal_shift jbe/bsw@0: if dest_type == atom.number or dest_type == atom.integer then jbe/bsw@0: if dest_type == atom.integer and frac ~= 0 then jbe/bsw@0: return atom.not_a_number jbe/bsw@0: else jbe/bsw@0: local f = int + frac / 10 ^ precision jbe/bsw@0: if negative then jbe/bsw@0: f = -f jbe/bsw@0: end jbe/bsw@0: return f jbe/bsw@0: end jbe/bsw@0: elseif dest_type == atom.fraction then jbe/bsw@0: return atom.fraction(int * 10 ^ precision + frac, 10 ^ precision) jbe/bsw@0: else jbe/bsw@0: error("Missing or invalid destination type for parsing.") jbe/bsw@0: end jbe/bsw@0: end jbe/bsw@0: end