сильно устарело, но базовые идеи живы.
Переменные могут хранить не только строки, но и другие типы значений.
Значение может быть таких типов:
· строка
· число
· истина/ложь
· хеш (ассоциативный массив),
· класс объекта
· объект
· таблица
· код (который будет выполнен позже)
· выражение (которое будет вычислено позже)
Переменная получает значение так:
$имя[значение]
или так:
$имя(выражение)
или при вызове метода:
^имя[значение]
^имя(вычисляемое выражение)
^имя{вычисляемый код}
В дальнейшем из переменной можно достать значение или поле значения, а также вызвать метод объекта, если тип значения - объект/класс.
Для удобной работы с подзначениями и методами можно использовать конструкцию
$имя{
код, обращающийся к полям/методам переменной,
не указывая всё время
$имя.поле или ^имя.метод[…]
}
Начнём с простого, задание и передача строковых значений:
@main[] метод, с которого начинается выполнение
$переменная[значение]
^метод[$переменная]
@метод[аргумент] выводит аргумент
аргумент=$аргумент
получится:
аргумент=значение
Числовые значения и выражения:
$переменная(выражение)
например:
$горшок(5) $вершок(1)
$возраст($горшок+2*$вершок)
возраст=$возраст
получится:
возраст=7
Главное: задавая значение переменной в круглых скобках мы можем задавать не просто константу, но выражение.
Та же идея и при передаче параметров:
@main[] проверка передачи выражения в метод
^метод(2000+1)
@метод[аргумент] тупо печатает свой аргумент
аргумент=$аргумент
получится:
аргумент=2001
Хэш (ассоциативный массив):
Задание значения переменной:
$человек[
$.возраст(27)
$.рост(1.72)
$.цвет_глаз[красный]
]
Получение поля значения:
$человек.возраст 27
Задание значения аргумента метода:
@main[] передаём параметром хэш
^нарисовать_ящик[
$.ширина(3)
$.высота(4)
$.глубина(6)
]
@нарисовать_ящик[ящик] выводит поле аргумента
действия по отрисовке ящика
$ящик{$ширина / $высота / $глубина}
получится:
действия по отрисовке ящика
3 / 4 / 6
С ящиком и размерами разобрались?
Ясно, что с ящиком можно делать много чего, и глупо всё время писать хвост «нарисовать_ящик», да передавать параметром [ящик], а потом ещё и переключаться для работы с ним: $ящик{…}.
Напрашивается что-то, позволяющее просто работать с ящиком, и всё.
Создадим box.p, и напишем там:
@CLASS
ящик
@создать[ш;в;г] создать новый пустой ящик
$ширина($ш)
$высота($в)
$глубина($г)
@нарисовать[] без параметров!
Действия по отрисовке ящика
$ширина / $высота / $глубина
Вот мы и описали класс объекта.
Делай 1: перестань трястись, заслышав это.
Делай 2: тащись - ведь здорово, что всё, относящееся к ящику снесено в отдельный файлик, и там не нужно писать на каждом шагу «ящик», ведь ясно, что всё, что там делают, делают ясно с чем.
Теперь создадим небольшой ящик и побалуемся с ним:
@USE
box.p
@main[]
$коробок[^ящик:создать(0.5;0.3;0.01)]
ширина коробка=$коробок.ширина
^коробок.нарисовать[]
получится:
ширина коробка=0.5
Действия по отрисовке ящика
0.5 / 0.3 / 0.01
Теперь маленькая тайна:
Все значения в Парсере теперь объекты.
Возьмём строку:
$вася[======]
$федя[============]
можно легко подсчитать,
^вася.length[] 6
^федя.length[] 12
что у васи длиннее.
Тут вася, это объект класса «строка», а объекты этого класса имеют, кроме прочих, метод «length», выдающий её длину.
Числа тоже имеют свои методы:
$итого(349.3)
принято печатать деньги с двумя цифрами после запятой:
^итого.format[%.2f] 349.30
Теперь все готовы к понятию таблица.
Просто код:
$разделы[^table:set{uriàзаголовокàцвет
/news/ |
Новости |
White |
/admin/ |
Администрирование сервера |
Black |
}]
$разделы{
^if(^locate[uri;/news/]){
<font color=$цвет>$заголовок</font>
;
нет раздела /news/
}
}
Работа с базой:
$sections[^table:sql{select uri,title from sections}]
$sections{^menu{
^if($uri eq “/news/”){
<b>$title</b>
;
<a href=$uri>$title</a>
}<br>
}}
Уже, наверное, обратили внимание, что параметры в if передаются занятно. Условие в () а тело в {}.
Такой подход можно использовать и в своих методах.
В чём дело:
Передавая параметр в [], мы передаём его вычисленное значение. Ещё раз: значение вычисляется до вызова метода.
^метод[какие-то действия]
@метод[аргумент]
код, не использующий аргумент совсем
так вот: действия будут выполнены в любом случае. В контексте вызова.
Передавая же параметр в {}, мы передаём кусок кода, который будет выполнен только при необходимости – при получения его значения.
^default{действия1}{действия2}
^default{действия1;действия2}
@default[a;b]
^if(def $a){$a;$b}
Передача именованных кусков кода(методов) параметром:
@main[]
^мучения[$послать_письмо_админу]
@послать_письмо_админу[заголовок]
отправляет письмо на admin@design.ru про $заголовок
@мучения[обработка_ошибки]
долгие мучения, в ходе которых может выясниться,
что чего-то сделать нельзя, в случае чего надо будет сделать
^обработка_ошибки[у меня сломались «действия»]
…
Передавая параметр в (), мы передаём не результат вычисления выражения, а само выражение. Оно будет вычислено позже:
^покрасить_забор($i*2)
@покрасить_забор[цвет]
^for[i](1;5){
<font color=$цвет>планка</font>
}
получится:
<font color=2>планка</font>
<font color=4>планка</font>
<font color=6>планка</font>
<font color=8>планка</font>
<font color=10>планка</font>
Операторы.
http://parser3.office.design.ru/docs/operators.txt
Системные классы.
unknown, int, double, string, table сейчас опускаем.
Вкратце об остальных
form
<input name=education value=”невежа”>
$form:education невежа
env
$env:REMOTE_HOST paf.office.design.ru
cookie
$cookie:user[вася]
^if(def $cookie:user){
Здравствуйте, $cookie:user.
;
Привет, незнакомец.
}
request
$request:uri /address.html?full
$request:browser.version 5.5
response
$response:body[вместо обычного ответа уйдут эти буквы]
^mail:send[
$from[paf@design.ru]
$to[admin@design.ru]
$cc[yuricle@design.ru]
$subject[parser3: большой тестовый сервер]
$body[
$1[Лёшик/Андрюшич,
создайте, пожалуйста, Юре тестовый сервер вот с этим
parser3, что прилагаю. Имя сервера скажет Юра.
С любовью,
PAF]
$attach[^file:load[parser3.zip]]
]
]
image
$рисунок[^image:create(200;100)]
^рисунок.line(0;0)(20;10)(0x0000FF)
$response:body[^рисунок.gif[]]
$логотип[^image:measure[/i/logos/${firm_id}.gif]]
^логотип.html[$alt[$firm_name]]
<img src=”/i/logos/48.gif” width=”60” height=”54” alt=”BMW” border=0>
file
$имя[some.zip]
$информация[^file:stat[$имя]]
Размер $имя = $информация.size
random
^random:generate(100)
0..99
MAIN
Тот .html, который вы создаёте, содержит методы объекта MAIN.
При
обработке запрашиваемого пользователем документа объект MAIN содержит методы не только из
запрошенного .html файла, но также из всех auto.p файлов, которые будут найдены… рядом с .html файлом, в каталоге над ним, в
каталоге ещё выше, и т.д. вплоть до корня веб пространства.
А также ещё в одном
системном каталоге, который зависит от варианта установки Парсера. Тот auto.p управляется администратором.
Каждый найденный auto.p становится родителем предыдущего. Про наследование классов позже.
Локальные переменные:
@метод[параметры][локальные переменные]
пример
$i[not local, field]
@действия[сколько][i] тут i локальна
^for[i](0;$сколько-1){
…
}
$self.i = not local, field
$title[not object’s title]
$object{
$title = $object.title
$:title = not object’s title
}
Значения переменных могут поступить извне, и просто так использовать их нельзя[причины обсудить с каждым непонявшим отдельно].
Термин: грязный(tainted). Данные, поступившие извне, считаются «грязными», и перед использованием они соответственно обрабатываются.
Термин: язык. В каждом конкретном случае значение подставляется куда-то, где изъясняются на каком-то языке.
От языка зависит, как именно надо обрабатывать грязные данные.
Поддерживаемые языки:
· file
· header
· uri
· table
· sql
· js
· html
· user-html
из интересного: user-html
по-умолчанию раньше был, в наших терминах, html язык.
И всё, что чинилось, это < в < и Co.
Теперь язык по-умолчанию: user-html
И замены, которые происходят в пользовательском тексте, контролируются табличкой замен, которая находится в руках скриптовальщика:
Допустим, задана такая таблица:
$user-html[^table:set{useràhtmlàcomment
<< |
«^; |
длинные user вперёд |
>> |
»^; |
|
\n\n |
<p> |
!эти есть в таблице по умолчанию |
\n |
<br> |
!но т.к. заменяем, надо повторить. |
< |
<^; |
!можно этим воспользоваться, |
> |
>^; |
!и что-то сделать ДО обычных замен |
" |
"^; |
!например из << и >> |
& |
&^; |
!сделать ёлочки-кавычки. |
_ |
 ^; |
|
^#AB |
«^; |
windows коды ёлочек |
^#BB |
»^; |
windows коды ёлочек |
(c) |
©^; |
|
^#A9 |
©^; |
windows (c) |
}]
тогда при выводе $form:title
где пользователь ввёл
А.Ф._Петросян <<Жизнь в аду>>.
Browser получит
А.Ф. Петросян«Жизнь в аду».
Использование ряда букв:
Если в тексте нужна буква, имеющая в Парсере специальный смысл, предварите её ^.
Если в тексте нужна буква, от которой известен её шестнадцатеричный(hexadecimal) код, но неизвестен способ нажать кнопку на клавиатуре, чтобы такая буква вылезла, или по какой-то причине это нежелательно, используйте ^#XX, где XX это две цифры кода(обязательно две).
Регулярные выражения (PCRE).
$текст[а1б1а2б2]
#результат match со (), это таблица, без () истина/ложь
$результат[^текст.match[(a)(.);g]]
$результат{
^count[] 2
^menu{
$1/$2<br>
} a/1 a/2
}
Наследование, виртуальность.
some.p
@CLASS
жирная_новость
@USE
news.p
@BASE
новость
@вывести[]
<b>^BASE.вывести[]</b>
@BASE
жирная_новость
@вывести[]
<i>^BASE.BASE.вывести[]</i> -- shit, but works
<i>^новость:вывести[]</i> -- shit, but works
<b>сегодня мы выпили миллионную чашку кофе</b>
TODO
Получение класса объекта
Проверка типа значения