Гость
Форумы / Caché, Ensemble, DeepSee, MiniM, IRIS, GT.M [игнор отключен] [закрыт для гостей] / Макросы / 20 сообщений из 20, страница 1 из 1
11.05.2015, 17:48
    #38955847
eduard93
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
Есть 3 вопроса по макросам

1. Можно как-то генерировать многострочные макросы?
2. Использую#define TestMacro ##SafeExpression($$aa^B())для генерирации COS кода. Как достичь аналогичного результата с использованием методов классов?
Например (не компилируется):#define TestMacro2 ##SafeExpression(##class(App.Gen).GenCOS()))Есть вариант с#define TestMacro3 ##function($ClassMethod("App.Test","GenCOS"))Но хотелось бы просто писать ##class(App.Gen).GenCOS()
3. Возможно передать в макрос произвольное количество аргументов? Как args... только для макросов.
...
Рейтинг: 0 / 0
11.05.2015, 21:56
    #38955947
DAiMor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
eduard931. Можно как-то генерировать многострочные макросы? ##continue


2. ##expression и ##safeexpression с использованием кода из класса в mac коде работает, из другого класса кстати тоже без проблем. Может все таки ошибку компиляции приложишь, а так только гадание на кофейной гуще получается.

eduard933. Возможно передать в макрос произвольное количество аргументов? Как args... только для макросов.
# def1arg
...
Рейтинг: 0 / 0
11.05.2015, 23:07
    #38955969
eduard93
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
DAiMor,

1. Ошибся, имеется в виду в коде, вызываемом макросом. Хочу, чтобы он возвращал несколько строк кода, а не одну как в методе GetString.
2. Код:Class App.Test Extends %RegisteredObject
{

ClassMethod Test()
{
  #define Hello(%in) ##safeexpression(##class(App.Test).GetString(%in))
  w $$$Hello("abc")
}

ClassMethod GetString(str)
{
  q "Hello "_str
}

}Выдает ошибку:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
---------------------------
Studio
---------------------------
ОШИБКА #5475: Ошибка при компиляции программы: App.Test.1.  Ошибок:  App.Test.1.INT(8) ERROR #1026: Invalid command : '}' : Offset:14 [zTest+1^App.Test.1]

  > ОШИБКА #5030: Возникла ошибка при компиляции класса App.Test
---------------------------
ОК   
---------------------------
Посмотрел на int код и нашел ошибку - генерируется строка без кавычек:
Код: sql
1.
w Hello abc


Как это исправить? Попробовал добавить ##Quote над ##safeexpression, но тогда генерируется w "##safeexpression(##class(App.Test).GetString(""abc""))"
Думал, что решилС помощью модификации метода GetString:

