3
// Copyright (C) 2001-2019, the Celestia Development Team
4
// Original version by Chris Laurel <claurel@gmail.com>
6
// This program is free software; you can redistribute it and/or
7
// modify it under the terms of the GNU General Public License
8
// as published by the Free Software Foundation; either version 2
9
// of the License, or (at your option) any later version.
15
#include <celastro/units.h>
16
#include <celutil/tokenizer.h>
19
using namespace std::string_view_literals;
21
namespace astro = celestia::astro;
26
using MeasurementUnit = std::variant<std::monostate,
35
explicit UnitsVisitor(Value::Units* _units) : units(_units) {}
37
void operator()(std::monostate) const { /* nothing to update */ }
38
void operator()(astro::LengthUnit unit) const { units->length = unit; }
39
void operator()(astro::TimeUnit unit) const { units->time = unit; }
40
void operator()(astro::AngleUnit unit) const { units->angle = unit; }
41
void operator()(astro::MassUnit unit) const { units->mass = unit; }
48
MeasurementUnit parseUnit(std::string_view name)
50
static const std::map<std::string_view, MeasurementUnit>* unitMap = nullptr;
54
unitMap = new std::map<std::string_view, MeasurementUnit>
56
{ "km"sv, astro::LengthUnit::Kilometer },
57
{ "m"sv, astro::LengthUnit::Meter },
58
{ "rE"sv, astro::LengthUnit::EarthRadius },
59
{ "rJ"sv, astro::LengthUnit::JupiterRadius },
60
{ "rS"sv, astro::LengthUnit::SolarRadius },
61
{ "AU"sv, astro::LengthUnit::AstronomicalUnit },
62
{ "ly"sv, astro::LengthUnit::LightYear },
63
{ "pc"sv, astro::LengthUnit::Parsec },
64
{ "kpc"sv, astro::LengthUnit::Kiloparsec },
65
{ "Mpc"sv, astro::LengthUnit::Megaparsec },
67
{ "s"sv, astro::TimeUnit::Second },
68
{ "min"sv, astro::TimeUnit::Minute },
69
{ "h"sv, astro::TimeUnit::Hour },
70
{ "d"sv, astro::TimeUnit::Day },
71
{ "y"sv, astro::TimeUnit::JulianYear },
73
{ "mas"sv, astro::AngleUnit::Milliarcsecond },
74
{ "arcsec"sv, astro::AngleUnit::Arcsecond },
75
{ "arcmin"sv, astro::AngleUnit::Arcminute },
76
{ "deg"sv, astro::AngleUnit::Degree },
77
{ "hRA"sv, astro::AngleUnit::Hour },
78
{ "rad"sv, astro::AngleUnit::Radian },
80
{ "kg"sv, astro::MassUnit::Kilogram },
81
{ "mE"sv, astro::MassUnit::EarthMass },
82
{ "mJ"sv, astro::MassUnit::JupiterMass },
86
auto it = unitMap->find(name);
87
return it == unitMap->end()
88
? MeasurementUnit(std::in_place_type<std::monostate>)
93
Value::Units readUnits(Tokenizer& tokenizer)
97
if (tokenizer.nextToken() != Tokenizer::TokenBeginUnits)
103
UnitsVisitor visitor(&units);
105
while (tokenizer.nextToken() != Tokenizer::TokenEndUnits)
107
auto tokenValue = tokenizer.getNameValue();
108
if (!tokenValue.has_value()) { continue; }
110
MeasurementUnit unit = parseUnit(*tokenValue);
111
std::visit(visitor, unit);
117
} // end unnamed namespace
120
/****** Parser method implementation ******/
122
Parser::Parser(Tokenizer* _tokenizer) :
123
tokenizer(_tokenizer)
128
std::unique_ptr<ValueArray> Parser::readArray()
130
Tokenizer::TokenType tok = tokenizer->nextToken();
131
if (tok != Tokenizer::TokenBeginArray)
133
tokenizer->pushBack();
137
auto array = std::make_unique<ValueArray>();
139
Value v = readValue();
142
array->push_back(std::move(v));
146
tok = tokenizer->nextToken();
147
if (tok != Tokenizer::TokenEndArray)
149
tokenizer->pushBack();
157
std::unique_ptr<Hash> Parser::readHash()
159
Tokenizer::TokenType tok = tokenizer->nextToken();
160
if (tok != Tokenizer::TokenBeginGroup)
162
tokenizer->pushBack();
166
auto hash = std::make_unique<Hash>();
168
tok = tokenizer->nextToken();
169
while (tok != Tokenizer::TokenEndGroup)
172
if (auto tokenValue = tokenizer->getNameValue(); tokenValue.has_value())
178
tokenizer->pushBack();
182
Value::Units units = readUnits(*tokenizer);
184
Value value = readValue();
190
value.setUnits(units);
191
hash->addValue(std::move(name), std::move(value));
193
tok = tokenizer->nextToken();
200
Value Parser::readValue()
202
Tokenizer::TokenType tok = tokenizer->nextToken();
205
case Tokenizer::TokenNumber:
206
return Value(*tokenizer->getNumberValue());
208
case Tokenizer::TokenString:
209
return Value(*tokenizer->getStringValue());
211
case Tokenizer::TokenName:
212
if (tokenizer->getNameValue() == "false")
214
else if (tokenizer->getNameValue() == "true")
218
tokenizer->pushBack();
222
case Tokenizer::TokenBeginArray:
223
tokenizer->pushBack();
225
std::unique_ptr<ValueArray> array = readArray();
226
if (array == nullptr)
229
return Value(std::move(array));
232
case Tokenizer::TokenBeginGroup:
233
tokenizer->pushBack();
235
std::unique_ptr<Hash> hash = readHash();
239
return Value(std::move(hash));
243
tokenizer->pushBack();