Что нового

Wrapper Plys — надмножество AutoIt с пространствами имён и прочими удобствами

Spray

Новичок
Сообщения
17
Репутация
2
Версия AutoIt
3.3.14.5
Версия
0.5.0
1637651211398.png
Plys представляет собой незаметную обёртку, дополняющую язык AutoIt следующими возможностями:
  1. директива препроцессора #import "filename" загружает только публичные функции и переменные
  2. блоки кода посредством отступов в стиле Python (без endfunc, wend и т. д.)
  3. dim и const вне функций означают global и global const соответственно, внутри функций означают local и local const
  4. аргументы функций по умолчанию являются константами, но со спецификатором dim становятся изменяемыми
  5. короткие синонимы для функций, которые как правило используются в крупных проектах: для массивов, файлов и строк
  6. имена переменных без префикса «$»
  7. однострочные анонимные функции
  8. и всё это опционально

#import​

Когда сценарий разрастается до тысяч строк, его удобнее поддерживать, разбив на несколько файлов и подключая их через #include. В каждом таком файле окажутся свои функции, переменные, константы. По мере дальнейшего роста проекта таких файлов и функций становится десятки или даже сотни — возрастает вероятность, что имена из разных файлов будут совпадать и код из одного файла вмешается в работу другого. Для разрешения подобных коллизий к именам функций и переменных добавляются префиксы, уникальные для каждого файла.

Минусы такого подхода: во-первых, пользователь всё равно может «выстрелить себе в ногу», случайно или намеренно используя функцию из другого файла по имени с заданным префиксом, во-вторых, код с префиксами становится громоздким, что сказывается на читаемости, а как известно, код чаще читается, чем пишется.

Эту проблему решает #import: во-первых, он, в отличие от #include, предоставляет доступ только к публичным именам подключаемого файла (отмечаются звёздочкой в конце имени при объявлении, например const Foo* = 42), во-вторых, в подключаемом файле префиксы больше не нужны — доступ к ним из другого файла всё равно будет запрещён, пока программист явно не разрешит.

EndFunc, WEnd…​

Повторюсь: код чаще читается, чем пишется. Подобные «закрывашки» делают код громоздким. Наверняка вы видели бессмысленную и уродливую лесенку наподобие этой:
Код:
Func Foo()
    ...
                    EndSwitch
                Next
            EndIf
        WEnd
    EndIf
EndFunc

В AutoIt Plys блоки кода определяются отступами и «закрывашки» являются необязательными. Но за отступами придётся последить. И это хорошо: код без отступов читать невозможно: и постороннему программисту, и вам, если вы давно не работали с проектом. И это несложно: любой адекватный текстовый редактор для программирования автоматически делает отступы.

dim/const​

Области видимости переменных — это одна из ошибок в дизайне AutoIt. Сами авторы языка AutoIt в официальной справке предостерегают использовать dim, признают неотличимость local и global при объявлении переменных в глобальном пространстве, не рекомендуют использовать global внутри функций. Ну и, опять же, громоздкие local и global const не добавляют читаемости. В AutoIt Plys сделано проще: объявляешь вне функции — будет глобальной, объявляешь внутри — будет локальной. Просто dim для переменных и просто const для констант. Без local и без global.

Константные аргументы функций​

Константы — это удобно. Речь, конечно, про большие сценарии, в маленьких удобнее не объявлять переменные вообще. Многие значения в сценарии по логике реализуемого алгоритма должны быть неизменными, а явное указание их константами предостерегает от ошибок: если вы случайно или намеренно попытаетесь изменить величину, объявленную как константа, интерпретатор выдаст сообщение об ошибке и вы точно узнаете, что была попытка совершить операцию, противоречащую логике алгоритма. Если же всегда и без разбора использовать изменяемые переменные, такой помощи со стороны интерпретатора уже не будет.

AutoIt Plys воспринимает аргументы функций по умолчанию как константы, преследуя вышеописанную цель: помочь пользователю в обнаружении ошибок. Да, в чистом AutoIt можно явно указать const перед именем аргумента, но об этом как правило забывают, да и, опять же, дополнительные префиксы не добавляют коду читаемости.
Зачем эти навороты в простом скриптовом языке AutoIt? Почему бы просто не перейти на Python/Ruby/Lua/Basic? AutoIt чертовски хорош, и даже если сценарий разрастается до тысяч строк не всегда хочется и резонно переходить на более серьёзную платформу. Впрочем, использовать AutoIt Plys не менее приятно и для коротких сценариев: использовать его крайне легко и прослойка максимально незаметна для пользователя.

Обзор​

Код:
; файл mylib.aup

dim foo*, bar

func baz*()
    foo = quux()

func quux(dim arg="one/two/three")
    bar = Sort(Split(arg, "/", @NoCount))
    return "begin" . @ . bar[0] . @ . "end"

Код:
; файл main.aup

#import "mylib.aup"
…

