--- parser3/operators.ru.txt 2002/03/25 10:27:20 1.22
+++ parser3/operators.ru.txt 2002/10/15 09:42:40 1.88
@@ -5,17 +5,21 @@ Xне сделано, видимо, не будет сделано
операторы
!^eval(выражение)[формат] выражение, кроме обычных функций::
+ !допустимы #комментарии
+ работают до конца строки или закрывающейся круглой скобки
+ внутри комментария допустимы вложенные круглые скобки
!из неочевидных операторов:
- # побитный xor
- ## логический xor
+ !| побитный xor
+ !|| логический xor
~ побитное отрицание
\ целочисленное деление 10\3=3
!def для проверки defined,
пустая строка не defined
пустая таблица не defined
пустой hash не defined
+ ^if(method $hash.delete){yes}
!eq ne lt gt le ge для сравнения строк,
- !in "/dir/" для проверки[раньше ^start]
+ !in "/dir/" для проверки
["внутри не допустимы, если надо сравнить со сложным,
пусть это будет переменная].
!is 'type' для проверки типа левого операнда,
@@ -27,16 +31,17 @@ Xне сделано, видимо, не будет сделано
!числовой литерал бывает 0xABC
!приоритеты:
/* logical */
- %left "##"
+ %left "!||"
%left "||"
%left "&&"
%left '<' '>' "<=" ">=" "lt" "gt" "le" "ge"
%left "==" "!=" "eq" "ne"
%left "is" "def" "in" "-f" "-d"
%left '!'
+ условие ? когдаДа: когдаНет
/* bitwise */
- %left '#'
+ %left '!|'
%left '|'
%left '&'
%left '~'
@@ -45,6 +50,8 @@ Xне сделано, видимо, не будет сделано
%left '-' '+'
%left '*' '/' '%' '\\'
%left NEG /* negation: unary - */
+
+
!^if(условие){когда да}{когда нет}
!^switch[значение]{^case[вариант1[;вариант2...]]{действие}^case[DEFAULT]{действие по умолчанию}}
!^while(условие){тело}
@@ -68,7 +75,6 @@ Xне сделано, видимо, не будет сделано
$exception.file $exception.lineno [если не запрещены при компиляции]
$exception.source = вася
$exception.comment = болван
- ^if($exception.type eq connect){^cache[read]}
}
^case[_default]{
код, обрабатывающий другую ошибку
@@ -86,7 +92,8 @@ Xне сделано, видимо, не будет сделано
default as-is
!^taint[[lang]][код]
default "just tainted, language unknown"
- !^process[строка, которая будет process-ed, как код]
+ !^process[[$caller.CLASS|$object|$КЛАСС:CLASS]]{строка, которая будет process-ed, как код}
+ по умолчанию, методы компилируются в $self [в случае оператора, $self=$MAIN:CLASS]
!^connect[protocol://строка соединения]]{код с ^sql[...]-ями}
!mysql://user:pass@{host[:port]|[/unix/socket]}/database?
charset=cp1251_koi8&
@@ -142,20 +149,29 @@ odbc c:\drives\y\parser3project\odbc\
/**имя_поля**/'literal'
!^rem{}
!^cache[файл](секунд){код}
+ !относительное задание времени
!скэшировать строку, которая получается при выполнении кода на 'секунд' секунд
!если 0секунд, значит не кэшировать, а старый такой стереть
- ^cache[delete]
- сигнализирует вышестоящему ^cache "не кэшировать, старое забыть"
- ^cache[read]
- сигнализирует вышестоящему ^cache "взять скэшированное насильно, игнорируя expires",
- выдаёт bool "получилось/нет"
+ !^cache[файл][expires date]{код}
+ !абсолютное задание времени
+ X^cache[файл] удалить файл [не ругает, если его нет] // такое было, больше не будет, делать ^cache(0)
+ !^cache(секунд)
+ !^cache[expires date]
+ !сигнализирует вышестоящему ^cache "уменьши до стольких-то 'секунд'/'expires'"
+ !в пределе: ^cache(0) отменить кэширование
+ X^cache[read]
+ сигнализирует вышестоящему ^cache "взять скэшированное насильно, игнорируя expires",
+ выдаёт bool "получилось/нет"
Xесть глобальный флажок в свойствах/командной строке "не оптимизировать"
- !и есть исключение: ^untaint[html]{код} не оптимизируется безотностительно флажка
+ !и есть исключение: ^untaint[html]{код} не оптимизируется
+ Xбезотностительно флажка
- !у всех макросов есть локальная переменная $result, если в неё что положить,
+ !у всех методов есть локальная переменная $result, если в неё что положить,
!то _это_ будет результатом макроса, а не его тело
+ !у всех методов есть локальная переменная $caller, в ней лежит родительский stack frame,
+ !если туда записать
!use(^use или @USE) ищет файл...
!1. ...если путь начинается с /, то считается, что это путь от корня веб пространства
@@ -210,6 +226,10 @@ odbc c:\drives\y\parser3project\odbc\
!void
+ !^имя.length[]
+ 0
+ !^имя.pos[...]
+ -1
!^имя.int[] (default)
0 или default
!^имя.double[] (default)
@@ -225,7 +245,7 @@ odbc c:\drives\y\parser3project\odbc\
!^имя.div(на сколько /)
!^имя.mod(на сколько %)
!^имя.format[формат]
- !^int/double:sql{query}[[$.limit(2) $.offset(4) $.default(0)]]
+ !^int/double:sql{query}[[$.limit(2) $.offset(4) $.default{0}]]
запрос, результат которого должен быть один столбец/одна строка
!string
@@ -237,7 +257,7 @@ odbc c:\drives\y\parser3project\odbc\
пример:
^if(def $form:name) не пуста?
^if($user.isAlive) истина? [автопреобразование к числу, не ноль?]
- !^string::sql{query}[[$.limit(2) $.offset(4) $.default[n/a]]]
+ !^string::sql{query}[[$.limit(2) $.offset(4) $.default{n/a}]]
результат запроса должен быть один столбец/одна строка
!^имя.int[] .int(default) целочисленное значение строки.
если ломается преобразование, берётся default
@@ -254,7 +274,13 @@ odbc c:\drives\y\parser3project\odbc\
!^строка.match[шаблон][опции поиска]{замена}
опции поиска+=
g заменить все вхождения, а не одно
+ !^строка.split[разделитель][[lrhv]]
+ l слева направо [default]
+ r справа налево
+ h nameless таблица
+ v таблица из столбца piece [default]
!^строка.{l|r}split[разделитель] таблица из столбца $piece
+ оставлен для совместимости
!^строка.upper|lower[]
X^строка.truncate(предел терпенья) стиль :(
!^строка.length[]
@@ -266,18 +292,21 @@ odbc c:\drives\y\parser3project\odbc\
<0 = не найдено
!^строка.replace[$таблица_подстановок_строка_на_строку]
!^строка.save[[append;]путь]
+ !^строка.normalize[] выдает другую строку, в которой фрагменты на одном языке объединены
+ полезно делать перед сложными match операциями, если вы знаете, что входная строка
+ состоит из большого числа фрагментов
!table
в выражении
логическое значение равно "не пуста?"
числовое значение равно count[]
!^table::create[[nameless]]{данные} старое имя "set"
- !^table::create[table]
- клонирует таблицу
+ !^table::create[table][[$.limit(1) $.offset(5) $.offset[cur]]]
+ клонирует таблицу
!^table::load[[nameless;]путь]
!если не nameless, названия колонок берутся из первой строки
!пустые строки, и строки в первой колонке содержащие '#', игнорируются
- !^table::sql{query}[[$.limit(2) $.offset(4)]]
+ !^table::sql{query}[[$.limit(2) $.offset(4) todo:$.default{ ^table::create[...] }]]
!^таблица.save[[nameless|append;]путь]
!$таблица.поле
!$таблица.fields+ из named таблицы выдаёт текущую запись как Hash
@@ -294,15 +323,19 @@ odbc c:\drives\y\parser3project\odbc\
X^таблица.remove(position[;count]) - стирает запись
из текущей позиции [стирает запись из конкретной позиции]
[стирает count записей]
- !^таблица.join[таблица] - добавляет записи из таблицы.
+ !^таблица.join[таблица][$.limit(1) $.offset(5) $.offset[cur]] - добавляет записи из таблицы.
таблицы должны иметь одинаковую структуру.
!^таблица.flip[] выдаёт транспонированную, надо куда-то сложить, потом пользовать
!^таблица.locate[поле;значение] передвигает текущую строку, если найдёт. выдаёт bool
!^таблица.locate(логическое выражение) передвигает текущую строку, если найдёт. выдаёт bool
- !^таблица.hash[поле, что будет ключом][[поле значений|table поля значений]]+
+ !^таблица.hash[поле, что будет ключом][[поле значений|table поля значений]][[$.distinct(1)]]
значением $hash.ключ будет hash в котором поля значений будут ключами
поля значений могут быть не указаны, тогда ими будут все столбцы, включая ключевой
!^таблица.columns[]+ таблица из одного столбца $column
+ !$отобранное[^таблица.select(выражение)] = таблица из тех же столбцов и строк, у которых условие совпало
+ $adults[^man.select($man.age>=18)]
+ ^таблица.color[цвет1;цвет2]
+
!hash
!в выражении
@@ -321,7 +354,7 @@ odbc c:\drives\y\parser3project\odbc\
!^a.intersection[b] = пересечение
значения a
!^a.intersects[b] = bool
- !^hash::sql{запрос}[[$.limit(2) $.offset(4)]]
+ !^hash::sql{запрос}[[$.distinct(1) $.limit(2) $.offset(4) todo:$.default{$.field[]...}]]
получается hash(ключи=значения первая колонка ответа)
of hash(ключи=названия остальных колонкок ответа)
!^hash._keys[]+ таблица из одного столбца $key
@@ -345,6 +378,7 @@ odbc c:\drives\y\parser3project\odbc\
!request
!$request:query
+ !$request:body unprocessed POST request body
!$request:uri
X!$request:browser это hash, поля:
!$type = ie/nn и !$version = номер, скажем 5.5
@@ -361,6 +395,8 @@ odbc c:\drives\y\parser3project\odbc\
!значение может быть string а может быть hash:
! $value[abc] field: {abc}<<часть
! $attribute[zzz] field: abc; {attribute=zzz}<<часть
+ !значение поля или атрибута может быть string или date
+ ! если дата, она будет преобразована к формату "Sun, 25-Aug-2002 12:03:45 GMT"
!$response:body[DATA] замещает стандартный ответ
!$response:status
!^response:clear[] забыть все заданные response поля
@@ -404,16 +440,78 @@ Xhashfile
^code.cache[заголовки новостей](35){....}
!mail
+ !$mail.received=MESSAGE:
+ .from
+ .reply-to
+ .subject
+ .date класса date
+ .message-id
+ .raw[
+ .СЫРОЕ_ПОЛЬЗОВАТЕЛЬСКОЕ-ПОЛЕ-ЗАГОЛОВКА
+ ]
+ $.{text|html|file#}[ << нумеруется как и в mail:send (text, text2, ...) (file, file2, ...)
+ $.content-type[
+ $.value[{text|...|x-unknown}/{plain|html|...|x-unknown}]
+ [$.charset[windows-1251]] << в каком пришло, сейчас уже перекодировано
+ $.ПОЛЬЗОВАТЕЛЬСКИЙ-ПАРАМЕТР-ЗАГОЛОВКА
+ ]
+ $.description
+ $.content-id
+ $.content-md5
+ $.content-location
+ .raw[
+ .СЫРОЕ_ПОЛЬЗОВАТЕЛЬСКОЕ-ПОЛЕ-ЗАГОЛОВКА
+ ]
+ $.value[строка|FILE]
+ ]
+ $.message#[MESSAGE] (message, message2, ...)
+
+ !^mail:send[
+ $.charset[кодировка заголовка и текстовых блоков]
+ $.any-header-field
+ $.text[string]
+ $.text[
+ $.any-header-field
+ $.value[string]
+ ]
+ $.html{string}
+ $.html[
+ $.any-header-field
+ $.value{string}
+ ]
+ $.file#[FILE]
+ $.file#[
+ $.any-header-field
+ $value[FILE]
+ ]
+ ]
+ !если charset указан, письмо перекодируется в этот charset
+ !content-type.charset не влияет на перекодирование
+ !после имени части может идти # число
+ ^mail:send[
+# по-умолчанию, совпадает с source encoding.
+# задаёт кодировку body
+ $.charset[windows-1251]
+# нет умолчания
+ $.content-type[$.value[text/plain] $.charset[windows-1251]]
+ $.from["вася" ]
+ $.to["петя" ]
+ $.subject[пойдём пивка]
+ $.body[
+ слова
+ ]
+ ]
!:send[$.header-field[] $.charset[кодировка письма] $.body[когда body не строка,
а hash, отсылается multipart письмо]]
!если charset указан, письмо перекодируется в этот charset
!content-type.charset не влияет на перекодирование
+ !после имени части может идти целое число, части пойдут в порядке чисел.
!если body указан строкой, то это текст письма, никаких вложений.
!если body указан hash, то это части, будут собраны текстовые блоки, затем вложения
+ !это старый формат, поддерживается для обратной совместимости
!если имя части начинается со слова text, то это текстовый блок.
!если имя части начинается со слова attach, то это вложение, формат задания::
!$attach[$.format[!uue|Xbase64] $.value[DATA] $.file-name[user-file-name]]
- !после имени части может идти целое число, части пойдут в порядке чисел.
!важно: при multipart не указывать content-type
^mail:send[
# по-умолчанию, совпадает с source encoding.
@@ -516,7 +614,7 @@ Xhashfile
возвращённый заголовок рассыпается на $поля
$status
$stderr
- !^file::exec[имя файла[;env hash[;1cmd[;2line[;3ar[;4g[;5s;...under win32 max 10 args]]]]]]]
+ !^file::exec[имя файла[;env hash $.stdin[текст][;1cmd[;2line[;3ar[;4g[;5s;...under win32 max 10 args]]]]]]]
!^file:move[старое имя файла;новое имя файла]
можно переименовывать и двигать каталоги[win32: но не через границу дисков]
каталоги для dest создаются с правами 775
@@ -526,8 +624,14 @@ Xhashfile
блокируется
выполняется код
разблокируется
+ Xchmod[...] НЕТ И НЕ БУДЕТ, ЧТОБЫ НЕ МОГЛИ СДЕЛАТЬ executable и запустить, даже если ftp запрещает chmod.
+ !^file:dirname[/a/some.tar.gz]=/a
+ !^file:dirname[/a/b/]=/a
+ !^file:basename[/a/some.tar.gz]=some.tar.gz
+ !^file:justname[/a/some.tar.gz]=some.tar
+ !^file:justext[/a/some.tar.gz]=gz
-!math
+math
!$math:PI
!^math:round floor ceiling
!^math:trunc frac
@@ -537,21 +641,35 @@ Xhashfile
!^math:degrees radians
!^math:pow sqrt
!^math:random(ширина диапазона)
+ ^math:GUID {C2C0983C-E26E-4169-BD07-77ECE9405BA5}
+ !^math:crypt[password;salt]
+ salt prefix $apr1$ вызывает встроенный MD5 алгоритм,
+ если нет тела salt, оно создаётся случайным
+ $1$ вызывает MD5 алгоритм функции OS 'crypt', если поддерживается [заведомо нет на solaris].
+ другие salt читайте документацию по функции OS 'crypt'.
!date
!время типа time можно использовать в выражениях, подставляет
количество дней с epoch [1 января 1970 (UTC)], дробное
!всё происходит в localtime,
!временная зона задаётся вне parser средствами OS
+ $date:UTC-offset сколько дней надо прибавить,чтобы попасть в local время
+ $date:TZ наш часовой пояс, дробное, в часах (где-то есть с точностью до получаса)
!^date::now[]
+ !^date::now(смещение в днях) выдаёт сейчас+смещение
!^date::create(дней с epoch) // старое имя set
- !^date::create(year;month;day[;hour[;minute[;second]]]) // старое имя set
- !$date.year month day hour minute second weekday read-only
- !^date.roll[year|month|day](+/- 1) сдвигает дату
+ !^date::create(year;month[;day[;hour[;minute[;second]]]]) // старое имя set
+ !^date::create[дата в формате %Y-%m-%d %H:%M:%S]
+ для удобного создания по значению из базы
+ формат1: %Y[-%m[-%d[ %H[:%M[:%S]]]]]
+ формат2: %H:%M[:%S]
+ !$date.year month day hour minute second weekday yearday(0...) daylightsaving
+ read-only
+ !^date.roll[year|month|day](+-смещение) сдвигает дату
!^date.sql-string[] %Y-%m-%d %H:%M:%S
where published='$дата.sql-string[]'
!^date:calendar[rus|eng;год;месяц] выдаёт неименованную таблицу
- столбцы: 0..6
+ столбцы: 0..6, week, weekyear
!^date:calendar[rus|eng;год;месяц;день] выдаёт именнованную таблицу
столбцы: year, month, day, weekday
@@ -583,10 +701,12 @@ xdoc(xnode)
!равно текущей кодировке выходной страницы,
$response:charset
::sql{...}
- !::create{} старое имя 'set'
- !::create[qualifiedName]
+ !::create[[URI]]{} старое имя 'set'
+ !::create[[URI]][qualifiedName]
+ URI default = disk path to requested document
+ для каталогов конечный / обязателен
!::load[file.xml]
- !.transform[rules.xsl][[params hash]] выдаёт dom
+ !.transform[rules.xsl|xdoc][[params hash]] выдаёт dom
шаблон кэшируется, кэш обновляется при изменении даты файла шаблона,
или изменении даты файла "имя шаблона.stamp"[проверка даты stamp приоритетнее]
+ !параметры передаются как есть, не xpath выражения
- !.string[output options]
- !.save[file.xml;output options] с шапкой
- !.file[output options] = file
+ !.string[[output options]]
+ !.save[file.xml[;output options]] с шапкой
+ !.file[[output options]] = file
output options идентичны атрибутам xsl:output
[исключение: игнорируется cdata-section-elements, нужно будет, сделаю]
выдаёт media-type при подстановке $response:body[сюда]
@@ -642,10 +763,15 @@ xdoc(xnode)
true if the attribute received its value explicitly in the XML document,
or if a value was assigned programatically with the setValue function.
false if the attribute value came from the default value declared in the document's DTD.
+ !$attribute_node.name
+ !$attribute_node.value
$text_node/cdata_node/comment_node.substringData
!$pi_node.target = target of this processing instruction
XML defines this as being the first token following the markup
that begins the processing instruction.
+ !$pi_node.data = The content of this processing instruction
+ This is from the first non white space character after the target
+ to the character immediately preceding the ?>.
document_node.
readonly attribute DocumentType doctype
readonly attribute DOMImplementation implementation
@@ -672,7 +798,7 @@ xdoc(xnode)
!void removeAttribute(in DOMString name) raises(DOMException)
!Attr getAttributeNode(in DOMString name)
!Attr setAttributeNode(in Attr newAttr) raises(DOMException)
- !/*Attr*/ removeAttributeNode(in Attr oldAttr) raises(DOMException)
+ !Attr removeAttributeNode(in Attr oldAttr) raises(DOMException)
!NodeList getElementsByTagName(in DOMString name)
!void normalize()
@@ -685,9 +811,9 @@ xdoc(xnode)
!^node.select[xpath/query/expression] = array of nodes,
empty array if nothing found
!^node.selectSingle[xpath/query/expression] = first node if any
- !^node.selectBool[xpath/query/expression] = bool if any
- !^node.selectNumber[xpath/query/expression] = double if any
- !^node.selectString[xpath/query/expression] = string if any
+ !^node.selectBool[xpath/query/expression] = bool if any or die
+ !^node.selectNumber[xpath/query/expression] = double if any or die
+ !^node.selectString[xpath/query/expression] = string if any or die
!error codes(пока придут как текст в случае соответствующих ошибок):
INDEX_SIZE_ERR
@@ -711,7 +837,7 @@ xdoc(xnode)
does not support data
NO_MODIFICATION_ALLOWED_ERR
If an attempt is made to modify an
- object where modifications are not
+ object where modifications are not
allowed
NOT_FOUND_ERR
If an attempt was made to reference a
@@ -761,19 +887,24 @@ xdoc(xnode)
!ixrss integral shared text memory size
!idrss integral unshared data size
!isrss integral unshared stack size
+ !tv_sec
+ !tv_usec
+ $s[$status:rusage]
+ ^s.tv_sec.format[%.0f].^s.tv_usec.format[%06.0f]
+
+
+!DATA::=string | file
!MAIN
это класс, загружаемый на автомате из parser3.conf,
кучи auto.p и запрашиваемого документа:
!parser3.conf
cgi:
- 1.0) полный путь из переменной окружения PARSER_ROOT_CONFIG
- 1.1) configure sysconfdir|windows directory
- 2)рядом с бинарником parser'а
+ 1. или полный путь из переменной окружения CGI_PARSER_SITE_CONFIG
+ или рядом с бинарником parser'а
isapi: windows directory
apache module:
- 1) ParserRootConfig [httpd.conf only]
- 2) ParserSiteConfig [can be in .htaccess]
+ 1) ParserConfig [can be in .htaccess]
!auto.p вниз от DOCUMENT_ROOT/ по дереву до каталога с обрабатываемым файлом включительно
класс собирается из всех этих файлов, последующие становятся родителями предыдущих
имя последнего загруженного MAIN, имён у предыдущих нет
@@ -782,7 +913,7 @@ xdoc(xnode)
!результат которого передаётся в его @post-process[data] if($data is string) ...
!результат которого отдаётся пользователю
- !если встречается ошибка и try не задан, её можно красиво сообщить пользователю,
+!если встречается ошибка и try не задан, её можно красиво сообщить пользователю,
!определив
!@unhandled_exception[exception;stack]
!$exception.type строка "тип проблемы"
@@ -793,11 +924,28 @@ xdoc(xnode)
там лежат в обратном порядке имена[name] и места вызовов[file line]
операторов/методов, приведших к ошибке.
- !нужно выключить русский apache: CharsetDisable on
-
-
-!DATA::=string | file
+!системные типы ошибок:
+ !parser.compile ^test[} компиляция (непарная скобка, ...)
+ !parser.runtime ^if(0). параметры (больше/меньше, чем нужно, не тех типов, ...)
+ !number.zerodivision ^eval(1/0) ^eval(1%0)
+ !number.format ^eval(abc*5)
+ !file.lock shared/exclusive lock error
+ !file.missing ^file:delete[delme] not found
+ !file.access ^table::load[.] no rights
+ !image.format ^image::measure[index.html] not gif/jpg
+ !sql.connect ^connect[mysql://baduser:pass@host/db]{} not found/timeout
+ !sql.execute ^void:sql{select bad} syntax error
+ sql.duplicate
+ sql.access
+ sql.missing
+ sql.xxx [serge asked]
+ !xml ^xdoc::create{} any error in xml/xslt libs
+ !smtp.connect not found/timeout
+ !smtp.execute communication error
+ !email.format hren tam@null.ru wrong email format(bad chars/empty)
+ !email.send $MAIL.sendmail[/shit] sendmail not executable
+
+!нужно выключить русский apache: CharsetDisable on
----
- если в MAIN будет определён флаг $ORIGINS(1) то вместо обычного вывода страницы будет
+!если в MAIN будет определён флаг $ORIGINS(1) то вместо обычного вывода страницы будет
выдан список фрагментов результата с указанием их происхождения