ClassMethod GetString(str)
{
  q """Hello "_str_""
}

Но при компиляции вылезают ошибки. Сравнить с компиляцией после

ClassMethod GetString(str)
{
  q """Hello "_str_""""
}
Возможно решить это с помощью макросов?

3. Спасибо, то что надо.
...
Рейтинг: 0 / 0
11.05.2015, 23:25
    #38955974
DAiMor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
ClassMethod GetString(str)
{
    quit """Hello: "_str_""""
}#define hello(%str) ##expression(##class(User.Test).GetString(%str))
    w $$$hello("John")
...
Рейтинг: 0 / 0
11.05.2015, 23:50
    #38955981
eduard93
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
DAiMor,

Заработало, но разве ##safeexpression и ##expression не должны иметь одинаковое поведение при одном классе?

Docs - http://docs.intersystems.com/cache20151/csp/docbook/DocBook.UI.Page.cls?KEY=GCOS_macros#GCOS_C5959 When a method contains an ##Expression this is detected when the class is compiled. Because the compiler does not parse the content of the ##Expression, this ##Expression could generate different code in a subclass. To avoid this, Cache causes the compiler to regenerate the method code for each subclass. For example, ##Expression(%classname) inserts the current classname; when you compile a subclass, the code expects it will insert the subclass classname. Cache forces this method to be regenerated in the subclass to ensure that this occurs.
If you know that the code will never be different in a subclass, you can avoid regenerating the method for each subclass. To do this, substitute the ##SafeExpression preprocessor directive for ##Expression. These two preprocessor directives are otherwise identical.

Добавление ещё одной кавычки в GetString вижу.
...
Рейтинг: 0 / 0
12.05.2015, 07:59
    #38956029
DAiMor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
eduard931. Ошибся, имеется в виду в коде, вызываемом макросом. Хочу, чтобы он возвращал несколько строк кода, а не одну как в методе GetString.похоже, что так сделать не получится почему то компилятор при получении многострочного результата ругается на то что ожидается конец строки.
...
Рейтинг: 0 / 0
12.05.2015, 07:59
    #38956031
DAiMor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
eduard93Заработало, но разве ##safeexpression и ##expression не должны иметь одинаковое поведение при одном классе?а разве это не так ?
...
Рейтинг: 0 / 0
12.05.2015, 09:19
    #38956070
servit
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
eduard931. Ошибся, имеется в виду в коде, вызываемом макросом. Хочу, чтобы он возвращал несколько строк кода, а не одну как в методе GetString.Используйте CodeMode = objectgenerator
eduard932.Class App.Test Extends %RegisteredObject
{

ClassMethod Test()
{
  #define Hello1(%in) ##safeexpression(##class(App.Test).GetString1(%in))
  #define Hello2(%in) ##safeexpression(##class(App.Test).GetString2(%in))
  
  w $$$Hello1("abc")
  w $$$Hello2("abc")
}

ClassMethod GetString1(str) As %String [ CodeMode = expression ]
{
$$$quote("Hello ")_"_"_$$$quote(str)
}

ClassMethod GetString2(str) As %String [ CodeMode = expression ]
{
$$$quote("Hello "_str)
}

}РезультатzTest() public {
  w "Hello "_"abc"
  w "Hello abc" }
...
Рейтинг: 0 / 0
13.05.2015, 21:10
    #38958034
eduard93
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
servitИспользуйте CodeMode = objectgeneratorКак его использовать для генерации кода в макросе?

Вот например нужен макрос - написать строку n раз:Class App.Test Extends %RegisteredObject
{

ClassMethod Test()
{
  #define WriteNTimes(%str,%cnt) ##safeexpression(##class(App.Test).GenStrings(%str,%cnt))
  $$$WriteNTimes("Hello World!",2)
}

ClassMethod GenStrings(string As %String = "", count As %Integer = 1) [ CodeMode = objectgenerator ]
{
  For i = 1:1:$g(count,0) {
     Do %code.WriteLine(" Write """ _ $g(string) _ """,!")
  }  
    Quit $$$OK
}
}При компиляции ошибка:Studio
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
---------------------------
Studio
---------------------------
ОШИБКА #5475: Ошибка при компиляции программы: App.Test:Test.  Ошибок:  

ERROR:  App.Test.1(4) : MPP5646 : завершение  ##expression  с ошибкой: $ze=##class(App.Test).GenStrings("Hello World!",2)

 TEXT: 	##safeexpression(##class(App.Test).GenStrings("Hello World!",2)) }
---------------------------
ОК   
---------------------------

Ещё такой вопрос: возможны ли необязательные аргументы в макросах:ClassMethod UnrequiredArgs()
{
  #define Log(%lvl,%msg) w "Level: ",%lvl,!,"Message: ",$g(%msg),!
  $$$Log(0,"It's a message!")
  $$$Log(0)
}Ошибка.Studio
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
---------------------------
Studio
---------------------------
ОШИБКА #5475: Ошибка при компиляции программы: App.Test:UnrequiredArgs.  Ошибок:  

ERROR:  App.Test.1(5) : MPP5614 : Недостаточно аргументов в макросе: 'Log'

 TEXT: 	$$$Log(0) }
---------------------------
ОК   
---------------------------
Код прилагается, вызов: do ##class(App.Test).Test()
 do ##class(App.Test).UnrequiredArgs()
...
Рейтинг: 0 / 0
14.05.2015, 13:45
    #38958623
servit
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
eduard93Как его использовать для генерации кода в макросе?В макросе - никак. Генерация нескольких строк - это уже целая программа, что противоречит концепции простой одностроковой подстановки: Conventions for Macro Values .
К тому же в этом случае возникают доп. вопросы, например с метками.eduard93Вот например нужен макрос - написать строку n раз:У Вас вперемешку run-time и compile-time.
Например, так:Class App.Test [ Abstract ]
{

Parameter count = 2;

Parameter string = "Hello World!";

ClassMethod Test()
{
  d ..WriteNTimes1(),..WriteNTimes2(),..WriteNTimes3(),..UnrequiredArgs()
}

/// управление через параметры класса
ClassMethod WriteNTimes1() [ CodeMode = objectgenerator ]
{
  For i = 1:1:$G(%parameter("count"),0) {
    Do %code.WriteLine($$$FormatText(" Write %1,!",$$$quote($G(%parameter("string")))))
  }
}

/// управление непосредственно
ClassMethod WriteNTimes2() [ CodeMode = objectgenerator ]
{
  For i = 1:1:4 {
    Do %code.WriteLine($$$FormatText(" Write %1,!",$$$quote(i_" : "_i)))
  }
}

/// управление через глобалы
ClassMethod WriteNTimes3() [ CodeMode = objectgenerator ]
{
  #Execute s ^count=5,^string="test"
  /*
  до компиляции ^count и ^string должны уже содержать нужные значения
  */
  For i = 1:1:$G(^count,0) {
    Do %code.WriteLine($$$FormatText(" Write %1,!",$$$quote($G(^string))))
  }
}

ClassMethod UnrequiredArgs() [ PlaceAfter = WriteNTimes3 ]
{
  #def1arg Log(%args) ##safeexpression("w "_##Quote("Level: ")_","_$li(%literalargs,1)_",!,"_##Quote("Message: ")_","_$s($ll(%literalargs)>1:$li(%literalargs,2),1:##Quote(""))_",!")
  #def1arg Log1(%args) ##safeexpression(##class(App.Test).Log(%literalargs))
  
  $$$Log(0,"It's a message!")
  $$$Log(0)
  $$$Log1(,,,"asd")
  $$$Log1("","",,,,,"asd")
}

ClassMethod Log(list As %List) As %String [ PlaceAfter = UnrequiredArgs ]
{
  s lvl=$li(list,1)
  s msg=$s($ll(list)>1:$li(list,2),1:"")
  s:lvl="" lvl=$$$quote(lvl)
  s:msg="" msg=$$$quote(msg)

  q "w "_##Quote("Level: ")_","_lvl_",!,"_##Quote("Message: ")_","_msg_",!"
}

}Результат компиляции:zTest() public {
  d ..WriteNTimes1(),..WriteNTimes2(),..WriteNTimes3(),..UnrequiredArgs() }
zWriteNTimes1() public {
 Write "Hello World!",!
 Write "Hello World!",! }
zWriteNTimes2() public {
 Write "1 : 1",!
 Write "2 : 2",!
 Write "3 : 3",!
 Write "4 : 4",! }
zWriteNTimes3() public {
 Write "test",!
 Write "test",!
 Write "test",!
 Write "test",!
 Write "test",! }
zUnrequiredArgs() public {
  w "Level: ",0,!,"Message: ","It's a message!",!
  w "Level: ",0,!,"Message: ","",!
  w "Level: ","",!,"Message: ","",!
  w "Level: ","",!,"Message: ","",! }
eduard93Ещё такой вопрос: возможны ли необязательные аргументы в макросах:Да, см. пример выше. Ещё здесь: 6396428 .
...
Рейтинг: 0 / 0
14.05.2015, 16:11
    #38958900
eduard93
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
servit, Спасибо.
...
Рейтинг: 0 / 0
29.05.2015, 12:33
    #38971714
servit
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
servit Макросы в InterSystems Caché eduard93Компилятор классов использует определение класса для генерации MAC кодаДокументация
  • Caché generates INT code for each routine and each class you compile.
  • источник
  • <...> Generated routines are routines which are derived or created by compiling other routines or classes. There are two types of generated routines: 1. .INT code which is created when Caché compiles a .MAC file, or a class. 2. .MAC code which is created when Caché compiles certain types of classes. источник
...
Рейтинг: 0 / 0
29.05.2015, 12:48
    #38971736
servit
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
...
Рейтинг: 0 / 0
29.05.2015, 15:06
    #38971921
servit
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
Alexey MaslovСтоило бы упомянуть и о том, что команда $$$Многострочного_Макроса должна быть единственной в строке.
<...>
Попробуйте, например, вернуть значение из многострочного макроса (как его может вернуть однострочный макрос-выражение).
<...>
Понятно, что через переменную вернуть можно (нарушая все правила приличия ))). Не увидел в вашем примере конструкций вида: set result=$$$SomeMacro(...)
Например:test.MAC  n a,b,c
  
#Define MyAdd(%a,%b) $$%mmmuMyAdd(%a,%b) ##continue
#IfNDef 0 ##continue
#Define 0 ##continue
  g ##Unique(new) ##continue
%mmmuMyAdd(a,b) {##continue
  q a+b ##continue
} ##continue
##Unique(old) ##continue
#EndIf ##continue
##Lit()

  s a=$$$MyAdd(1,2) w a,!
  s b=$$$MyAdd(2,3) w b,!
  s c=$$$MyAdd(3,4) w c,!
test.INT  n a,b,c
  s a=$$%mmmuMyAdd(1,2) 
  g %mmmu1 
%mmmuMyAdd(a,b) {
  q a+b 

%mmmu1 
 w a,!
  s b=$$%mmmuMyAdd(2,3) 
 w b,!
  s c=$$%mmmuMyAdd(3,4) 
 w c,!Результат
Код: plaintext
1.
2.
3.
USER>d ^test
3
5
7
Alexey MaslovmorrisonAlexey MaslovНа самом деле, компилятор классов генерирует INT-код.Тоже думал так, но похоже что сначала mac?А вы проверьте на практике…В WRC тоже считают, что INT. Обещали поправить документацию.
...
Рейтинг: 0 / 0
29.05.2015, 16:04
    #38971976
servit
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
MAC генерируется в очень редких случаях: например, если в классе есть методы-генераторы и наличествует флаг компиляции "k" ( Keep Generated Source Code ).
ПримерClass my.a Extends %RegisteredObject
{

/// w ##class(my.a).MyAdd1(1,2)
ClassMethod MyAdd1(
  a,
  b) As %Integer [ CodeMode = generator, PlaceAfter = MyAdd2 ]
{
  $$$GENERATE(" #Define c1 11")
  $$$GENERATE(" Quit a+b+$$$c1+$$$c2")
}

/// w ##class(my.a).MyAdd2(1,2)
ClassMethod MyAdd2(
  a,
  b) As %Integer [ CodeMode = objectgenerator ]
{
  Do %code.WriteLine(" #Define c2 22")
  Do %code.WriteLine(" Quit a+b+$$$c2")
}

}
Кстати, кто попробует пример выше, сможет увидеть некоторые недокументированные директивы MPP в сгенерированном MAC-коде.
...
Рейтинг: 0 / 0
29.05.2015, 16:27
    #38972004
Alexey Maslov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
servit#Define MyAdd(%a,%b) $$%mmmuMyAdd(%a,%b) ##continue
...
Всё ждал, когда подобный пример предложит Эдуард, но так и не дождался... Как говорится, "типа круто", но итог проделанных ухищрений: в макроопределение упрятана функция. В чём полезность сего деяния? Чем это лучше (гибче, etc), чем просто написать такую же точно функцию и явно её вызывать?
...
Рейтинг: 0 / 0
29.05.2015, 17:30
    #38972072
servit
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
Alexey MaslovКак говорится, " типа круто ", но итог проделанных ухищрений <...>

В чём полезность сего деяния? Чем это лучше (гибче, etc) <...>?
- Папа, сделай мне iPhone.
По прошествии времени ...
- На, сынок.
- В чём полезность сего деяния? Чем это лучше стандартного iPhone?
- ?!

Вывод: папе раньше нужно было спрашивать: "А тебе это зачем, сынок?"
Я сам удивился вопросу (зачем это?), но раз Вы задали, значит это Вам действительно нужно было.
Собственно сам вопрос не с этой ли целью задавался, не ради ли "возможно/невозможно/как"?

Инструмент предоставляет возможности. Как ими распорядиться или не распорядиться - решать разработчику.
...
Рейтинг: 0 / 0
29.05.2015, 18:09
    #38972106
Alexey Maslov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
Вы, похоже, лучше меня знаете, что и зачем я спрашиваю.
Даже когда спрашиваю в другом месте и другого человека )))
...
Рейтинг: 0 / 0
02.06.2015, 09:12
    #38973968
servit
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
servitAlexey Maslovпропущено...
А вы проверьте на практике…В WRC тоже считают, что INT. Обещали поправить документацию.Официальный ответ WRC (от разработчиков):"When you compile a class we generate MAC code in a temporary array, but this is never saved
as a MAC routine and in fact it is not even valid as a MAC routine as it is just a series of method
fragments which we stitch together. Then we ask the macro processor to turn these fragments into
INT code and this INT code may be saved if the 'k' flag is present when we combine these
fragments into a routine. So cls->int->obj is probably the correct order, with the mac piece
being hidden from users so it should not be documented as such."

So the mac part is more of an internal process and the documentation will be changed accordingly.
eduard93 ,

Исправлять ли статью решать Вам.
...
Рейтинг: 0 / 0
05.06.2015, 09:09
    #38976982
servit
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Макросы
Документация<...> Generated routines are routines which are derived or created by compiling other routines or classes. There are two types of generated routines:

1. .INT code which is created when Caché compiles a .MAC file, or a class.
2. .MAC code which is created when Caché compiles certain types of classes.
источник servit How These Code Elements Work Together Во вчерашнем билде 2015.2.FT документацию в обоих случаях уже исправили и картинку заменили.
...
Рейтинг: 0 / 0
Форумы / Caché, Ensemble, DeepSee, MiniM, IRIS, GT.M [игнор отключен] [закрыт для гостей] / Макросы / 20 сообщений из 20, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]