В этом примере переменная bar и функция quux() приватные для модуля mylib.aup (их имена в объявлении заканчиваются звёздочкой) и невидимы в main.aup. Переменная foo и функция baz() будут видимы с префиксом mylib:

Код:
; файл main.aup

#import "mylib.aup"

foo = baz()  ; ошибка: в этом пространстве foo и baz() не объявлены
mylib:foo = mylib:baz()  ; порядок: foo baz() являются публичными в пространстве mylib
mylib:bar = mylib:quux()  ; ошибка: bar и quux() являются приватными в пространстве mylib

Sort — это синоним для _ArraySort, Split — это синоним для StringSplit, @NoCount — это синоним для $STR_NOCOUNT, “@” — это синоним для @CRLF, “.” — это синоним для оператора “&”.
Add ColDelete ColInsert Combinations Display Extract FindAll Insert Max MaxIndex Min MinIndex Permute Pop Push Search Shuffle Sort Swap ToClip Transpose Trim Unique → _Array*
ToHist → _Array1DToHistogram
BinSearch → _ArrayBinarySearch
Concat → _ArrayConcatenate

ChangeDir Copy CreateShortcut Flush GetAttrib GetEncoding GetLongName GetShortcut GetShortName GetSize GetTime GetVersion Open Opendialog Read ReadLine ReadToArray Recycle RecycleEmpty SaveDialog SelectFolder SetAttrib SetEnd SetPos SetTime Write WriteLine → File*
CreateLink → FileCreateNTFSLink
FirstFile → FileFindFirstFile
NextFile → FileFindNextFile

Struct → DllStructCreate
StructGet → DllStructGetData
StructGetSize → DllStructGetSize
StructGetPtr → DllStructGetPtr
StructSet → DllStructSetData

Echo → ConsoleWrite

AddCR Format InStr IsAlNum IsAlpha IsASCII IsDigit IsLower IsSpace IsUpper IsX⁠Digit Left Len Lower Mid Replace Right Split StripCR StripWS TrimLeft TrimRight Upper → String*
ReFind → StringRegExp
ReReplace → StringRegExpReplace

Activate Active Flash GetCaretPos GetClassList GetClientSize GetProcess GetTitle Kill List MenuSelectItem MinimizeAll MinimizeAllUndo SetOnTop SetTitle SetTrans Wait WaitActive WaitClose WaitNotActive → Win*

@ReMatch → $STR_REGEXPMATCH
@ReArray @ReArrayFull @reArrayGlobal @reArrayGlobalFull → $STR_REGEXP*MATCH

@NoCaseSense @CaseSense @NoCaseSenseBasic @StripLeading @StripTrailing @StripSpaces @StripAll @ChrSplit @EntireSplit @NoCount @EndNotStart @UTF16 @USC2 → $STR_*

@ → @CRLF
@ActiveWin → WinGetHandle("[ACTIVE]")
@CmdLine → $CmdLine

. → &
.= → &=

Установка​

Требования: AutoIt (минимум), AutoIt Script Editor (опционально).
  1. Скачайте и распакуйте архив из последнего выпуска.
  2. Дважды щёлкните по файлу setup.aup.au3 и следуйте инструкциям установки.

Первые шаги​

  1. Щёлкните правой кнопкой в любой папке и выберите New > AutoIt Plys Script.
  2. Щёлкните правой кнопкой по созданному файлу и выберите Edit Script.
  3. В конце содержимого файла напечатайте следующее:
    1. Код:
      #include <MsgBoxConstants.au3>
      dim msg = ""
      for i = 1 to 10
          msg .= "Hello World!" . @
      msg = TrimRight(msg, 1)
      MsgBox(MB_OK, "My First Plys Script", msg)
  4. Сохраните сценарий и щёлкните дважды по файлу для запуска (или щёлкните правой кнопкой по файлу и выберите Run Script).

Дополнительные опции​

Вы можете использовать дополнительные опции, добавив в сценарий одну из следующих директив:

Код:
#plys dollarprefix  ; запретить использование переменных без префикса «$»
#plys noconst  ; использовать поведение по умолчанию для объявлений переменных
#plys noindent  ; игнорировать отступы, но требовать использование endif, wend и т. п.
#plys noimport  ; запретить оператор import
#plys nosynonyms  ; запретить синонимы для функций и макро
#plys nolambda  ; запретить анонимные функции

Окружение​

После установки Plys уже будет встроен в оболочку Windows (запуск по двойному щелчку, контекстное меню). Если вы хотите запускать ваш сценарий через командную строку, используйте следующую команду
<AutoIt3.exe path> <AutoIt3exe folder>\Plys\plys.aup.au3 [/Rapid] [/ErrorStdOut] [/NoStdio] <script path> [<arguments>]

/Rapid означает, что если исходные файлы не были изменены с предыдущего запуска, они не будут перетранслированы. Эта опция повышает скорость запуска сценария.

