В настоящее время я разрабатываю свой собственный язык программирования. Кодовая (в Lua) состоит из нескольких модулей, а именно:Lua Spaghetti Modules
- первый, error.lua, не имеет зависимостей;
- lexer.lua зависит только от ошибки.lua;
- prototypes.lua также не имеет зависимости;
- parser.lua, вместо этого, зависит от всех модулей выше;
- interpreter.lua - это точка опоры всей кодовой базы. Это зависит от error.lua, parser.lua и memory.lua;
- memory.lua зависит от functions.lua;
- , наконец, functions.lua зависит от memory.lua и interpreter.lua. Это требуется изнутри memory.lua, поэтому мы можем сказать, что memory.lua также зависит от interpreter.lua.
С «А зависит от Б» Я имею в виду, что функции, объявленные в потребность, объявленных в B.
Реальная проблема, однако, когда А зависит от B, которая зависит от А, что, как вы можете понять из приведенного выше списка, довольно часто происходит в моем коде.
Чтобы дать конкретный пример моей проблемы, вот как interpreter.lua выглядит следующим образом:
--first, I require the modules that DON'T depend on interpreter.lua
local parser, Error = table.unpack(require("parser"))
--(since error.lua is needed both in the lexer, parser and interpreter module,
--I only actually require it once in lexer.lua and then pass its result around)
--Then, I should require memory.lua. But since memory.lua and
--functions.lua need some functions from interpreter.lua to work, I just
--forward declare the variables needed from those functions and then those functions themself:
--forward declaration
local globals, new_memory, my_nil, interpret_statement
--functions I need to declare before requiring memory.lua
local function interpret_block()
--uses interpret_statement and new_memory
end
local function interpret_expresion()
--uses new_memory, Error and my_nil
end
--Now I can safely require memory.lua:
globals, new_memory, my_nil = require("memory.lua")(interpret_block, interpret_espression)
--(I'll explain why it returns a function to call later)
--Then I have to fulfill the forward declaration of interpret_executement:
function interpret_executement()
--uses interpret_expression, new_memory and Error
end
--finally, the result is a function
return function()
--uses parser, new_fuction and globals
end
Модуль memory.lua возвращает функцию, так что он может получить interpret_block
и interpret_expression
в качестве аргументов, как это:
--memory.lua
return function(interpret_block, interpret_expression)
--declaration of globals, new_memory, my_nil
return globals, new_memory, my_nil
end
Теперь у меня появилась идея форвардных деклараций here и что из функций-как-модулей (например, в memory.lua, чтобы передать некоторые функции из модуля, требующего до требуемого модуля) here. Все они великие идеи, и я должен сказать, что они работают очень. Но вы платите в удобочитаемости.
На самом деле, разбив кусочки меньшего размера, код на этот раз заставил мою работу усерднее, если бы я закодировал все в одном файле, что невозможно для меня, потому что это более 1000 строк кода, и я кодирование с помощью смартфона.
Чувство, которое у меня есть, - это работа с кодом спагетти, только в большем масштабе.
Итак, как я могу решить проблему непонятного моего кода из-за того, что некоторые модули нуждаются друг в друге (что не требует, чтобы все переменные были глобальными, конечно)? Как программисты на других языках решают эту проблему? Как я должен реорганизовать свои модули? Существуют ли стандартные правила использования модулей Lua, которые также могут помочь мне в решении этой проблемы?
Вау, я так и не ожидал ответа. В настоящее время проблема заключается в следующем: интерпретатор -> функции -> память <-> переводчик. Теперь я собираюсь проанализировать подмножества, как вы объяснили, и посмотреть, могу ли я что-то извлечь из этого. – user6245072
Желаю вам удачи в этом, пожалуйста, дайте мне знать результат. –
О, спасибо. Я остановился сосредоточиться только на модулях, и теперь я создаю дерево зависимостей функций. – user6245072