4
Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,
6
https://bmstu.codes/lsx/simodo/loom
9
#include "ScriptAnalyzer.h"
10
#include "simodo/interpret/AnalyzeException.h"
11
#include "simodo/inout/convert/functions.h"
12
#include "simodo/inout/format/fmt.h"
14
#include "simodo/interpret/StackOfNames.h"
18
namespace simodo::interpret
22
SemanticDataCollector_null null_collector;
25
ScriptAnalyzer::ScriptAnalyzer(ModuleManagement_interface & module_management)
26
: ScriptSemantics_abstract(module_management)
27
, _collector(null_collector)
31
ScriptAnalyzer::ScriptAnalyzer(ModuleManagement_interface & module_management, SemanticDataCollector_interface & collector)
32
: ScriptSemantics_abstract(module_management)
33
, _collector(collector)
37
bool ScriptAnalyzer::checkInterpretType(InterpretType interpret_type) const
39
return interpret_type == InterpretType::Analyzer;
42
InterpretState ScriptAnalyzer::performOperation(const ast::Node & op)
46
return ScriptSemantics_abstract::performOperation(op);
48
catch(const AnalyzeException & e)
50
inter().reporter().reportError(e.location(), e.what());
51
_number_of_mistakes ++;
53
catch(const bormental::DrBormental & e)
55
const ast::Node * node_p = inter().lookupOperationNode();
56
inout::Location loc = node_p
57
? node_p->token().makeLocation(inter().files())
58
: inout::null_location;
60
inter().reporter().reportWarning(
62
inout::fmt("Danger of error '%1'").arg(e.what()));
64
catch(const std::exception & e)
66
const ast::Node * node_p = inter().lookupOperationNode();
67
inout::Location loc = node_p
68
? node_p->token().makeLocation(inter().files())
69
: inout::null_location;
71
inter().reporter().reportWarning(
73
inout::fmt("Danger of error '%1'").arg(e.what()));
76
if (_number_of_mistakes >= MAX_NUMBER_OF_MISTAKES)
77
throw AnalyzeException("ScriptAnalyzer::performOperation",
78
op.token().makeLocation(inter().files()),
79
inout::fmt("The number of errors has exceeded the allowable limit"));
81
return InterpretState::Flow;
84
InterpretState ScriptAnalyzer::before_start()
86
return ScriptSemantics_abstract::before_start();
89
InterpretState ScriptAnalyzer::before_finish(InterpretState state)
91
return ScriptSemantics_abstract::before_finish(state);
94
/// \note Код оставил закомментированным в надежде на оптимизацию в будущем
95
// InterpretState ScriptAnalyzer::executePushVariable(const inout::Token & variable_name)
97
// InterpretState state = ScriptSemantics_abstract::executePushVariable(variable_name);
98
// const variable::Variable & var = inter().table().variable(inter().table().top());
100
// if (!var.origin().name().isError())
101
// _collector.collectNameUsed(var.origin(), variable_name.location());
106
/// \note Код оставил закомментированным в надежде на оптимизацию в будущем
107
// InterpretState ScriptAnalyzer::executeObjectElement(const ast::Node & op)
112
/// \note Код оставил закомментированным в надежде на оптимизацию в будущем
113
// InterpretState ScriptAnalyzer::executeFunctionCall(const ast::Node & op)
115
// return ScriptSemantics_abstract::executeFunctionCall(op);
118
InterpretState ScriptAnalyzer::executePrint(bool /*need_detailed_report*/)
120
inter().stack().pop();
122
return InterpretState::Flow;
125
/// \note Код оставил закомментированным в надежде на оптимизацию в будущем
126
// InterpretState ScriptAnalyzer::executeBlock(bool is_beginning_of_block, const ast::Node & op)
128
// if (is_beginning_of_block)
130
// // _collector.collectFrameBegin(op.operation_symbol().location, FrameType::CodeBlock);
132
// /// \todo Добавить сбор информации о локальных переменных
134
// // _collector.collectFrameEnd(op.operation_symbol().location);
137
// return ScriptSemantics_abstract::executeBlock(is_beginning_of_block, op);
140
InterpretState ScriptAnalyzer::executeImport(const inout::Token & path)
142
InterpretState state = ScriptSemantics_abstract::executeImport(path);
144
notifyDeclared(inter().stack().variable(inter().stack().top()));
149
InterpretState ScriptAnalyzer::executeContract(const ast::Node & op)
151
InterpretState state = ScriptSemantics_abstract::executeContract(op);
153
notifyDeclared(inter().stack().variable(inter().stack().top()));
158
/// \note Код оставил закомментированным в надежде на оптимизацию в будущем
159
// InterpretState ScriptAnalyzer::executeDeclaration(const ast::Node & op)
161
// InterpretState state = ScriptSemantics_abstract::executeDeclaration(op);
163
// // notifyDeclared(inter().table().variable(inter().table().top()));
165
// // assert(stack().index_over_top() > 0);
167
// // const variable::Variable & v = stack().variable(stack().top());
168
// // _declared.back() = v.name();
173
InterpretState ScriptAnalyzer::executeDeclarationCompletion()
175
InterpretState state = ScriptSemantics_abstract::executeDeclarationCompletion();
180
InterpretState ScriptAnalyzer::executeFunctionDefinitionEnd(const ast::Node & op)
182
name_index_t function_index = stack().top();
183
const variable::Variable & function_variable = stack().variable(function_index).origin();
185
if (function_variable.type() == variable::ValueType::Null)
186
return InterpretState::Flow;
188
assert(function_variable.type() == variable::ValueType::Function);
190
const std::shared_ptr<variable::Object> function_object = function_variable.value().getObject();
191
assert(function_object->variables().size() >= 2);
193
_functions_for_analyze.push_back(function_variable);
195
return ScriptSemantics_abstract::executeFunctionDefinitionEnd(op);
198
/// \note Код оставил закомментированным в надежде на оптимизацию в будущем
199
// InterpretState ScriptAnalyzer::executePostAssignment(const ast::Node & op)
201
// InterpretState state = ScriptSemantics_abstract::executePostAssignment(op);
203
// // checkFunctions();
208
InterpretState ScriptAnalyzer::executeCheckState(const ast::Node & op)
212
return ScriptSemantics_abstract::executeCheckState(op);
215
/// \note Код оставил закомментированным в надежде на оптимизацию в будущем
216
// InterpretState ScriptAnalyzer::executeAssignment(const ast::Node & op)
218
// InterpretState state = ScriptSemantics_abstract::executeAssignment(op);
220
// name_index_t var_index = stack().top();
221
// const variable::Variable & var = stack().variable(var_index).origin();
223
// if (var.origin().value().isFunction()) {
224
// eraseFunction(var.origin());
225
// _functions_for_analyze.push_back(var.origin());
231
InterpretState ScriptAnalyzer::executeConditional(ScriptOperationCode code, const ast::Node & op_true, const ast::Node * op_false)
233
name_index_t condition_index = stack().top();
234
variable::Variable condition_variable = stack().variable(condition_index).origin();
238
if (condition_variable.type() != variable::ValueType::Bool
239
&& !condition_variable.value().isError()) {
240
condition_variable = inter().expr().convertVariable(condition_variable, variable::ValueType::Bool);
242
if (condition_variable.value().isError())
243
return InterpretState::Flow;
246
inter().stack().pop();
248
inter().addFlowLayer(op_true,
249
[this, op_false](const FlowLayerInfo &)
252
inter().addFlowLayer(*op_false);
255
return InterpretState::Flow;
259
if (code == ScriptOperationCode::Ternary)
260
inter().stack().pop(inter().stack().top() - condition_index);
265
return InterpretState::Flow;
268
void ScriptAnalyzer::notifyDeclared(const variable::Variable & var)
270
_collector.collectNameDeclared(var);
273
void ScriptAnalyzer::notifyInitiated(const variable::Variable & var)
275
_collector.collectNameInitiated(var);
277
if (var.origin().value().isFunction()) {
278
eraseFunction(var.origin());
279
_functions_for_analyze.push_back(var.origin());
283
void ScriptAnalyzer::notifyNameUsed(const variable::Variable & variable, const inout::TokenLocation & location)
285
_collector.collectNameUsed(variable, location);
288
void ScriptAnalyzer::notifyRef(const inout::Token & token, const std::u16string & ref)
290
_collector.collectRef(token, ref);
293
void ScriptAnalyzer::notifyBeforeFunctionCalling(const variable::Variable & function)
295
eraseFunction(function);
298
void ScriptAnalyzer::notifyRemoteFunctionLaunch(const inout::TokenLocation & location)
300
_collector.collectRemoteFunctionLaunch(location);
303
void ScriptAnalyzer::checkFunctions()
305
while(!_functions_for_analyze.empty()) {
306
variable::Variable function_variable = _functions_for_analyze.back();
307
_functions_for_analyze.pop_back();
309
assert(function_variable.type() == variable::ValueType::Function);
311
std::shared_ptr<variable::Object> function_object = function_variable.value().getObject();
312
assert(function_object->variables().size() >= 2);
314
stack().push(function_variable);
316
variable::Variable & function_core = function_object->getVariableByIndex_mutable(0);
317
variable::InternalFunction & internal_function =
318
const_cast<variable::InternalFunction &>(std::get<variable::InternalFunction>(function_core.value().variant()));
319
boundary_index_t boundary_index = stack().startBoundary(BoundScope::Local, BOUNDARY_MARK_FUNCTION_FRAME);
321
/// \note Тут можно пересобирать self, чтобы были видны все члены модуля.
322
/// Но это не совсем корректно (и почему-то не работает).
323
/// Оставил этот код закомментированным, пока.
324
// internal_function.parent = inter().expr().makeSelf();
326
for(size_t i=2; i < function_object->variables().size(); ++i) {
327
const variable::Variable & v = function_object->variables()[i];
328
inter().stack().push(v);
331
const variable::Value & tethered_value = function_variable.origin().spec().object()->find(variable::SPEC_TETHERED);
333
if (tethered_value.isBool() && tethered_value.getBool()) {
334
boundary_index_t module_bound_index = stack().findNearestMarkedBoundary(BOUNDARY_MARK_MODULE_FRAME, BoundScope::Global);
335
assert(module_bound_index != UNDEFINED_BOUNDARY_INDEX);
336
const auto [begin,end] = stack().boundaryLowAndTop(module_bound_index);
337
for(name_index_t i = begin; i < end; ++i)
338
stack().pushRef(stack().variable(i), function_variable.location());
341
for(const variable::Variable & closure : internal_function.closures.variables()) {
342
if (closure.name() == SELF_VARIABLE_NAME) {
343
/// \note `self` обрабатывается "хардкодом" в executePushVariable
344
/// Здесь код пока оставил закомментированным
345
// assert(internal_function.parent);
346
// variable::Variable self = { SELF_VARIABLE_NAME, internal_function.parent, closure.location() };
347
// inter().stack().push(self);
348
// notifyDeclared(self);
351
inter().stack().push(closure);
353
// notifyNameUsed(closure, closure.location());
356
variable::Variable declared_return_variable = function_object->variables()[1];
357
variable::ValueType declared_return_type = declared_return_variable.type();
358
inout::TokenLocation function_location = declared_return_variable.location();
360
inter().stack().setBoundaryToGlobal(boundary_index);
361
inter().expr().setReturnValue({variable::ValueType::Null});
362
inter().addFlowLayer(
363
*internal_function.code,
365
[this, boundary_index, declared_return_type, function_location](const FlowLayerInfo & flow)
367
inter().stack().clearBoundary(boundary_index);
368
inter().stack().pop();
373
if (declared_return_type != variable::ValueType::Null
374
&& inter().expr().return_value().isNull() && !inter().expr().return_value().isError())
375
throw AnalyzeException("ScriptSemantics_abstract::executeReturn",
376
function_location.makeLocation(inter().files()),
377
inout::fmt("The function must return a value"));
382
void ScriptAnalyzer::eraseFunction(const variable::Variable & function)
384
if (!function.value().isFunction())
387
auto it = std::find_if(_functions_for_analyze.begin(), _functions_for_analyze.end(),
388
[function](const variable::Variable & f)
390
return f.value().isFunction() && f.value().getFunction().get() == function.value().getFunction().get();
393
if (it != _functions_for_analyze.end())
394
_functions_for_analyze.erase(it);