Опция /ErrorStdOut позволяет перенаправить сообщения о фатальных ошибках в StdOut, чтобы их можно было поймать приложением.

Также вы можете отключить обмен данными через стандартные потоки ввода/вывода, тогда процесс-обёртка не будет потреблять память, но тогда вы не сможете наблюдать вывод вашей программы в окне вывода вашей среды разработки. Это делается добавлением опции /NoStdio.

Если вы хотите перевести сценарий в чистый AutoIt-код, используйте
<AutoIt3.exe path> <AutoIt3exe folder>\Plys\plys.aup.au3 [/Translate] <script path>

Попробуйте пакет AutoIt Plys для Sublime Text, который включает в себя подсветку синтаксиса, авто-дополнение, систему сборки для запуска и компиляции, контекстную справку, переход к определению, включение комментария по горячей клавише, команды Tidy и Include Helper для AutoIt и AutoIt Plys.

1636772507367.png

Вы можете скомпилировать сценарий, указав компилятору переведённый файл *.aup.au3.

Как это работает​

Файл plys.aup.au3 содержит код, который запускается сразу же при запуске вашего сценария. При установке этот файл копируется в папку с установленным AutoIt (как Plys\plys.aup.au3) и файлы *.aup ассоциируются с ним. Во время запуска aup-файлов они автоматически обрабатываются, после чего новый процесс AutoIt интерпретирует уже сконвертированный код, и текущий процесс остаётся в цикле для продолжения обмена данными с новым процессом посредством стандартных потоков. Этот обработчик заменяет все #import директивой #include. Обработанные файлы получают расширение .aup.au3 и помещаются в папку исходного сценария с атрибутом «скрытый».

Будущее​

  • #import "filename.aup" noprefix
Код:
#import "mylib.aup" noprefix

bar = foo()
; bar и foo будут взяты из mylib.aup без префикса mylib:

  • #import "filename.aup" as alias
Код:
#import "mylib.aup" as ml

ml:bar = ml:foo()  ; bar и foo будут взяты из mylib.aup

  • функции внутри функций
Код:
func GlobalFunc()
    dim var1 = "body"
    func LocalFunc(var2)
        return "begin" . @ . var2 . @ . "end"
    return LocalFunc(LocalFunc(var1))

MsgBox(MB_OK, "begin/body/end", GlobalFunc())

  • значения-массивы «на месте»
Код:
a = [3, 7, 1]
for i in [1, 2, 4]
    Echo(i . @)
    Display([t*3 for t in a if t > i])  ; if i = 2 then Display([9, 21]) etc.


Скачать
 
Последнее редактирование:
Автор
Spray

Spray

Новичок
Сообщения
17
Репутация
2
Re: Обёртка, имитирующая область видимости «файл»

Сейчас работаю над версией, которая будет не в виде обёртки, которую нужно прикручивать к запуску/компиляции, а будет активироваться при простом включении через #include. Как ей пользоваться:

