Celestia

Форк
0
/
parser.cpp 
246 строк · 6.3 Кб
1
// parser.cpp
2
//
3
// Copyright (C) 2001-2019, the Celestia Development Team
4
// Original version by Chris Laurel <claurel@gmail.com>
5
//
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.
10
#include <map>
11
#include <string_view>
12
#include <utility>
13
#include <variant>
14

15
#include <celastro/units.h>
16
#include <celutil/tokenizer.h>
17
#include "parser.h"
18

19
using namespace std::string_view_literals;
20

21
namespace astro = celestia::astro;
22

23
namespace
24
{
25

26
using MeasurementUnit = std::variant<std::monostate,
27
                                     astro::LengthUnit,
28
                                     astro::TimeUnit,
29
                                     astro::AngleUnit,
30
                                     astro::MassUnit>;
31

32
class UnitsVisitor
33
{
34
public:
35
    explicit UnitsVisitor(Value::Units* _units) : units(_units) {}
36

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; }
42

43
private:
44
    Value::Units* units;
45
};
46

47

48
MeasurementUnit parseUnit(std::string_view name)
49
{
50
    static const std::map<std::string_view, MeasurementUnit>* unitMap = nullptr;
51

52
    if (!unitMap)
53
    {
54
        unitMap = new std::map<std::string_view, MeasurementUnit>
55
        {
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 },
66

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 },
72

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 },
79

80
            { "kg"sv, astro::MassUnit::Kilogram },
81
            { "mE"sv, astro::MassUnit::EarthMass },
82
            { "mJ"sv, astro::MassUnit::JupiterMass },
83
        };
84
    }
85

86
    auto it = unitMap->find(name);
87
    return it == unitMap->end()
88
        ? MeasurementUnit(std::in_place_type<std::monostate>)
89
        : it->second;
90
}
91

92

93
Value::Units readUnits(Tokenizer& tokenizer)
94
{
95
    Value::Units units;
96

97
    if (tokenizer.nextToken() != Tokenizer::TokenBeginUnits)
98
    {
99
        tokenizer.pushBack();
100
        return units;
101
    }
102

103
    UnitsVisitor visitor(&units);
104

105
    while (tokenizer.nextToken() != Tokenizer::TokenEndUnits)
106
    {
107
        auto tokenValue = tokenizer.getNameValue();
108
        if (!tokenValue.has_value()) { continue; }
109

110
        MeasurementUnit unit = parseUnit(*tokenValue);
111
        std::visit(visitor, unit);
112
    }
113

114
    return units;
115
}
116

117
} // end unnamed namespace
118

119

120
/****** Parser method implementation ******/
121

122
Parser::Parser(Tokenizer* _tokenizer) :
123
    tokenizer(_tokenizer)
124
{
125
}
126

127

128
std::unique_ptr<ValueArray> Parser::readArray()
129
{
130
    Tokenizer::TokenType tok = tokenizer->nextToken();
131
    if (tok != Tokenizer::TokenBeginArray)
132
    {
133
        tokenizer->pushBack();
134
        return nullptr;
135
    }
136

137
    auto array = std::make_unique<ValueArray>();
138

139
    Value v = readValue();
140
    while (!v.isNull())
141
    {
142
        array->push_back(std::move(v));
143
        v = readValue();
144
    }
145

146
    tok = tokenizer->nextToken();
147
    if (tok != Tokenizer::TokenEndArray)
148
    {
149
        tokenizer->pushBack();
150
        return nullptr;
151
    }
152

153
    return array;
154
}
155

156

157
std::unique_ptr<Hash> Parser::readHash()
158
{
159
    Tokenizer::TokenType tok = tokenizer->nextToken();
160
    if (tok != Tokenizer::TokenBeginGroup)
161
    {
162
        tokenizer->pushBack();
163
        return nullptr;
164
    }
165

166
    auto hash = std::make_unique<Hash>();
167

168
    tok = tokenizer->nextToken();
169
    while (tok != Tokenizer::TokenEndGroup)
170
    {
171
        std::string name;
172
        if (auto tokenValue = tokenizer->getNameValue(); tokenValue.has_value())
173
        {
174
            name = *tokenValue;
175
        }
176
        else
177
        {
178
            tokenizer->pushBack();
179
            return nullptr;
180
        }
181

182
        Value::Units units = readUnits(*tokenizer);
183

184
        Value value = readValue();
185
        if (value.isNull())
186
        {
187
            return nullptr;
188
        }
189

190
        value.setUnits(units);
191
        hash->addValue(std::move(name), std::move(value));
192

193
        tok = tokenizer->nextToken();
194
    }
195

196
    return hash;
197
}
198

199

200
Value Parser::readValue()
201
{
202
    Tokenizer::TokenType tok = tokenizer->nextToken();
203
    switch (tok)
204
    {
205
    case Tokenizer::TokenNumber:
206
        return Value(*tokenizer->getNumberValue());
207

208
    case Tokenizer::TokenString:
209
        return Value(*tokenizer->getStringValue());
210

211
    case Tokenizer::TokenName:
212
        if (tokenizer->getNameValue() == "false")
213
            return Value(false);
214
        else if (tokenizer->getNameValue() == "true")
215
            return Value(true);
216
        else
217
        {
218
            tokenizer->pushBack();
219
            return Value();
220
        }
221

222
    case Tokenizer::TokenBeginArray:
223
        tokenizer->pushBack();
224
        {
225
            std::unique_ptr<ValueArray> array = readArray();
226
            if (array == nullptr)
227
                return Value();
228
            else
229
                return Value(std::move(array));
230
        }
231

232
    case Tokenizer::TokenBeginGroup:
233
        tokenizer->pushBack();
234
        {
235
            std::unique_ptr<Hash> hash = readHash();
236
            if (hash == nullptr)
237
                return Value();
238
            else
239
                return Value(std::move(hash));
240
        }
241

242
    default:
243
        tokenizer->pushBack();
244
        return Value();
245
    }
246
}
247

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.