Вот в таком виде:
IMMEDIATE operator [EXECUTE] ^ IN aCode aCode DO ; // [EXECUTE]
Заменить на инициализацию глобальных переменных и IMMEDIATE OPERATOR.
Это нужно, чтобы компилированный код был детерминирован.
Чтобы можно было кешировать компилированные словари.
Примеры:
Test TestCompileValue STRING VAR S [EXECUTE] ( S := 'Hello' ) S := 'World' INTEGER VAR I [EXECUTE] ( I := 20 ) I := 30 [EXECUTE] ( I CompileValue ) . [EXECUTE] ( S CompileValue ) . OBJECT VAR O [EXECUTE] ( O := @ . ) [EXECUTE] ( S CompileValue O CompileValue ) [EXECUTE] ( 'сч сч сч' CompileValue @ . CompileValue ) 'сч сч сч 2' [EXECUTE] ( @ . CompileValue ) I . S . ; // TestCompileValue TestCompileValue ... Тест Immediate VAR A : TryVarPrint A . 10 >>> A A . ; : TryVar1 [EXECUTE] ( 1024 >>> A 'Попали в инициализацию A' . ) // - этот кусок должен выполняться ОДИН раз при компиляции скрипта TryVarPrint ; : TryVar2 1024 >>> A // - этот кусок должен выполняться КАЖДЫЙ раз при выполнении слова TryVarPrint ; TryVar1 TryVar1 TryVar2 TryVar2 TryVar1 TryVar1 ; Immediate ... INTEGER VAR g_EtalonCount [EXECUTE] ( 0 >>> g_EtalonCount ) ... INTEGER VAR g_TimerNum [EXECUTE] ( 0 >>> g_TimerNum ) ... STRING VAR tb24Name [EXECUTE] ( tb24Date '.2004' '04' string:Replace '.' '' string:Replace =: tb24Name ) STRING VAR tb27Name [EXECUTE] ( tb27Date '.2004' '04' string:Replace '.' '' string:Replace =: tb27Name ) ... INTEGER VAR Indent [EXECUTE] ( Indent := 0 ) ...
Для инициализации глобальных переменных определить секцию initialization.
А для тестов CompileValue заменить на IMMEDIATE OPERATOR.
Хотя для CompileValue можно оставить и [EXECUTE]. Оно в данном случае ничуть не хуже IMMEDIATE OPERATOR.
Возможно стоит запретить вызов [EXECUTE] ВНУТРИ словарей.
А оставить ТОЛЬКО для kwMain.
Но это ещё ВОПРОС. Надо подумать.
Как-то так:
Test TestCompileValue STRING VAR S [EXECUTE] ( S := 'Hello' ) S := 'World' INTEGER VAR I [EXECUTE] ( I := 20 ) I := 30 [EXECUTE] ( I CompileValue ) . [EXECUTE] ( S CompileValue ) . OBJECT VAR O [EXECUTE] ( O := @ . ) [EXECUTE] ( S CompileValue O CompileValue ) [EXECUTE] ( 'сч сч сч' CompileValue @ . CompileValue ) 'сч сч сч 2' [EXECUTE] ( @ . CompileValue ) I . S . ; // TestCompileValue TestCompileValue ... Тест Immediate VAR A : TryVarPrint A . 10 >>> A A . ; : TryVar1 initialization ( 1024 >>> A 'Попали в инициализацию A' . ) // - этот кусок должен выполняться ОДИН раз при компиляции скрипта TryVarPrint ; : TryVar2 1024 >>> A // - этот кусок должен выполняться КАЖДЫЙ раз при выполнении слова TryVarPrint ; TryVar1 TryVar1 TryVar2 TryVar2 TryVar1 TryVar1 ; Immediate ... INTEGER VAR g_EtalonCount initialization ( 0 >>> g_EtalonCount ) ... INTEGER VAR g_TimerNum initialization ( 0 >>> g_TimerNum ) ... STRING VAR tb24Name initialization ( tb24Date '.2004' '04' string:Replace '.' '' string:Replace =: tb24Name ) STRING VAR tb27Name initialization ( tb27Date '.2004' '04' string:Replace '.' '' string:Replace =: tb27Name ) ...
initialization выглядит примерно так:
VOID IMMEDIATE operator initialization ^ IN aCode aCode Ctx:Engine pop:ScriptEngine:AddInitialization // - тут добавляем секцию инициализации в скриптовую машину, // чтобы она её вызвала потом, когда надо ; // initialization
Чтобы скомпилировать код раз и навсегда.
Детерминированно.
Возможно ещё придётся сделать секцию finalization.
Ну и ещё выделить код:
constructor TkwCompiledFunction.Create(aWordProducer: TtfwWord; const aPrevFinder: Il3KeywordFinder; const aTypeInfo: TtfwTypeInfo; const aCtx: TtfwContext; aKey: TtfwKeyWordPrim); //#UC START# *4DC9723702F5_4F3BEDFE0051_var* var l_Var : TkwCompiledVar; l_KW : TtfwKeyWord; //#UC END# *4DC9723702F5_4F3BEDFE0051_var* begin //#UC START# *4DC9723702F5_4F3BEDFE0051_impl* l_KW := Self.CheckWord(TtfwCStringFactory.C(cResult)); l_Var := TkwCompiledVar.Create((aCtx.rEngine.As_ItfwKeywordFinder.KeywordByName[TtfwCStringFactory.C(TkwVar.NameForRegister)] As TtfwKeyWord).Word, // - чтобы обеспечить слову нужный "стереотип" // хак конечно, надо как-то константу хотя бы завести Self{nil{PrevFinder}, aTypeInfo{TtfwTypeInfo_E{Modifiers}, aCtx, l_KW); try l_KW.Word := l_Var; f_ResultVar := l_Var; f_ResultVar.SetResultTypeInfo(aTypeInfo, aCtx); if (f_Modifiers.Modifiers = [tfw_wmStr]) then f_ResultVar.SetValue(TtfwStackValue_C(TtfwCStringFactory.C('')), aCtx) else if (f_Modifiers.Modifiers = [tfw_wmInt]) then f_ResultVar.SetValue(TtfwStackValue_C(0), aCtx) else if (f_Modifiers.Modifiers = [tfw_wmIntf]) then f_ResultVar.SetValue(TtfwStackValue_NULL, aCtx) else if (f_Modifiers.Modifiers = [tfw_wmObj]) then f_ResultVar.SetValue(TtfwStackValue_NULL, aCtx); finally FreeAndNil(l_Var); end;//try..finally inherited; //#UC END# *4DC9723702F5_4F3BEDFE0051_impl* end;//TkwCompiledFunction.Create
В слово InitVar.
И вызывать этот код при создании Result (ввести TkwResultVar вместо TkwCompiledVar) и при создании TkwGlobalVar.
И если создаётся переменная ВНЕ вложенного слова, т.е. на уровне словаря или непосредственно внутри TkwMain, то создавать TkwGlobalVar, а не TkwCompiledVar.
Кстати надо переименовать TkwCompiledVar в TkwLocalVar.
Точнее для TkwGlobalVar вызывать InitVar не при создании, а при КАЖДОМ запуске компилированного кода.
Такая "автоматическая" секция инициализации (initialization) для каждой глобальной переменной.
И ещё заменить пару implementation @ XXX end. на implementation @ XXX ;
Вот тут:
StereotypeStereotypeProducer P : X1 ; : m2 ; ; <<P>> MDAClass : m1 ; : m2 ; ; <<P>> MDACategory : m1 ; : m2 ; ; <<MDAClass>> SimpleClass : m1 ; : m2 ; ; <<SimpleClass>> Tl3Base : m1 ; ; <<MDACategory>> Unit : x1 ' World' . ; : x2 ; ; IMMEDIATE operator implementation ^ IN aWordToWork Ctx:PushCompiler Ctx:PushFinder VAR l_NewCompiler aWordToWork DO =: l_NewCompiler l_NewCompiler pop:Compiler:SetToCtx l_NewCompiler pop:Finder:SetToCtx ; IMMEDIATE operator end. pop:Finder:SetToCtx pop:Compiler:SetToCtx ; implementation @ <<Unit>> : NewMethod 'Hello' . x1 ; end. : XXX 'Bang!' . ; :: <<Unit>> NewMethod ; XXX
Для этого придётся в implementation "парсить" код за ним.
ДО "скобки" ;
Зачем это нужно?
Чтобы иметь детерминированное состояние стека.
Как-то так:
IMMEDIATE operator implementation ^ IN aWordToWork Ctx:PushCompiler TRY Ctx:PushFinder TRY VAR l_NewCompiler aWordToWork DO =: l_NewCompiler l_NewCompiler pop:Compiler:SetToCtx l_NewCompiler pop:Finder:SetToCtx CompileCodeTill ';' FINALLY pop:Finder:SetToCtx END FINALLY pop:Compiler:SetToCtx END ;
Ну и:
Бумажки. Бумажки. Надо обязательно написать пост про бумажки
Чем хороши "бумажки"?
Вот я сейчас много чего понаписал. В "потоке сознания".
Многое обдумывать надо.
Завтра с электронного носителя перепишу всё это на бумажки и положу в стопку СНИЗУ.
С указанием "электронных ссылок".
А делать продолжу - с ВЕРХА стопки.
Реализуя задачи и выкидывая бумажки.
И обдумывая.
Пока не дойду до бумажек про этот пост.
А там может и переосмысление придёт, а может и задача утратит актуальность.
Но зато - не потеряется.
И на бумажках можно писать, черкать, рисовать.
Добавлять новые бумажки.
Писать на них ссылки к "электронным документам".
И т.д. и т.п.
Гибкость в выразительных формах - неимоверная.
В отличии от электронных документов.
Да и электронные документы бывает где-то "замыливаются", теряются.
А бумажки - вот они. ЛЕЖАТ на столе. СТОПКОЙ.
И пока задачи НЕ РЕАЛИЗОВАНЫ или НЕ ПОТЕРЯЛИ актуальности - бумажки никуда не деваются.
Они - МАТЕРИАЛЬНЫ.
Есть бумажка - есть работа. Работа сделана - бумажка выкинута в урну.
В отличии от электронных документов.
И именно НЕ тетрадка. НЕ "список ToDo".
А СТОПКА бумажек.
Она - ЗРИМА.
Не надо листать страницы.
Не надо вычёркивать.
Не надо ставить "галочку" типа "task done".
Вариантов ровно три:
1. Сделали задачу - выкинули бумажку.
2. Появилась задача - написали НОВУЮ бумажку.
3. Не дозрели до задачи - переместили бумажку в низ стопки.
Ещё раз. Стопка бумажек - ЗРИМА.
Это материальная вещь. В отличии от "электронных документов".
У меня на работе на столе стопка бумажек.
Ну и дома - ещё одна.
По разным категориям задач.
Иногда я ношу их туда-сюда.
Но скорее - пишу себе "электронную напоминалку". а потом - дублирую бумажку.
У меня на работе есть "баг-треккер" и дома есть Issues в bitbucket.
И я пытался пользоваться чем-то вроде EverNotes.
На компьютере и прочих мобильных устройствах.
Но не один раз уже понял, без "бумажек" - не обойтись.
Они гибче, оперативнее и надёжнее.
----
Что-то в бумажках есть от:
Scrum
CRC-карта
Только на "микро"-уровне. Не в команде, а "для себя лично".
Ну и понятное дело, что бумажки не отменяют электронного проектного Code & Document Flow.
Они НА РАЗНЫХ уровнях абстракции находятся.
Бумажки - для "себя".
Flow - для команды и "руководства". Ну и прочих Stakeholder'ов.
Ну и понятно, что бумажки это скорее "скетчи" и наброски, а электронные документы - более развёрнуты.
Одно другому не мешает. А дополняет.
Бумажки это в первую очередь - ЧТО СДЕЛАТЬ, а электронные документы - КАК ДЕЛАТЬ.
Ну такие приоритеты.
На бумажке можно очень быстро и гибко записать "сиюминутную мысль", а в электронном документе - развить её и подробнее описать.
И ещё я начал нумеровать бумажки. Сквозной нумерацией.
Чтобы можно было ссылаться на них из электронных документов.
Но тут ест "парадокс" - если нумеруешь бумажки, то их НЕЛЬЗЯ выкидывать.
Ибо на них есть ссылки.
Можно видимо "перекладывать" в "ящик стола".
;-)
Комментариев нет:
Отправить комментарий