[list type=decimal]
[*]скопировать файл FileScope.au3 в папку Include
[*]включить его в стартовый файл вашей программы (#include <FileScope.au3>)
[*]файлы проекта, которые также нужно обработать, включить через #import "MyLib.au3"
[*]запускать программу в обход AutoIt3Wrapper или с отключением проверки кода
[/list]

MyProg.au3
Код:
#AutoIt3Wrapper_Run_AU3Check=N
#include <FileScope.au3>
#import "MyLib.au3"

global $_private = MyLib_foo () ; Ура, конфликта с повторным объявлением не будет!

ConsoleWrite ($_private) ; В SciTE произойдёт вывод в окно Output!


MyLib.au3
Код:
global $_private = 10

func MyLib_foo ()
    return $_private
endfunc


Для чего всё это нужно? (3) — если включать файлы через обычный #include, то при запуске интерпретатор AutoIt сразу найдёт повторные объявления и приостановит выполнение. (4) — AutoIt3Wrapper предварительно проверяет код, поэтому будет ругаться на все функции из библиотек, «включаемых» по #import, ибо он проигнорирует директиву и просто не найдёт соответствующих объявлении.

Как это работает? Во включаемом FileScope.au3 находится код, который приводится в действие сразу же по запуску вашей программы: автоматически обрабатываются файлы, после чего запускается новый процесс AutoIt, интерпретирующий уже преобразованный код, а текущий процесс остаётся крутиться в цикле, чтобы продолжать обмен данными с новым процессом через стандартные потоки. Обработке подлежат только файлы, включаемые по #import. Обработчик комментирует строчку #include <FileScope.au3> во избежание рекурсии, а все #import заменяет на обычный #include. Обработанные файлы получают расширение .auf и помещаются в папку исходного сценария.

Следующий этап

Новая задача: имитация оператора import наподобие того, как это сделано в Python. А именно:
  • «импортированные» публичные функции (т. е. без подчёркивания в начале) должны быть тоже «зашифрованы» для сокрытия от лишних глаз, чтобы видели их только те, кто импортирует файл напрямую
first.au3:
Код:
#AutoIt3Wrapper_Run_AU3Check=N
#include <import>
#import "second.au3"


second.au3:
Код:
#import "third.au3"
#import "fourth.au3"

публичные из third.au3 не должны быть видны ни в first.au3, ни в fourth.au3, только в second.au3 (и для себя, конечно)
  • возможность импортировать публичные функции как есть (будут доступны по оригинальным именам) либо заданной приставкой
Код:
#AutoIt3Wrapper_Run_AU3Check=N
#include <import>
#import "foo.au3" as is
#import "bar.au3" with MyPrefix

FuncFromFoo ()
MyPrefix_FuncFromBar ()
FuncFromBar () ; ошибка
 

Вложения

  • FileScope.au3
    4.9 КБ · Просмотры: 10

Mute

Новичок
Сообщения
7
Репутация
0
Спасибо, очень пригодился скрипт
 
Автор
Spray

Spray

Новичок
Сообщения
17
Репутация
2
Spray сказал(а):
Следующий этап

Новая задача: имитация оператора import наподобие того, как это сделано в Python. А именно:
  • «импортированные» публичные функции (т. е. без подчёркивания в начале) должны быть тоже «зашифрованы» для сокрытия от лишних глаз, чтобы видели их только те, кто импортирует файл напрямую
  • возможность импортировать публичные функции как есть (будут доступны по оригинальным именам) либо заданной приставкой

Задача оказалась непростой. Вот моё решение для упрощённой модели.

  • Имеется дерево зависимостей, заданное массивом $DepsOf, каждый индекс которого соответствует файлу, а каждое значение — массив зависимостей файла.
    Код:
    const $deps_of_1 [2] = [2, -3]
    const $deps_of_2 [0] = []
    const $deps_of_3 [0] = []
    const $DepsOf = [3, $deps_of_1, $deps_of_2, $deps_of_3]

    Это значит, что дерево состоит из трёх файлов: 1 зависит от 2 и 3, а 2 и 3 не имеют зависимостей. Причём 1 связан с 2 через обычный #include, а с 3 — через #import.
    [box]2 <− [1] => 3

    1: #include "2", #import "3"…
    2: …
    3: …
    [/box]


  • Задача: по данным массива $DepsOf сгенерировать массив $SeersOf, каждый индекс которого соответствует файлу, но каждое значение — массив зависимых файлов, которые должны видеть содержимое этого файла. Т. е. для примера выше на выходе должно получиться
    Код:
    $SeersOf = [3, [2], [1], [-1, -2]]

    Это значит, что для трёх файлов:
    [list type=decimal]
  • все имена из 1 должны быть видны в 2, но не в 3
  • все имена из 2 должны быть видны в 1, но не в 3
  • публичные имена из 3 должны быть видны и в 1, и в 2.
Все имена из 1 должны быть видны в 2 (п. 1) неспроста, т. к. 2 по сути «слеплен» с 1 через #include. То же относится и к п. 3: 2 как часть 1 импортит 3, а значит тоже должен видеть его публичные имена.
Код:
#include <Array.au3>

global const $EMPTY [0] = []
global enum $INCLUDE, $IMPORT

local const $deps_of_1 [3] = [-2, -3, -5]
local const $deps_of_2 [2] = [4, -5]
local const $deps_of_3 [2] = [6, 9]
local const $deps_of_4 [1] = [-7]
local const $deps_of_5 [3] = [-4, 8, -9]
local const $deps_of_6 [1] = [9]
local const $deps_of_7 [1] = [-5]
local const $deps_of_8 [0] = []
local const $deps_of_9 [0] = []
global const $DepsOf = [9, $deps_of_1, $deps_of_2, $deps_of_3, $deps_of_4, $deps_of_5, $deps_of_6, $deps_of_7, $deps_of_8, $deps_of_9]

; init seers table
global $SeersOf = [0]; seers table: index is module number, element is array of seers, [0] is count of elements
append_seers (1, $EMPTY)

capture_seers (1)
for $i = 1 to $SeersOf [0]
	ConsoleWrite ($i & ": " & _ArrayToString ($SeersOf [$i], ", ") & @CRLF)
next

func capture_seers ($module, $host=0, $character=$INCLUDE)
; capture seers and return seers from dependencies

	; 1: 2 -3 --> [A: B -C]
	if $host <> 0 then
		switch $character
		case $INCLUDE
			; append seers from host (1, 2, -3) to module A
			local $seers_from_host = $SeersOf [$host] ; add 2 and -3
			_ArrayAdd ($seers_from_host, $host) ; add 1
		case $IMPORT
			; append seers from host (-1, -2) to module A
			local $seers_from_host = [-$host] ; add 1 as -1
			for $seer in $SeersOf [$host]
				if character ($seer) = $INCLUDE then _ArrayAdd ($seers_from_host, -$seer); add 2 as -2
			next
		endswitch
	else
		local $seers_from_host [0]
	endif
	
	; [A: B -C] --> X: Y -Z
	local $seers_from_deps [0]
	if append_seers ($module, $seers_from_host) or $host = 0 then
		if UBound ($DepsOf [$module]) then
			local $ascndn_seers_of_dep
			local $appended = False
			do ; recursive traversal and append seers from dependencies (X) to module A
				for $dep in $DepsOf [$module]
					$ascndn_seers_of_dep = capture_seers (Abs ($dep), $module, character ($dep))
					if character ($dep) = $INCLUDE then
						_ArrayConcatenate ($seers_from_deps, $ascndn_seers_of_dep)
						_ArrayAdd ($seers_from_deps, $dep)
					endif
				next
				$appended = append_seers ($module, $seers_from_deps)
			until not $appended
		endif
	endif
	return ($character=$INCLUDE) ? $seers_from_deps : $EMPTY
	
endfunc

func append_seers (const $module)
; return True if $SeersOf changed else False
	if $module > $SeersOf [0] then
		redim $SeersOf [$module + 1]
		$SeersOf [0] = $module
	endif
	if not IsArray ($SeersOf [$module]) then $SeersOf [$module] = $EMPTY
	if not UBound ($new_seers) then return False
	; exclude self
		_ArrayDelete ($new_seers, _ArraySearch ($new_seers, $module))
		_ArrayDelete ($new_seers, _ArraySearch ($new_seers, -$module))
	if not UBound ($new_seers) then return False
	; extend $SeersOf if needed
	local $seers = $SeersOf [$module]
	_ArrayConcatenate ($seers, $new_seers)
	$seers = ArrayUnique ($seers)
	if UBound ($seers) = UBound ($SeersOf [$module]) then
		local $changed = False
		for $i = 0 to UBound ($seers) - 1
			if $seers [$i] <> ($SeersOf [$module]) [$i] then
				$changed = True
				exitloop
			endif
		next
		if not $changed then return False
	endif
	$SeersOf [$module] = $seers
	return True
endfunc

func character (const $dep)
	return ($dep > 0) ? $INCLUDE : $IMPORT
endfunc

func ArrayUnique (const byref $array)
	local $result [0], $found, $size
	for $src_val in $array
		$found = False
		for $i = 0 to UBound ($result) - 1
			if Abs ($src_val) = Abs ($result [$i]) then
				if $src_val > $result [$i] then $result [$i] = $src_val
				$found = True
				exitloop
			endif
		next
		if not $found then
			$size = UBound ($result)
			redim $result [$size + 1]
			$result [$size] = $src_val
		endif
	next
	return $result
endfunc



[*]
После того как массив $SeersOf сгенерирован, останется зашифровать имена в каждом файле и такие же имена в тех файлах, которые от него зависят (в случае зависимости через #import — только публичные).


[/list]
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Это интересно конечно, но мне кажется оно не стоит того чтобы заморачиваться.
Код нужно писать предотвращая ошибки на ходу, а не исправляя уже созданные.
Если мне нужно использовать стороннюю библиотеку где автор не продумал этот нюанс, то я поправлю библиотеку, это делается двумя заменами по рег. выражению (по Ctrl + H):

1:
Код:
Ищем:
Global\s+\$\(\w+\)
заменяем на:
Global $LIB_Prefix_\1

2:
Код:
Ищем:
^\s*Func\s+_?\(\w+\)
заменяем на:
Func _LIB_Prefix_\1
 
Автор
Spray

Spray

Новичок
Сообщения
17
Репутация
2
CreatoR сказал(а):
Это интересно конечно, но мне кажется оно не стоит того чтобы заморачиваться.
Код нужно писать предотвращая ошибки на ходу, а не исправляя уже созданные.
Если мне нужно использовать стороннюю библиотеку где автор не продумал этот нюанс, то я поправлю библиотеку, это делается двумя заменами по рег. выражению

Отчасти заморочки, отчасти весьма удобно в практике. У меня к тому же и научно-эстетический интерес, в дополнение к практическому.
Но, во-первых, повторюсь, код с префиксами выглядит громоздко, особенно когда программа часто обращается к этим именам, во-вторых, твоё решение с заменой по регуляркам будет сложно применить, когда библиотека будет состоять из нескольких взаимозависимых файлов. Я как раз с такой ситуацией столкнулся, когда библиотека в разных файлах более чем на 1000 строк, и программа, использующая функции этой библиотеки, сама такая же.
Но главное: решение нацелено на разработку собственных библиотек, а не улучшение уже написанных сторонних. Это не исправление ошибок, а изменение стиля программирования: не беспокоиться о префиксах и больше сил оставить на архитектурные задачи.
 
Последнее редактирование:

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
Spray
чем сложнее инструмент, тем больше вероятность бага.
Верно сказано, что сразу делается проверка на ошибки и исправляется.
Лично я ни разу не сталкивался с одинаковыми именами функций. Понял еще одну вещь, что без нужды лучше не плодить глобальные переменные
для более чистой проверки кода использую http://autoit-script.ru/index.php?topic=3925.msg123627#msg123627
потому что редактор не всегда выдает предупреждения, а когда все собрано в один файл, тогда проще просканировать код.
правда, использую немного модифицированный вариант, чтобы результат сохранить в файл
Код:
#include <WinAPIFiles.au3>

Global $sAutoItExe = @AutoItExe ;Should be 3.3.12.0 / 3.3.9.4 / 3.3.8.X / 3.3.6.X
;Global $sAutoItExe = 'D:\AutoIt_Versions\AutoIt_3.3.12.0\AutoIt3.exe'

Local $sFile = FileOpenDialog('Select script file (source from your compiled script)...', @ScriptDir, 'AutoIt v3 Script (*.au3)')
If @error Then Exit

SplashTextOn('Generating error code line', 'Please wait...', 200, 50, -1, -1, BitOR(16, 32), '', 12, 800)
$sCodeLine = _AU3_GetErrLineCode($sFile)
SplashOff()

Func _AU3_GetErrLineCode($sScript_File, $iLine = 0)
	Local $sSrc_Raw, $iPos1, $iPos2, $iLen
	$sSrc_Raw = _AU3_StripToRaw($sScript_File)
	If @error Then
		Return SetError(1, 0, '')
	EndIf
	$sSrc_Raw = StringStripWS($sSrc_Raw, 3)
	FileWrite($sScript_File & '.Strip.au3',$sSrc_Raw)
EndFunc
конечно, если это все для тренировки ума, то можно продолжать совершенствоваться.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Spray [?]
твоё решение с заменой по регуляркам будет сложно применить, когда библиотека будет состоять из нескольких взаимозависимых файлов
Для этого я и написал FindEx )) (странно что я её не выкладывал ранее), который встраивается в оболочку SciTE.

