| 1907 | } |
| 1908 | |
| 1909 | CheckedError Parser::ParseSingleValue(const std::string *name, Value &e, |
| 1910 | bool check_now) { |
| 1911 | if (token_ == '+' || token_ == '-') { |
| 1912 | const char sign = static_cast<char>(token_); |
| 1913 | // Get an indentifier: NAN, INF, or function name like cos/sin/deg. |
| 1914 | NEXT(); |
| 1915 | if (token_ != kTokenIdentifier) return Error("constant name expected"); |
| 1916 | attribute_.insert(0, 1, sign); |
| 1917 | } |
| 1918 | |
| 1919 | const auto in_type = e.type.base_type; |
| 1920 | const auto is_tok_ident = (token_ == kTokenIdentifier); |
| 1921 | const auto is_tok_string = (token_ == kTokenStringConstant); |
| 1922 | |
| 1923 | // First see if this could be a conversion function. |
| 1924 | if (is_tok_ident && *cursor_ == '(') { return ParseFunction(name, e); } |
| 1925 | |
| 1926 | // clang-format off |
| 1927 | auto match = false; |
| 1928 | |
| 1929 | #define IF_ECHECK_(force, dtoken, check, req) \ |
| 1930 | if (!match && ((dtoken) == token_) && ((check) || IsConstTrue(force))) \ |
| 1931 | ECHECK(TryTypedValue(name, dtoken, check, e, req, &match)) |
| 1932 | #define TRY_ECHECK(dtoken, check, req) IF_ECHECK_(false, dtoken, check, req) |
| 1933 | #define FORCE_ECHECK(dtoken, check, req) IF_ECHECK_(true, dtoken, check, req) |
| 1934 | // clang-format on |
| 1935 | |
| 1936 | if (is_tok_ident || is_tok_string) { |
| 1937 | const auto kTokenStringOrIdent = token_; |
| 1938 | // The string type is a most probable type, check it first. |
| 1939 | TRY_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING, |
| 1940 | BASE_TYPE_STRING); |
| 1941 | |
| 1942 | // avoid escaped and non-ascii in the string |
| 1943 | if (!match && is_tok_string && IsScalar(in_type) && |
| 1944 | !attr_is_trivial_ascii_string_) { |
| 1945 | return Error( |
| 1946 | std::string("type mismatch or invalid value, an initializer of " |
| 1947 | "non-string field must be trivial ASCII string: type: ") + |
| 1948 | kTypeNames[in_type] + ", name: " + (name ? *name : "") + |
| 1949 | ", value: " + attribute_); |
| 1950 | } |
| 1951 | |
| 1952 | // A boolean as true/false. Boolean as Integer check below. |
| 1953 | if (!match && IsBool(in_type)) { |
| 1954 | auto is_true = attribute_ == "true"; |
| 1955 | if (is_true || attribute_ == "false") { |
| 1956 | attribute_ = is_true ? "1" : "0"; |
| 1957 | // accepts both kTokenStringConstant and kTokenIdentifier |
| 1958 | TRY_ECHECK(kTokenStringOrIdent, IsBool(in_type), BASE_TYPE_BOOL); |
| 1959 | } |
| 1960 | } |
| 1961 | // Check for optional scalars. |
| 1962 | if (!match && IsScalar(in_type) && attribute_ == "null") { |
| 1963 | e.constant = "null"; |
| 1964 | NEXT(); |
| 1965 | match = true; |
| 1966 | } |