среда, 8 июля 2015 г.

ToDo. Избавиться от [EXECUTE]


Вот в таком виде:

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'ов.

Ну и понятно, что бумажки это скорее "скетчи" и наброски, а электронные документы - более развёрнуты.

Одно другому не мешает. А дополняет.

Бумажки это в первую очередь - ЧТО СДЕЛАТЬ, а электронные документы - КАК ДЕЛАТЬ.

Ну такие приоритеты.

На бумажке можно очень быстро и гибко записать "сиюминутную мысль", а в электронном документе - развить её и подробнее описать.

И ещё я начал нумеровать бумажки. Сквозной нумерацией.

Чтобы можно было ссылаться на них из электронных документов.

Но тут ест "парадокс" - если нумеруешь бумажки, то их НЕЛЬЗЯ выкидывать.

Ибо на них есть ссылки.

Можно видимо "перекладывать" в "ящик стола".

;-)

Комментариев нет:

Отправить комментарий