Это не исправление ошибок, а изменение стиля программирования, как бы на диалекте AutoIt с дополнительной особенностью, где можно забить на префиксы и чуть больше сил оставить на архитектурные задачи.
У меня не уходят силы на префиксы так как это вошло в привычку, я считаю что как раз таки это и является стильным программированием )).
 
Автор
Spray

Spray

Новичок
Сообщения
17
Репутация
2
Модульное программирование, инкапсуляция — не слышали? Вы точно программисты?)
 
Последнее редактирование:
A

Alofa

Гость
Spray сказал(а):
... Вам по приколу префиксы в ваших библиотеках...
OffTopic:
Дело тут не в префиксах, а в порядке. Порядок должен быть везде, в том числе и в голове.
То что вы тут пытаетесь сотворить - это есть "костыль", расслабляющий и затуманивающий мозг Кодера. Когда случись не будет под рукой подобного инструмента то он (Кодер) потеряется [но это чисто ИМХО].



Добавлено:
Сообщение автоматически объединено:

Spray сказал(а):
OffTopic:
Да, да и ваше. Это чисто наши мнения.
Так что успехов Вам в ваших начинаниях
.
 
Автор
Spray

Spray

Новичок
Сообщения
17
Репутация
2
Spray сказал(а):
Следующий этап

