--- parser3/operators.ru.txt 2002/03/22 11:25:05 1.21
+++ parser3/operators.ru.txt 2009/09/18 09:16:49 1.227
@@ -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,34 +50,43 @@ Xне сделано, видимо, не будет сделано
%left '-' '+'
%left '*' '/' '%' '\\'
%left NEG /* negation: unary - */
+ !литералы
+ true
+ false
+
+
!^if(условие){когда да}{когда нет}
!^switch[значение]{^case[вариант1[;вариант2...]]{действие}^case[DEFAULT]{действие по умолчанию}}
- !^while(условие){тело}
+ !^while(условие){тело}[[разделитель]|{разделитель который выполняется перед непустым очередным не первым телом}]
!^for[i](0;4){тело}[[разделитель]|{разделитель который выполняется перед непустым очередным не первым телом}]
!^use[модуль]
!^try{
...
- !^throw[sql.connect;вася;болван] // был ^error[текст]
+ !^throw[sql.connect[;вася[;болван]]] // был ^error[текст]
+ !^throw[
+ $.type[sql.connect]
+ $.source[вася]
+ $.comment[болван]
+ ]
...
}{
- ^if($exception.type eq sql){
- $exception.handled(1) ^rem{флаг, что exception обработан}
+ ^if($exception.type eq "sql"){
+ $exception.handled(1|true) ^rem{флаг, что exception обработан}
....
}
- ^switch($exception.type){
+ ^switch[$exception.type]{
^case[sql;mail]{
$exception.handled(1)
код, обрабатывающий sql ошибку
$exception.type = sql.connect
- $exception.file $exception.lineno [если не запрещены при компиляции]
+ $exception.file $exception.lineno $exception.colno [если не запрещены при компиляции]
$exception.source = вася
$exception.comment = болван
- ^if($exception.type eq connect){^cache[read]}
}
- ^case[_default]{
+ ^case[DEFAULT]{
код, обрабатывающий другую ошибку
- ^throw[$exception] << re-throw
+ ^throw[$exception] << re-throw // DON'T! It's default behaviour!
}
}
}
@@ -80,23 +94,36 @@ Xне сделано, видимо, не будет сделано
удобно сделать после выставления 401 ошибки
^return[результат] + - отваливает из выполнения метода,
выдавая нестандартный результат
- ^break[] + - обрывает цикл
- ^continue[] + - обрывает итерацию цикла
- !^untaint[[as-is|file-spec|http-header|mail-header|uri|table|sql|js|xml|html|optimized-html]]{код}
+ !^break[] + - обрывает цикл
+ !^continue[] + - обрывает итерацию цикла
+ !^untaint[[as-is|file-spec|http-header|mail-header|uri|sql|js|xml|html|optimized-html|regex|parser-code]]{код}
default as-is
!^taint[[lang]][код]
default "just tainted, language unknown"
- !^process[строка, которая будет process-ed, как код]
+ !^process[[$caller.CLASS|$object|$КЛАСС:CLASS]]{строка, которая будет process-ed, как код}[
+ $.main[во что переименовать @main]
+ $.file[имя файла из которого, якобы, данный текст]
+ $.lineno(номер строки в файле, откуда данный текст. можно отрицательный)
+ ]
+ !^process..[путь][во что переименовать @main]
+ по умолчанию, методы компилируются в $self [в случае оператора, $self=$MAIN:CLASS]
!^connect[protocol://строка соединения]]{код с ^sql[...]-ями}
!mysql://user:pass@{host[:port]|[/unix/socket]}/database?
+ ClientCharset=parser-charset << charset in which parser thinks client works
charset=cp1251_koi8&
timeout=3&
- compress=1&
- named_pipe=1
-
- !pgsql://user:pass@{host[:port]|[local]}/database
+ compress=0&
+ named_pipe=1&
+ multi_statements=1& allow execute more then one query in one parser :sql{} request
+ autocommit=1
+ autocommit если выставить в 0, будет делать commit/rollback
+
+ !pgsql://user:pass@{host[:port]|[local]}/database?
+ client_encoding=win,[to-find-out]
+ &datestyle=ISO,SQL,Postgres,European,NonEuropean=US,German,DEFAULT=ISO
+ &ClientCharset=parser-charset << charset in which parser thinks client works
- oracle://user:pass@service?
+ !oracle://user:pass@service?
NLS_LANG=RUSSIAN_AMERICA.CL8MSWIN1251&
NLS_LANGUAGE language-dependent conventions
NLS_TERRITORY territory-dependent conventions
@@ -107,18 +134,25 @@ Xне сделано, видимо, не будет сделано
NLS_ISO_CURRENCY ISO currency symbol
NLS_SORT sort sequence
ORA_ENCRYPT_LOGIN=TRUE
+ ClientCharset=parser-charset << charset in which parser thinks client works
- !odbc://DSN=dsn^;UID=user^;PWD=password
+ !odbc://DSN=dsn^;UID=user^;PWD=password^;ClientCharset=parser-charset
+ ClientCharset << charset in which parser thinks client works
+
+ !sqlite://DBfile?
+ ClientCharset=parser-charset& << charset in which parser thinks client works
+ autocommit=1
- для работы connect нужно, чтобы заранее(рекомендуется в системном parser3)
+ для работы connect нужно, чтобы заранее(рекомендуется в системном конфигурационном auto.p)
была определена таблица
#sql drivers
$SQL[
- $.drivers[^table::set{protocol driver client
-mysql /www/parser3/libparser3mysql.so /usr/local/lib/mysql/libmysqlclient.so
-pgsql /www/parser3/libparser3pgsql.so /usr/local/pgsql/lib/libpq.so
-oracle /www/parser3/libparser3oracle.so /u01/app/oracle/product/8.1.5/lib/libclntsh.so?ORACLE_HOME=/u01/app/oracle/product/8.1.5&ORA_NLS33=/u01/app/oracle/product/8.1.5/ocommon/nls/admin/data
-odbc c:\drives\y\parser3project\odbc\debug\parser3odbc.dll
+ $.drivers[^table::create{protocol driver client
+mysql /www/parser3/libparser3mysql.so /usr/local/lib/mysql/libmysqlclient.so
+pgsql /www/parser3/libparser3pgsql.so /usr/local/pgsql/lib/libpq.so
+oracle /www/parser3/libparser3oracle.so /u01/app/oracle/product/8.1.5/lib/libclntsh.so?ORACLE_HOME=/u01/app/oracle/product/8.1.5&ORA_NLS33=/u01/app/oracle/product/8.1.5/ocommon/nls/admin/data
+sqlite /www/parser3/libparser3sqlite.so /usr/local/sqlite/lib/sqlite3.so
+odbc c:\drives\y\parser3project\odbc\debug\parser3odbc.dll
}]
]
!в таблице у oracle в столбце клиентской библиотеки
@@ -139,28 +173,40 @@ odbc c:\drives\y\parser3project\odbc\
ставить такой префикс перед открывающим апострофом, впритык, везде без проблелов
/**имя_поля**/'literal'
!^rem{}
- !^cache[файл](секунд){код}
+ !^cache[файл](секунд){код}[{catch код}]
+ !относительное задание времени
!скэшировать строку, которая получается при выполнении кода на 'секунд' секунд
!если 0секунд, значит не кэшировать, а старый такой стереть
- ^cache[delete]
- сигнализирует вышестоящему ^cache "не кэшировать, старое забыть"
- ^cache[read]
- сигнализирует вышестоящему ^cache "взять скэшированное насильно, игнорируя expires",
- выдаёт bool "получилось/нет"
+ !в catch коде $exception.handled[cache] ^rem{флаг, что exception обработан}
+ !^cache[файл][expires date]{код}[{catch код}]
+ !абсолютное задание времени
+ X^cache[файл] удалить файл [не ругает, если его нет] // такое было, больше не будет, делать ^cache(0)
+ !^cache(секунд)
+ !^cache[expires date]
+ !сигнализирует вышестоящему ^cache "уменьши до стольких-то 'секунд'/'expires'"
+ !в пределе: ^cache(0) отменить кэширование
+ !^cache[] выдаёт текущую expires date
+ X^cache[read]
+ сигнализирует вышестоящему ^cache "взять скэшированное насильно, игнорируя expires",
+ выдаёт bool "получилось/нет"
+ !^sleep(seconds)
Xесть глобальный флажок в свойствах/командной строке "не оптимизировать"
- !и есть исключение: ^untaint[html]{код} не оптимизируется безотностительно флажка
+ !и есть исключение: ^untaint[html]{код} не оптимизируется
+ Xбезотностительно флажка
- !у всех макросов есть локальная переменная $result, если в неё что положить,
+ !у всех методов есть локальная переменная $result, если в неё что положить,
!то _это_ будет результатом макроса, а не его тело
+ !у всех методов есть локальная переменная $caller, в ней лежит родительский stack frame,
+ !если туда записать
!use(^use или @USE) ищет файл...
!1. ...если путь начинается с /, то считается, что это путь от корня веб пространства
!есть глобальная строка/таблица $MAIN:CLASS_PATH с путём/путями к каталогу с классами.
!корень путя/путей считается от корня веб пространства.
!2. ...относительно строчки из table $MAIN:CLASS_PATH, снизу вверх
- задавайте её в parser3.conf вашего сайта
+ задавайте её в конфигурационном auto.p вашего сайта
!глобальная табличка $CHARSETS[$.название[имя файла]]
!задаёт какие буквы считаются какими(whitespace, letter, etc), а также их unicode
@@ -181,6 +227,7 @@ odbc c:\drives\y\parser3project\odbc\
!$имя whitespace или ${имя}неважно подстановка значения
!^имя параметры вызов
!$имя.CLASS класс значения
+ !$имя.CLASS_NAME имя класса
!$имя[$.key[] () {}] конструктор элемента переменной-хэша $имя.key
!^method[$.key[] () {}] конструктор элемента параметра-хеша $parameter.key
$CLASS.имя обращение к переменной класса
@@ -208,22 +255,36 @@ odbc c:\drives\y\parser3project\odbc\
!void
+ !^имя.length[]
+ 0
+ !^имя.pos[...]
+ -1
+ !^имя.left(n)
+ ничего не выдаёт
+ !^имя.right(n)
+ ничего не выдаёт
+ !^имя.mid(p[;n])
+ ничего не выдаёт
!^имя.int[] (default)
0 или default
!^имя.double[] (default)
0 или default
- !^void:sql{запрос без результата}
+ !^имя.bool[] (default)
+ false или default
+ !^void:sql{запрос без результата}{$.bind[см. table::sql]}
+
!int,double
!^имя.int[] целочисленное значение
!^имя.double[]+ double значение
+ !^имя.bool[] + .bool(true|false) bool значение
!^имя.inc(на сколько +)
!^имя.dec(на сколько -)
!^имя.mul(на сколько *)
!^имя.div(на сколько /)
!^имя.mod(на сколько %)
!^имя.format[формат]
- !^int/double:sql{query}[[$.limit(2) $.offset(4) $.default(0)]]
+ !^int/double:sql{query}[[$.limit(2) $.offset(4) $.default{0} $.bind[см. table::sql]]]
запрос, результат которого должен быть один столбец/одна строка
!string
@@ -235,24 +296,34 @@ 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(1) $.offset(4) $.default{n/a} $.bind[см. table::sql]]]
результат запроса должен быть один столбец/одна строка
- !^имя.int[] .int(default) целочисленное значение строки.
+ !^строка.int[] .int(default) целочисленное значение строки.
если ломается преобразование, берётся default
- !^имя.double[]+ .double(default) double значение строки
+ !^строка.double[]+ .double(default) double значение строки
+ !^строка.bool[] + .bool(default) bool значение строки
если ломается преобразование, берётся default
- !^имя.format[формат] %d %.2f %02d...
- !^строка.match[шаблон][[опции поиска]] $prematch $match $postmatch $1 $2...
+ !^строка.format[формат] %d %.2f %02d...
+ !^строка.match[шаблон-строка|шаблон-regex][[опции поиска]] $prematch $match $postmatch $1 $2...
опции поиска=
i CASELESS
x whitespace in regex ignored
s singleline = $ считается концом всего текста
m multiline = $ считается концом строки[\n], не концом всего текста
g найти все вхождения, а не одно
- !^строка.match[шаблон][опции поиска]{замена}
+ ' создавать столбцы prematch, match, postmatch
+ n вернуть цисло с количеством найденных совпадений, а не таблицу с результатами
+ U инвертировать смысл модификатора '?'
+ !^строка.match[шаблон-строка|шаблон-regex][опции поиска]{замена}
опции поиска+=
g заменить все вхождения, а не одно
+ !^строка.split[разделитель][[lrhv]][[название столбца для вертикального разбиения]]
+ l слева направо [default]
+ r справа налево
+ h nameless таблица с ключами 0, 1, 2, ...
+ v таблица из 1 столбца 'piece' или как передадут [default]
!^строка.{l|r}split[разделитель] таблица из столбца $piece
+ оставлен для совместимости
!^строка.upper|lower[]
X^строка.truncate(предел терпенья) стиль :(
!^строка.length[]
@@ -261,26 +332,44 @@ odbc c:\drives\y\parser3project\odbc\
!^строка.left(N)
!^строка.right(N)
!^строка.pos[подстрока]
+ !^строка.pos[подстрока](позиция, с которой ищем)
<0 = не найдено
!^строка.replace[$таблица_подстановок_строка_на_строку]
!^строка.save[[append;]путь]
+ !^строка.save[путь[;$.charset[в какой кодировке сохраняем] $.append(true)]]
+ !^строка.normalize[] выдает другую строку, в которой фрагменты на одном языке объединены
+ полезно делать перед сложными match операциями, если вы знаете, что входная строка
+ состоит из большого числа фрагментов
+ !^строка.trim[start|both|end|left|right[;chars]] выкидывает chars из начала/конца/и начала и конца
+ default 'chars' -- whitespace chars
+ !^строка.append[string]
+ !^строка.base64[] encode
+ !^string:base64[encoded] decode
!table
в выражении
логическое значение равно "не пуста?"
числовое значение равно count[]
- !^table::create[[nameless]]{данные} старое имя "set"
- !^table::create[table]
- клонирует таблицу
- !^table::load[[nameless;]путь]
+ !^table::create[[nameless]]{данные}[[$.separator[^#09]]] старое имя "set"
+ !^table::create[table][[$.limit(1) $.offset(5) $.offset[cur] $.reverse(1)]]
+ клонирует таблицу
+ reverse << сзаду на перёд (работает пока только в locate, в table::create НЕ работает)
+ !^table::load[[nameless;]путь[;опции]]
!если не nameless, названия колонок берутся из первой строки
!пустые строки, и строки в первой колонке содержащие '#', игнорируются
- !^table::sql{query}[[$.limit(2) $.offset(4)]]
- !^таблица.save[[nameless|append;]путь]
+ !$.separator[^#09]
+ !$.encloser["] по-умолчанию, нет.
+ !^table::sql{query}[[$.limit(2) $.offset(4) $.bind[hash] todo:$.default{ ^table::create[...] }]]
+ bind привязывает переменные в запросе к их значениям
+ пока реализован только для oracle
+ в запросе надо написать ":имя"
+ в параметре bind передать hash, из которого возьмётся(или куда запишется) значение
+ !^таблица.save[[nameless|append;]путь[;опции, см. load]]
!$таблица.поле
- !$таблица.fields+ из named таблицы выдаёт текущую запись как Hash
- !^таблица.menu{тело}[разделитель]
- !^таблица.offset[[whence]](5) сдвигает; без параметра - печатает offset
+ !$таблица.fields из named таблицы выдаёт текущую запись как Hash
+ !^таблица.menu{тело}[[разделитель]]
+ !^таблица.offset[] печатает offset
+ !^таблица.offset[[whence]](5) сдвигает
!whence=cur|set
!без whence - это cur
!^таблица.count[]
@@ -292,58 +381,113 @@ 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 поля значений]]+
+ !^таблица.locate[поле;значение][[$.limit(1) $.offset(5) $.offset[cur] $.reverse(1)]]
+ передвигает текущую строку, если найдёт. выдаёт bool
+ !^таблица.locate(логическое выражение)[[$.limit(1) $.offset(5) $.offset[cur] $.reverse(1)]]
+ передвигает текущую строку, если найдёт. выдаёт bool
+ !^таблица.hash{[поле]|{код}|(выражение)}[[поле значений|table поля значений]][[$.distinct(1) $.distinct[tables]]]
значением $hash.ключ будет hash в котором поля значений будут ключами
поля значений могут быть не указаны, тогда ими будут все столбцы, включая ключевой
- !^таблица.columns[]+ таблица из одного столбца $column
+ если distinct содержит true, то не будет ошибки при повторяющихся ключах
+ если distinct содержит tables, то будет создан hash из таблиц, содержащих строки с ключом
+ !^таблица.columns[[название столбца]]+ таблица из одного столбца 'column' или как передадут
+ !$отобранное[^таблица.select(выражение)] = таблица из тех же столбцов и строк, у которых условие совпало
+ $adults[^man.select($man.age>=18)]
+ ^таблица.color[цвет1;цвет2]
+
!hash
!в выражении
!логическое значение равно "не пуста?"
!числовое значение равно _count[]
- !$hash.ключ
+ !$хеш.ключ
!_default - специальный ключ, если задан,
то при обращении по ключу, которому нет соответствия, выдаётся _default значение
- !^hash::create[[!copy_from_hash|Xcopy_from_hashfile]]
+ !$хеш.fields выдает $hash. чтобы класс hash был чуть больше похож на класс table
+ !^hash::create[[!copy_from_hash|copy_from_hashfile]]
создаёт новый hash, копию старого
- !^hash.add[слагаемое]
+ !^хеш.add[слагаемое]
перезаписывает одноимённые
- !^hash.sub[вычитаемое]
- !^a.union[b] = объединение
+ !^хеш.sub[вычитаемое]
+ !^хеш.union[b] = объединение
одноимённые остаются
- !^a.intersection[b] = пересечение
- значения a
- !^a.intersects[b] = bool
- !^hash::sql{запрос}[[$.limit(2) $.offset(4)]]
+ !^хеш.intersection[b] = пересечение
+ значения хеш
+ !^хеш.intersects[b] = bool
+ !^hash::sql{запрос}[[$.distinct(1) $.limit(2) $.offset(4) todo:$.default{$.field[]...}]]
получается hash(ключи=значения первая колонка ответа)
of hash(ключи=названия остальных колонкок ответа)
- !^hash._keys[]+ таблица из одного столбца $key
- !^hash._count[]
- !^foreach[key;value]{тело}[[разделитель]|{разделитель который выполняется перед непустым очередным не первым телом}]
- !^delete[ключ] удалить ключ
+ !^хеш._keys[[название колонки с ключами]]+ таблица из одного столбца $key или как передадут
+ !^хеш._count[]
+ !^хеш.foreach[key;value]{тело}[[разделитель]|{разделитель который выполняется перед непустым очередным не первым телом}]
+ !^хеш.delete[ключ] удалить ключ
+ !^хеш.contain[ключ] - существует ли в хеше ключ (bool)
+
+!hashfile
+ !^hashfile::open[filename]
+ !^хешфайл.clear[] забыть всё
+ !$хешфайл.ключ[значение] положить значение
+ !$хешфайл.ключ[$.value[значение] $.expires[ЗНАЧЕНИЕ]}
+ положить значение до expires
+ значение поля expires может быть date, или число дней(0дней=на вечно)
+ !$хешфайл.ключ достать
+ !^хешфайл.delete[ключ] удалить ключ
+ !^хешфайл.delete[] удалить файлы, содержащие данные
+ !^хешфайл.hash[]
+ преобразовать в обычный hash
+ попутно стирает устаревшие пары
+ !^хешфайл.foreach[key;value]{тело}[[разделитель]|{разделитель который выполняется перед непустым очередным не первым телом}]
+ !^хешфайл.release[]
+ записать данные и снять блокировки.
+ при повторном обращении к элементам откроется автоматически.
+ !^хешфайл.cleanup[] пробежаться по всем элементам и удалить устаревшие.
+
+ пример:
+ $sessions[^hashfile::open[/db/sessions]]
+
+ $sid[^math:uuid[]]
+ $sessions.$sid[$.value[$uid] $.expires(1)]
+ $uid[$sessions.$sid]
+
!form
[берётся первый элемент из одноимённых из GET, потом первый из POST]
!$form:поле = string/file
+ !$form:nameless = поле со значением поля без имени "?value&...", "...&value&...", "...&value"
+ !$form:qtail = строка со значением текста после второго "?xxxxx", если там не было ',' [imap]
!$form:fields = hash со всеми полями формы
!$form:tables.поле = table с одним столбцом "field" со значениями "поля"
+ !$form:files.поле = hash со значениями полей типа файл, ключи - 0, 1, ..., значение - файл
+ !$form:imap = хэш с ключами 'x' и 'y'
+ со значением ?1,2 приписки при использовании server-site image map
+
!env
!$env:переменная
+ !$env:PARSER то же самое, что показывается при запуске parser.cgi
+
!cookie
!$cookie:имя считать старое или свежезаданное
!$cookie:имя[значение] на 90 дней
- !$cookie:имя[$.value[значение] $.expires(дней, 0дней=session)]
+ !$cookie:имя[$.value[значение] $.expires[ЗНАЧЕНИЕ] $.secure(true)]
+ !значение поля expires может быть 'session', date, или число дней(0дней=session)
+ ! если дата, она будет преобразована к формату "Sun, 25-Aug-2002 12:03:45 GMT"
+ ! можно устанавливать bool свойства, например $.secure(true), $.httponly(true)
+ !$cookie:fields = hash со всеми cookies
+
!request
!$request:query
+ !$request:body unprocessed POST request body
!$request:uri
+ !$request:document-root
+ каталог, относительно которого считаются пути в parser, по-умолчанию = $env:DOCUMENT_ROOT
+ можно изменить, если на hosting что-то неудобно настроено
+ !$request:argv = hash с параметрами коммандной строки. ключи 0, 1, ... [0 -- имя обрабатываемого файла].
X!$request:browser это hash, поля:
!$type = ie/nn и !$version = номер, скажем 5.5
X$request:user
@@ -354,12 +498,18 @@ odbc c:\drives\y\parser3project\odbc\
ПРЕДУПРЕЖДЕНИЕ: класс form получает свои поля после обработки всех auto класса MAIN
поэтому необходимо задать $request/response:charset в одном из них. не после.
+
!response
!$response:поле[значение] и можно считать старое -- $response:поле
!значение может быть string а может быть hash:
! $value[abc] field: {abc}<<часть
! $attribute[zzz] field: abc; {attribute=zzz}<<часть
+ !значение поля или атрибута может быть string или date
+ ! если дата, она будет преобразована к формату "Sun, 25-Aug-2002 12:03:45 GMT"
+ !$response:headers накопленные поля
!$response:body[DATA] замещает стандартный ответ
+ !$response:download[DATA] замещает стандартный ответ,
+ выставляет флаг, заставляющий browser предложить download
!$response:status
!^response:clear[] забыть все заданные response поля
!$response:charset
@@ -371,47 +521,118 @@ odbc c:\drives\y\parser3project\odbc\
ПРЕДУПРЕЖДЕНИЕ: класс form получает свои поля после обработки всех auto класса MAIN
поэтому необходимо задать $request/response:charset в одном из них. не после.
-Xhashfile
- !^hashfile::open[$DB_HOME;filename]
- !^hashfile.clear[]
- забыть всё
- !.ключ[значение] положить значение навечно
- !.ключ[$.value[значение] $.expires(секунд)} положить значение на expires секунд
- !.ключ достать
- !^cache[ключ](секунд){код}
- !суть то же, что и "положить+достать", но за один раз и компактнее
- !если 0секунд, значит не кэшировать, а старый такой стереть
- !внутри {кода} может быть вызван ^delete[]
- !^delete[[ключ]] удалить ключ
- !буде вызван без параметра изнутри cache, отменяет кэширование блока:
- !блок не будет скэширован, его старое значение будет стёрто
- !^hash[]
- преобразовать в обычный hash
- !^foreach[key|value]{тело}[[разделитель]|{разделитель который выполняется перед непустым очередным не первым телом}]
-
- примеры:
- $uids[^hashfile::assign[/db/uids]]
- $code:clear[/db/cache]]
- $code[^hashfile::assign[/db/cache]]
-
- $random[23847387taduigh345XGHWElxjgdjg]
- $uids.$random[$.value[$uid] $.expires(60*30)]
- $uid[$persistent.logins.$random]
+!regex
+ !в выражении
+ !логическое значение всегда равно true
+ !числовое значение равно количеству байт скомпилированного шаблона.
+ !^regex::create[шаблон-строка][[опции поиска]]
+ !^шаблон.size[] количество байт скомпилированного шаблона
+ если значение очень большое -- стоит почитать документацию по pcre и, возможно, переписать шаблон.
+ !^шаблон.study_size[] размер study-структуры. если==0 -- шаблон не может быть "изучен"
+ ^шаблон.save[filespec]
+ ^шаблон.load[filespec]
+
+
+!reflection
+ !^reflection:create[класс;конструктор[;пара;[мет[;ры]]]] вызывает указанный конструктор класса (не более 100 параметров)
+ !^reflection:classes[] хеш со всеми классами. ключ -- имя класса, значение бывает methoded (класс с методами) или void
+ !^reflection:class[объект] класс переданного объекта
+ !^reflection:class_name[объект] имя класса переданного объекта
+ !^reflection:base[объект] родительский класс переданного объекта
+ !^reflection:base_name[объект] имя родительского класса переданного объекта
+ !^reflection:methods[класс] хеш со списком методов указанного класса, значения -- строки 'native' или 'parser'
+ !^reflection:fields[класс или объект] хеш со списком статических полей указанного класса или динамических полей указанного объекта
+ !^reflection:method_info[класс;метод] хеш с параметрами указанного метода класса
+ $.inherited[класс] имя класса, где метод был определён (возвращается только если метод был определён в предке)
+ для native классов возвращается хеш:
+ .min_params(минимально необходимое число параметров)
+ .max_params(максимально возможное число параметров)
+ .call_type[dynamic|static|any]
+ для parser классов возвращается хеш:
+ ключ -- номер параметра (0, 1, ...), значение - имя параметра
+ !^reflection:dynamical[[object or class, caller if absent]] возвращает true, если метод был вызван из динамического контекста
+ при передаче параметра возвращает true, если передан динамический объект,
+ false если класс
- ^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[
+ $.options[-odd]
+ unix: строка, которая будет добавлена к команде запуска sendmail
+ -odd означает "быстро поставь в очередь без проверки email"
+ win32: игнорируется
+ $.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]]
- !после имени части может идти целое число, части пойдут в порядке чисел.
+ !если имя части начинается со слова file, то это вложение, формат задания::
+ !$file[$.format[!uue|!base64] $.value[DATA] $.name[user-file-name]]
!важно: при multipart не указывать content-type
^mail:send[
# по-умолчанию, совпадает с source encoding.
@@ -439,13 +660,14 @@ Xhashfile
$.body[слова]
]
#для удобства скриптования можно указать только одну часть, при этом не будет multipart
- $.attach[
+ $.file[
$.value[^file::load[my beloved.doc]]
- $.file-name[мой любимый.doc]
+ $.name[мой любимый.doc]
+ $.format[base64]
]
- $.attach2[
+ $.file2[
$.value[^file::load[my beloved.doc]]
- $.file-name[мой любимый.doc]
+ $.name[мой любимый.doc]
]
]
]
@@ -463,6 +685,12 @@ Xhashfile
!$картинка[^image::measure[DATA]]
смотрит на .ext case insensitive,
умеет мерить пока только .gif и .jpg .jpeg
+ !$картинка.exif << hash после measure jpeg с exif информацией
+ !$image.exif.DateTime & co
+ [полный список см. http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html]
+ !числа типа int/double,
+ !даты типа date
+ !перечисления в виде hash с ключами 0..count-1
!$картинка.src .width .height
!$картинка.line-width число=ширина линий
!$картинка.line-style строка=стиль линий '*** * '='*** * *** * *** * '
@@ -478,12 +706,18 @@ Xhashfile
!^картинка.polyline+(цвет)[table x:y точки]
!^картинка.polygon(цвет)[table x:y вершины_многоугольника]
!^картинка.polybar(цвет)[table x;y вершины_многоугольника]
- !^картинка.font[набор_букв;имя_файла_шрифта.gif](ширина_пробела[;ширина_символа])
+ !^картинка.font[набор_букв;имя_файла_шрифта.gif][(ширина_пробела[;ширина_символа])]
высота символа = высота картинки/количество букв в наборе
если указана ширина_символа, то monospaced, если 0, то ширина_символа = ширине gif
+ !^картинка.font[набор_букв;имя_файла_шрифта.gif;
+ $.space(ширина_пробела) // по умолчанию = ширине gif
+ $.width(ширина_символа) // см. выше, по умолчанию proportional
+ $.spacing(расстояние между буквами) // по умолчанию = 1
+ ]
!^картинка.text(x;y)[текст_надписи] AS_IS
!^картинка.length[текст_надписи] AS_IS
- !^картинка.gif[] -- кодирует в FILE с content-type=image/gif
+ !^картинка.gif[возможно, имя файла] -- кодирует в FILE с content-type=image/gif
+ имя файла будет использовано при $response:download
!^картинка.arc(center x;center y;width;height;start in degrees;end in degrees;color)
!^картинка.sector(center x;center y;width;height;start in degrees;end in degrees;color)
!^картинка.circle(center x;center y;r;color)
@@ -497,33 +731,72 @@ Xhashfile
определяющее прожорливость выделялки цветов из палитры [default=150]
меньше - точнее приближает цвета, но они быстро кончаются
больше - неточно приближает цвет, но бОльшей части хватит
+ !^картинка.pixel(x;y)[(color)]
+ узнать или задать цвет пиксела
+
!file
!$файл_из_post.name
!$файл_из_post.size
!$файлtиз_post.text
- !^файл.save[text|binary;имя файла]
+ !^файл.save[text|binary;имя файла[;$.charset[в какоq кодировке сохраняем]]]
!^file:delete[имя файла]
!^file:find[имя файла][{когда не нашли}]
- !^file:list[путь[;шаблон]] = table с колонкой name
- !^file::load[text|binary;!big.zip[;!domain_press_release_2001_03_01.zip]]
+ !^file:list[путь[;шаблон-строка|шаблон-regex]] = table с колонкой name
+ !^file::load[text|binary;!big.zip[;!domain_press_release_2001_03_01.zip][;опции]]
+ !^file::create[text;имя;^untaint[xml]{data}]
!$файл_который_был_loaded.size
+ !$файл_который_был_loaded_или_created.mode = text/binary
!^file::stat[имя файла]
- !$файл_который_был_stated.size !.adate !.mdate !.cdate
- !^file::cgi[имя файла[;env hash[;1cmd[;2line[;3ar[;4g[;5s]]]]]]]
+ !$файл_который_был_stated_или_loaded.size !.adate !.mdate !.cdate
+ !^file::cgi[[text|binary;]имя файла[;env hash +options[;1cmd[;2line[;3ar[;4g[;5s]]]]]]]
возвращённый заголовок рассыпается на $поля
$status
$stderr
- !^file::exec[имя файла[;env hash[;1cmd[;2line[;3ar[;4g[;5s;...under win32 max 10 args]]]]]]]
+ !^file::exec[[text|binary;]имя файла[;env hash[;1cmd[;2line[;3ar[;4g[;5s;...under unix max 50 args]]]]]]]
+ options:
+ $.stdin[текст] если текст пуст, отключается автоматическое пересовывание данных HTTP-POST
!^file:move[старое имя файла;новое имя файла]
можно переименовывать и двигать каталоги[win32: но не через границу дисков]
каталоги для dest создаются с правами 775
каталог старого файла стирается, если после move он остаётся пуст
+ !^file:copy[имя файла;имя копии файла]
+ можно копировать только файлы
!^file:lock[имя файла]{код}
файл при необходимости создаётся
блокируется
выполняется код
разблокируется
+ 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
+ !/some/page.html: ^file:fullpath[a.gif] => /some/a.gif
+ !^файл.sql-string[] внутри ^connect даст правильно escaped строку, которую можно в запрос отдать
+ X^file::sql[[имя_файла_для_download]]{}
+ !^file::sql{}[[
+ $.name[имя_файла_для_download]
+ $.content-type[пользовательский content-type]
+ ]]
+ результат запроса должен быть "одна строка".
+ колонки:
+ первая колонка - данные
+ если есть вторая - это имя файла
+ если есть третья - это content-type
+ !^файл.base64[] encode
+ !^file:base64[имя файла] encode
+ !^file::base64[encoded string] decode
+ !^file:crc32[имя файла]
+ вычисляет crc32 файла с указанным именем
+ !^файл.crc32[]
+ вычисляет crc32 объекта
+ !^файл.md5[]
+ !^file:md5[имя файла]
+ выдает digest файла, длиной 16 байт в виде строки,
+ где байты digest выданы в hex виде, впритык, в нижнем регистре
+
!math
!$math:PI
@@ -535,25 +808,69 @@ Xhashfile
!^math:degrees radians
!^math:pow sqrt
!^math:random(ширина диапазона)
+ !^math:uuid[]
+ 22C0983C-E26E-4169-BD07-77ECE9405BA5
+ win32: пользуется cryptapi
+ unix: пользуется /dev/urandom,
+ если нет, /dev/random,
+ если нет, rand
+ [на solaris /dev/random можно добавить]
+ !^math:uid64[]
+ BA39BAB6340BE370
+ !^math:md5[string]
+ выдает digest строки, длиной 16 байт в виде строки,
+ где байты digest выданы в hex виде, впритык, в нижнем регистре
+ !^math:crypt[password;salt]
+ salt prefix $apr1$ вызывает встроенный MD5 алгоритм,
+ если нет тела salt, оно создаётся случайным
+ $1$ вызывает MD5 алгоритм функции OS 'crypt', если поддерживается [заведомо нет на solaris].
+ другие salt читайте документацию по функции OS 'crypt'.
+ !^math:crc32[string]
+ вычисляет crc32 строки
+ !^math:sha1[string]
+
+
+!inet
+ !^inet:ntoa(long)
+ !^inet:aton[IP]
+
!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.sql-string[] %Y-%m-%d %H:%M:%S
- where published='$дата.sql-string[]'
- !^date:calendar[rus|eng;год;месяц] выдаёт неименованную таблицу
- столбцы: 0..6
- !^date:calendar[rus|eng;год;месяц;день] выдаёт именнованную таблицу
+ !^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::unix-timestamp()
+ !^дата.unix-timestamp[]
+ !$дата.year month day hour minute second weekday yearday(0...) daylightsaving TZ weekyear
+ read-only
+ TZ="" << локальная зона
+ !^дата.roll[year|month|day](+-смещение) сдвигает дату
+ !^дата.roll[TZ;Новая зона] говорит, что дата в таком-то часовом поясе: влияет на .hour & Co
+ !^дата.sql-string[] %Y-%m-%d %H:%M:%S
+ where published='^дата.sql-string[]'
+ !^date:calendar[rus|eng](год;месяц) выдаёт неименованную таблицу
+ столбцы: 0..6, week, year
+ !^date:calendar[rus|eng](год;месяц;день) выдаёт именнованную таблицу
столбцы: year, month, day, weekday
-
+ !^date:last-day(год;месяц) вернёт последний день месяца
+ !^дата.last-day[] вернёт последний день месяца $дата
+ !^дата.gmt-string[] Fri, 23 Mar 2001 09:32:23 GMT
+
+
xdoc(xnode)
+ !$xdoc.search-namespaces hash, where keys=prefixes, values=urls
+
DOM1 attributes:
!readonly attribute DocumentType doctype
Xreadonly attribute DOMImplementation implementation
@@ -581,10 +898,15 @@ xdoc(xnode)
!равно текущей кодировке выходной страницы,
$response:charset
::sql{...}
- !::create{} старое имя 'set'
- !::create[qualifiedName]
- !::load[file.xml]
- !.transform[rules.xsl][[params hash]] выдаёт dom
+ !::create[[URI]]{} старое имя 'set'
+ !::create[[URI]][qualifiedName]
+ URI default = disk path to requested document
+ для каталогов конечный / обязателен
+ !::create[file] can be usable:
+ $f[^file::load[binary;http://;some HTTP options here...]]
+ $x[^xdoc::create[$f]]
+ !::load[file.xml[;опции]]
+ !.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[сюда]
+ !если на документ ссылаются так:
+ parser://method/param/to/that/method
+ то в качестве документа используется ^MAIN:method[/param/to/that/method]
+ [примечание: в параметр всегда приходит лидирующая /, даже, если параметров вообще не было]
+
!xnode
DOM1 attributes:
!$node.nodeName
!$node.nodeValue
+ !read
+ !write
!$node.nodeType = int
ELEMENT_NODE = 1
ATTRIBUTE_NODE = 2
@@ -634,16 +964,23 @@ xdoc(xnode)
!$node.previousSibling
!$node.nextSibling
!$node.ownerDocument = xdoc
+ !$node.prefix
+ !$node.namespaceURI
!$element_node.attributes = hash of xnodes
!$element_node.tagName
!$attribute_node.specified = boolean
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
@@ -670,22 +1007,23 @@ 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()
!Introduced in DOM Level 2:
!Node importNode(in Node importedNode, in boolean deep) raises(DOMException)
- !NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName);
+ !NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName)
+ !boolean hasAttributes()
!XPath:
!^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
@@ -709,7 +1047,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
@@ -723,6 +1061,11 @@ xdoc(xnode)
attribute that is already inuse
elsewhere
+!memory
+ !^memory:compact[] собрать мусор, освободив место под новые данные
+ (предупреждение: память процесса никогда не освобождается)
+ полезно делать перед XSL transform.
+
!status
!чтобы класс был доступен, в apache нужно сказать
@@ -736,21 +1079,11 @@ xdoc(xnode)
url time
url time
url time
- !$status:db hash
- !cache hash db_home=>tables table
- name time users
- name time users
- name time users
!$status:stylesheet
!cache table
file time
file time
file time
- !$status:charset hash
- !cache table
- file
- file
- file
!$status:rusage hash
!utime user time used
@@ -759,43 +1092,143 @@ 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]
+
+ !$status:memory hash
+ !used
+ Includes some pages that were allocated but never written.
+
+ !free
+
+ !ever_allocated_since_compact
+ Return the number of bytes allocated since the last collection.
+
+ !ever_allocated_since_start
+ Return the total number of bytes [EVER(c)PAF] allocated in this process.
+ Never decreases.
+
+ !$status:pid process id
+ !$status:tid thread id
+
+console
+ $console:timeout
+ !$console:line
+ read/write строку
+
+DATA::=string | file | hash
+
+!hash вида
+[
+ $.file[имя файла на диске]
+ $.name[имя файла для пользователя]
+ $.mdate[date]
+]
!MAIN
- это класс, загружаемый на автомате из parser3.conf,
+ это класс, загружаемый на автомате из конфигурационного auto.p,
кучи auto.p и запрашиваемого документа:
- !parser3.conf
+ !конфигурационный auto.p
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, имён у предыдущих нет
!после загрузки MAIN класса вызывается его @main[]
- !результат которого передаётся в его @post-process[data] if($data is string) ...
+ !результат которого передаётся в его @postprocess[data] if($data is string) ...
!результат которого отдаётся пользователю
- !если встречается ошибка и try не задан, её можно красиво сообщить пользователю,
+!если встречается ошибка и try не задан, её можно красиво сообщить пользователю,
!определив
!@unhandled_exception[exception;stack]
!$exception.type строка "тип проблемы"
- !$exception.file $exception.lineno файл и строка где случилась проблема [если не запрещены при компиляции]
+ !$exception.file $exception.lineno $exception.colno файл, строка и позиция, где случилась проблема [если не запрещены при компиляции]
!$exception.source строка, из-за которой случилась проблема
!$exception.comment комментарий english
!stack табличка из колонок file line name,
там лежат в обратном порядке имена[name] и места вызовов[file line]
операторов/методов, приведших к ошибке.
- !нужно выключить русский apache: CharsetDisable on
-
+!при загрузке файла (file::load, table::load, xdoc::load) можно указать такое имя файла:
+ !http://domain/document[?params<> создает http.status ошибку,
+ !это можно отключить, передав
+ !$.any-status(1)
+ !$.charset[кодировка удалённых докуметов по-умолчанию] << если сервер вернёт content-type:charset=ОНА_ПЕРЕБИВАЕТ
+ !$.user[пользователь]
+ !$.password[пароль]
+ !file::load в дополнительные поля записывает
+ !ПОЛЕ:значение (имена полей ответа заглавными буквами)
+ !tables << хеш их ПОЛЕ->table с единственным столбцом "value".
+ в таких таблицах можно брать повторяющиеся заголовки. например, несколько set-cookies
+ todo:сделать отдельный cookies
+
+!системные типы ошибок:
+ !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
+ !file.read ^file::load[...] error while reading file
+ !file.seek seek failed
+ !file.execute ^file::cgi[...] incorrect cgi header/can't execute
+ !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
+ !http.host ^file::load[http://notfound/there] host not found
+ !http.connect ^file::load[http://not_accepting/there] host found, but do not accept connections
+ !http.timeout ^file::load[http://host/doc] whole load operation failed to complete in # seconds
+ !http.response ^file::load[http://ok/there] host found, connection accepted, bad answer
+ !http.status ^file::load[http://ok/there] host found, connection accepted, status!=200
+ !date.range ^date::create(1950;1;1) date out of valid range
-!DATA::=string | file
+!нужно выключить русский apache: CharsetDisable on
----
- если в MAIN будет определён флаг $ORIGINS(1) то вместо обычного вывода страницы будет
+Xесли в MAIN будет определён флаг $ORIGINS(1) то вместо обычного вывода страницы будет
выдан список фрагментов результата с указанием их происхождения
+
+!если в MAIN определён $SIGPIPE(1) то в случае, если обработка была прервана пользователем, сообщение
+ об этом будет записано в parser3.log (раньше оно всегда писалось)
+
+!если описание метода содержит локальную переменную result в явном виде
+ (есть и неявная переменная)
+ то код вывода строковых литералов не попадает в конечный байт-код,
+ а непробельные символы считаются синтаксической ошибкой
+ для вывода чего бы то ни было надо пользоваться этой переменной
+