Новая задача: имитация оператора import наподобие того, как это сделано в Python. А именно:
  • «импортированные» публичные функции (т. е. без подчёркивания в начале) должны быть тоже «зашифрованы» для сокрытия от лишних глаз, чтобы видели их только те, кто импортирует файл напрямую
  • возможность импортировать публичные функции как есть (будут доступны по оригинальным именам) либо заданной приставкой

Задача решена! Правда алгоритм другой: надоело мучиться с рекурсией и стал хранить зависимости в виде таблицы $DepTable [номер файла][номер зависимости], которая дополняется до [номер файла][номер видимого].

Например, для зависимости main.au3 => module1.au3 -> module2.au3 исходная таблица:
Код:
  | 0           1   2   3
--+-−-−-−-−-−-−-−-−-−-−-−-−
0 | 3
1 | main.au3        1
2 | module1.au3         2
3 | module2.au3
Это значит, что в файле main.au3 есть строчка #import "module1.au3" (значение 1 в ячейке [1][2]), а в файле module1.au3 есть строчка #include "module2.au3" (значение 2 в ячейке [2][3]).

Далее таблица обрабатывается согласно определённым правилам, и на выходе получается:
Код:
  | 0           1   2   3
--+-−-−-−-−-−-−-−-−-−-−-−-−
0 | 3
1 | main.au3        1   1
2 | module1.au3         2
3 | module2.au3     1.5
Это значит, что файлу main.au3 должны быть видны публичные имена из module2.au3 (значение 1 в ячейке [1][3]), а файлу module2.au3 тоже должны быть видны имена из module1.au3 (значение 1.5 в ячейке [2][1]).

Кроме того, создаётся массив уникальных «суффиксов», предотвращающих намеренное обращение к скрываемым именам, а в нулевую строку массива $DepTable помещаются массивы имён, объявленных в соответствующих файлах.

После всех этих предварительных процедур во всех файлах происходит подмена имён, а результат записывается в файлы с расширением .fs.au3


Как пользоваться этой библиотекой

[list type=decimal]
[*]Поместите файл «import» в папку с библиотекой AutoIt (c:\Program Files (x86)\AutoIt3\Include\).
[*]В самое начало вашей программы добавьте строки
Код:
#AutoIt3Wrapper_Run_AU3Check=N
#include <import>

[*]После чего, если у вас есть файлы mylib1.au3 и mylib2.au3 с одинаковыми именами
Код:
global $bar
func foo()
endfunc

вы сможете написать в своей программе так
Код:
#import "mylib1.au3"
#import "mylib2.au3"
mylib1:$bar = mylib2:foo()
#import "mylib2.au3" ; повторный import файлов без «#include-once» не приведёт к ошибкам
[/list]

Можно отключить обмен данными через стандартные потоки ввода вывода, тогда в памяти не будет висеть процесс-оболочка, но тогда вы не сможете наблюдать вывод вашей программы в окне вывода вашей среды разработки. Сделать это можно, добавив в главный файл вашей программы строку
Код:
#import: no stdio exchange


Можно вообще отключить автозапуск вашей программы, оставив только генерацию исполняемых файлов, например, для дальнейшей компиляции, добавив в главный файл вашей программы строку
Код:
#import: no run

После чего можно будет скомпилировать программу, указав компилятору получившийся файл main.fs.au3, если главный файл вашей программы называется main.au3.

Обработка файлов довольно тупая, так что возможны баги.


Следующий этап

Код:
#import from "mylib.au3"
$bar = foo() ; bar и foo будут взяты из библиотеки mylib


Код:
#import "mylib.au3" as ml
ml:$bar = ml:foo() ; bar и foo будут взяты из библиотеки mylib
 

Вложения

  • import.zip
    3.1 КБ · Просмотры: 1

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
За всю историю моей работы с аутоит, у меня всего один раз была необходимость использовать такие методы, чтобы протестировать сложные библиотеки из них самих используя функции с главного скрипта...
Вопрос вот в чём, как это всё будет себя вести при компиляции?
 
Автор
Spray

Spray

Новичок
Сообщения
17
Репутация
2
CreatoR сказал(а):
Вопрос вот в чём, как это всё будет себя вести при компиляции?
С компиляцией никаких проблем. В результате работы сценария создаются файлы с расширением .fs.au3. По сути, это набор готовых к выполнению сценариев на чистом AutoIt. Допустим, запускаемый файл программы называется main.au3, тогда среди выходных будет файл main.fs.au3. Чтобы получить рабочий исполняемый файл, нужно всего лишь передать компилятору файл main.fs.au3.
 
Последнее редактирование:

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
Перечитал еще раз, так и не понял: для чего все это. Автор, можно ну ученическом языке объяснить? Или, может, кто другой объяснит пользу этого?
 

InnI

AutoIT Гуру
Сообщения
4,911
Репутация
1,427
joiner [?]
может, кто другой объяснит пользу этого
Никакой практической пользы здесь нет. Автор так и пишет:
Spray [?]
заморочки. У меня больше научно-эстетический интерес, нежели практический



Spray
Если я правильно понял, идея заключалась в отказе от префиксов. Но в итоге вы к ним и вернулись:
было
Код:
#include "mylib.au3"
$mylib_bar = mylib_foo()

стало
Код:
#import "mylib.au3"
mylib:$bar = mylib:foo()
;)
 
Автор
Spray

Spray

Новичок
Сообщения
17
Репутация
2
joiner сказал(а):
Перечитал еще раз, так и не понял: для чего все это. Автор, можно ну ученическом языке объяснить? Или, может, кто другой объяснит пользу этого?
Польза проявляется в программах со сложной архитектурой, с множеством самописных библиотек в тысячи строк.
Недостатки эмуляции пространств имён с помощью префиксов типа __MyLib_foo перечислены здесь https://ru.wikipedia.org/wiki/Пространство_имён_(программирование)#Эмуляция_пространств_имён
Ещё немного про модульное программирование https://ru.wikipedia.org/wiki/Модульное_программирование

На самом деле лучший способ понять, зачем это — изучить язык программирования, поддерживающий модульность на уровне синтаксиса, и писать действительно сложные программы, особенно во взаимодействии с множеством групп программистов.


Добавлено:
Сообщение автоматически объединено:

InnI сказал(а):
Spray
Если я правильно понял, идея заключалась в отказе от префиксов. Но в итоге вы к ним и вернулись:
было
Код:
#include "mylib.au3"
$mylib_bar = mylib_foo()

стало
Код:
#import "mylib.au3"
mylib:$bar = mylib:foo()
;)

Отнюдь:

Spray сказал(а):
После чего, если у вас есть файл mylib.au3
Код:
global $bar
func foo()
endfunc

Вы поняли неправильно — предлагается отказ от префиксов внутри библиотек, а не при их использовании. Прошу вас, будьте внимательнее.
 
Последнее редактирование:

InnI

AutoIT Гуру
Сообщения
4,911
Репутация
1,427
Spray [?]
если не владеете темой, не засоряйте обсуждение критикой
Ну извините, что мы тут пытаемся понять, зачем AutoIt нужна "модульность на уровне синтаксиса", тем более, что этот язык не разрабатывался для того, чтобы на нём "писать действительно сложные программы, особенно во взаимодействии с множеством групп программистов". Для этого есть другие языки, а AutoIt - это лишь язык автоматизации и создания несложных программ-утилит. Поэтому у него и синтаксис соответствующий и многопоточность отсутствует и быстродействие оставляет желать лучшего.
Но, всё равно, хочу пожелать вам удачи. Дополнительная функциональность, хоть и сомнительная, уж точно не повредит :beer:
 

joiner

Модератор
Локальный модератор
Сообщения
3,556
Репутация
628
Думаю, что данную идею можно озвучить на официальном форуме. Там часто разрабы участвуют в обсуждении. Может и нарисуется какая то конкретика.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Spray [?]
С компиляцией никаких проблем
Следует указать, что для корректности необходимо хотя бы один раз запустить исходный скрипт прежде чем его можно компилировать.

joiner [?]
Думаю, что данную идею можно озвучить на официальном форуме. Там часто разрабы участвуют в обсуждении. Может и нарисуется какая то конкретика.
Подобное уже делалось и обсуждалось не раз. Я сам давно пытался усовершенствовать язык потратить своё время впустую, в результате чего, всем что придумал (в стиле данной тематики), никогда так и не пользовался.

Удачи автору, подобное занятие очень хорошо развивает мозг.
 
Автор
Spray

Spray

Новичок
Сообщения
17
Репутация
2
Изменения

Отключение обмена данными через стандартные потоки ввода вывода:
Код:
#import: no stdio exchange


Отключение автозапуска, только генерация исполняемых файлов:
Код:
#import: no run

Чтобы скомпилировать программу, нужно указать компилятору получившийся файл main.fs.au3, если главный файл вашей программы называется main.au3.

Повторное импортирование модулей, в которых отсутствует директива «#include-once», не приведёт к ошибкам.
Код:
#import "mylib.au3"
#import "mylib.au3" ; OK



30 марта 2019
Исправлено: обёртка работает в режиме чувствительности к регистру вместо нечувствительности (находит «local …», но не «Local …»).
Критично! Алгоритм работал некорректно со сценариями, написанными в общепринятом стиле (!), когда ключевые слова начинаются с заглавной буквы.

2 июня 2019
Масштабное обновление!

  • Добавлено: возможность обозначать блоки кода в стиле Python — посредством отступов (без endfunc, wend и т. п.)
  • Добавлено: dim и const вне функций означают global и global const соответственно, внутри функций означают local и local const
  • Добавлено: аргументы функций по умолчанию становятся константами, но с префиксом dim становятся изменяемыми (переменными)
  • Добавлено: короткие синонимы для функций, которые как правило используются в больших проектах: для массивов, файлов и строк
14 июня 2019
  • Добавлено: можно не использовать префикс «$» в именах переменных

Версия 0.4.0​

  • Переписано на Plys
  • Добавлено: автоматическая установка
  • Добавлено: интеграция в оболочку. Запуск и трансляция в AutoIt по двойному щелчку или через контекстное меню
  • Изменено: имена публикуются через суффикс * (звёздочка) в объявлении вместо приватизации через _ (подчёркивание) в начале имени
  • Добавлено: синонимы для операторов/макро &, &= и @CRLF
  • Добавлено: лямбда (анонимные) функции

Версия 0.4.3​

  • Добавлено: скомпилированная HTML справка с примерами (aup-файлами)

Версия 0.5.0​

  • Добавлено: опция быстрого запуска /Rapid
  • Добавлено: подстановки макро @ScriptFullPath, @ScriptName and @ScriptLineNumber
  • Добавлено: макро @PlysPath and @PlysVersion
  • Добавлено: поддержка Юникода для потоков stderr и stdout
  • Добавлено: обработка сообщения в окне ошибки, всплывающей подсказки и иконки в области уведомлений
  • Изменено: алгоритм трансляции для лучшей производительности
  • Изменено: Plys-опции для каждого файла
  • Изменено: ключ командной строки /NoStdio вместо «#plys nostdio» в строке сценария
  • Изменено: возможность использовать анонимные функции включена по умолчанию
  • Исправлено: преобразование табуляций в пробелы не работает
  • Исправлено: добавляется префикс «$» у ключевого слова «until»
  • Исправлено: неправильная нумерация строк
  • Исправлено: лишний endif после однострочного if..then и уменьшения отступа
 
Последнее редактирование:
Верх