Абрис 1 - Руководство
|
Язык программирования Абрис 1.Версия документа 1.3 Последнее изменение 29.09.04 Данный документ является краткой "пилотной" версией руководства к языку Абрис - языку программирования гипертекстовых оболочек к базам данных системы представления знаний Абриаль. Документ рассчитан на продвинутых в программировании читателей. Требуется знание основ HTML, принципов функционирования Веба (WWW), реляционных баз данных, желательно знакомство с объектно-ориентированной идеологией, понимание концепций объекта, класса, отношения, запроса, и т.д. Необходимо хотя бы поверхностное знакомство с идеологией системы Абриаль. В конце документа приведен Словарик основных терминов. Дополнением и продолжением данного документа является Описание Примитивов, т.е. встроенных операций и операторов языка Абрис. Если Вас не пугает все сказанное выше, желаю успешного изучения Абриса. А.И.Пацкин (автор системы Абриаль)
Что такое Абрис.Абрис в узком смысле - это язык функционального объектно-ориентированного типа для макрогенерации страниц гипертекстовых оболочек баз данных системы Абриаль. В широком смысле это система программирования нового поколения, реализующая идею датацентрических приложений. Датацентризм - это идеология, переносящая центр тяжести приложений на резидентные объекты распределенной и потенциально бесконечной сетевой базы данных, и дающая пользователю средства непосредственной манипуляции этими объектами через стандартизованный прозрачный интерфейс гипертекстовых оболочек, убирающих основную преграду между пользователем и базой данных - сложную самостоятельно организованную среду исполнения программы. Что такое Абриаль.Абриаль 2 представляет собой среду для быстрой разработки сложных активных баз знаний и приложений на их основе. По заданной пользователем структуре данных система сама автоматически строит интерфейс для просмотра и изменения данных. Добавление новых типов данных мгновенно отражается на автоматически изменяемом интерфейсе и может быть тут же испытано, что, однако, не затрагивает ранее введенные данные и их структуру. Приложение в среде системы Абриаль 2 имеет датацентрическое устройство: оно представляет собой активную базу данных, заключенную в активную интерфейсную оболочку. Активность реализуют вычислительные конструкции, встроенные и в саму базу данных, и/или в интерфейсную оболочку. Основополагающей новацией в системе Абриаль 2 является её модель данных, имеющая ряд общих черт с объектной, реляционной и с логической (предикатной) моделями представления данных, и в то же время отличная от этих моделей в одном очень существенном аспекте: модель Абриаля изотропная , это значит, что тут полностью исключены односторонние ссылки, а вместо них используются двухсторонние и многосторонние связи, проходимые во всех направлениях качественно одинаковым образом. Основополагающая идея языка Абрис.Нет смысла изобретать новый язык программирования, если в основе нового языка не будет какой-либо фундаментальной идеи, существенно продвигающей развитие области и не реализованной ни в одном из существующих языков. Это справедливо и для Абриса, поэтому новая фундаментальная идея Абриса должна быть четко сформулированной. Попробуем это сделать вкратце. Развитие программирования в 20-м веке в определенном аспекте (очень грубо!) шло в трех направлениях 1) Центральное - структуры среды исполнения (ООП, списки, продукции и т.д.). 2) Базы данных (SQL, XML...) 3) Интерфейс пользователя (HTML, JScript, Дельфи...). Это фактически привело на грани веков к созданию трех различных миров (их ключевые слова приведены выше в скобках). В результате, для стержневой задачи современных информационных технологий, для работы в Сети с базами данных необходимо наличие этакого "слоеного пирога" между пользователем и объектами данных. В этом "пироге" присутствуют все три мира, каждый со своими порядками и сложностями; и между кликом пользователя по экрану и получением ответа все эти миры задействуются. Но это происходит так, что пользователь не видит объектов базы данных как таковых, они заслонены от него "слоеным пирогом". Вообще говоря, объектов может и не быть (особенно если используется строго реляционная идеология организации БД) не говоря про объекты среды исполнения, каковые являются внутренним делом конкретного программиста, и как детали реализации никого не интересуют. В итоге пользователь видит среду не как сеть логически взаимосвязанных объектов проблемных областей, а как множество страниц, не соотносимых ни с какими объектами. Всякие согласования объект-страница или ссылка-объект возникают лишь случайно и непредсказуемо. В результате, на программиста ложится огромная ответственность, забота и труд - каждый раз изобретать эту объектную среду заново, (или - не изобретать, оставляя пользователю взгляд на его среду через замочную скважину). А на пользователя ложится забота изучать от нуля каждую новую систему построенную из своих окошек и страничек, в которую конкретный программист вносит свою неповторимую индивидуальность, философию и свои взгляды на мир. Идеология датацентризма - вообще, и язык Абрис - в частности, призваны решить эту проблему кардинальным образом. Среда исполнения ликвидируется - путем погружения вычислений в саму базу данных. В Абрисе нет никаких типов данных кроме текстовых строк. В Абрисе минимально используются переменные, а массивы и структуры будут заведены для эпизодического использования лишь в последующих версиях - в основном они заменяются на прозрачные потоки данных проходящие среду исполнения Абриса насквозь. Среда интерфейса тоже ликвидируется, но иначе. Типичный пример среды интерфейса: Дельфи или JavaScript/DHTML, где элементы интерфейса имеют свои имена и программа читает или пишет данные по этим именам. Идея макрогенерации и функциональный стиль Абриса - убирает необходимость в именовании элементов интерфейса - всякая конструкция Абриса производит некий текст, который подставляется вместо неё, и интерпретируется, таким образом, по месту, декларативно, а функциональность полученного HTML-текста отдается на откуп стандартному броузеру. В итоге пользователь получает стандартный интерфейс и стандартную логическую среду для манипуляции с любыми существующими и будущими объектами. Причем данный интерфейс опирается на логически ясную и прозрачную среду проблемных объектов пользователя, а не каких-то непонятных страничек, изобретаемых программистом в рамках его собственной философии. Каждая страничка соответствует некоторому объекту и/или определенному аспекту сложного объекта, и каждая ссылка соответствует либо действию с логическим объектом либо навигационному переходу на него.
Работа строится на основе последовательности обращений пользователя к базе данных, аналогично тому, как это происходит в рамках технологии CGI. Точнее, существует два варианта работы программы Абриаль:
В первом (клиентском) варианте используется специальная версия броузера, встроенная в программу Абриаль и понимающая язык Абрис. В серверном варианте используется обычный (в данном случае - уже любой) броузер, работающий из-под любой ОС. Для языка Абрис это различие незаметно, постольку поскольку безразлична конкретная реализация, т.е. конкретная форма ссылок, используемых на страничке. В момент написания данного руководства полноценная реализация технологии существует для её клиентского варианта, т.е. в виде программы Абриаль. Для серверного варианта существует пока только прототип с рядом существенных ограничений функциональности и с не решенным пока вопросом: будет ли сохраняться контекст пользователя, и если будет, то какими средствами, (cookie, скрытые поля...). В целом Абрис работает по следующей схеме:
Особенности технологииТаким образом, исполнение программы на Абрисе начинается с запроса пользователя в момент его нажатия на кнопку формы или выбора ссылки, состоит в генерации страницы и/или с возможным изменением данных в базе данных и после полного формирования страницы заканчивается. При этом существенны следующие технологические моменты:
Навигации по сети и действия с сетью.Работа системы с использованием Абриса строится из последовательности шагов: запрос-генерация-ответ. Запросы логически делятся на две разновидности: шаги навигации и действия. Каждая страница относится к определенному объекту определенной базы данных, отображаемому определенным методом, возможно с параметрами. Очередной запрос содержит новую совокупность: БД, объект, метод и параметры метода, иными словами, задает определенную точку навигации. Шаги навигации, т.е. переходы от точки к точки меняют что нибудь в запросе и соответственно изображают другую страничку, но как правило ничего не меняют в данных т.е. не меняют базу данных. Действия, напротив, не меняют отображаемую точку навигации, но меняют данные в базе данных. Шаг навигации происходит проще. Страничка генерируется в соответствии с новым запросом и посылается пользователю. Действие производится в два этапа: сначала вызывается метод из запроса, который по идее должен что-то изменить в базе данных, формально он устроен так же как шаг навигации, т.е. также может генерировать некий текст, например, сообщающий пользователю что действие выполнено, или, что его не удалось выполнить. Но этот текст не посылается в страничку, а попадает в специальную системную переменную RESULT. Затем повторяется в точности предыдущий навигационный запрос, т.е. генерируется страничка соответствующая последнему шагу навигации. Внутри этой странички может быть предусмотрено место для отображения текста из переменной RESULT. При первом отображении навигационной странички переменная RESULT была пуста, она очищается в начале каждого шага. И соответственно, ничего на страничке не извещало о результате действия - ведь его пока еще не было. Итак, работа состоит из ряда навигационных запросов, меняющих точку навигации, но не меняющих данные, и в определенной точке навигации, т.е. после очередного шага навигации может следовать ряд запросов действий, изменяющих данные в этой же точке. Формально запрос действия отличается от навигационного запроса наличием параметра ACT, задающим имя метода - действия (см. раздел Структура запроса). Структура запросаЗапрос логически представляет собой множество параметров, т.е. пар вида Имя=Значение, где Имя - идентификатор (из латинских букв, знака "_" и цифр, начинающийся с буквы или знака "_"), а Значение - любая строка символов, не содержащая нулевого символа. Регистр букв учитывается. В одном запросе каждое имя уникально с учетом регистра. Физически, т.е. в виде текста на страничке запрос представляется в виде гиперссылки, вид которой зависит от варианта системы, например для клиентского варианта ссылка может выглядеть так: ab://ab/D=C%3A%5CABRIAL%5C%5FBASES%2EAB&O=559 а целиком тег A, содержащий эту ссылку будет выглядеть так: <A HREF="ab://ab/D=C%3A%5CABRIAL%5C%5FBASES%2EAB&O=559">Медицинская диагностика</A> Данная ссылка содержит два параметра:
Типы данныхВ языке Абрис имеется только один тип обрабатываемых данных, а именно строки или, в более общем виде последовательности строк, т.е. текст. Числа, целые и вещественные обрабатываются непосредственно в своем строчном представлении. Системные идентификаторы (иды, IDs) объектов БД представляются в виде строчной записи соответствующих целых положительных чисел. Логические (булевские) значения представляются следующим образом. Пустая строка, с длиной 0, представляет логическое значение FALSE (ЛОЖЬ), любая непустая строка представляет логическое значение TRUE (ИСТИНА). Стандартное значение для TRUE, возвращаемое логическими операциями - один пробел, " ". МетодыВ языке Абрис работа программы состоит в вызове методов (т.е. функций) которые в качестве результата возвращают текст. Вызов главного метода, указанного в параметре M запроса (ссылки) возвращает текст страницы, отображаемой пользователю. В случае, если параметром ACT указан главный метод действия, всё происходит также, только результирующий текст попадает не в отображаемую страничку, а в промежуточное хранилище, - переменную RESULT. Итак, по сути методы в Абрисе, это - функции возвращающие текст. По форме методы делятся на
Примитивные методы аналогичны обычным операторам и встроенным функциям в языках программирования высокого уровня. О них речь ниже, а здесь мы рассмотрим разницу между макросами и (метод-) функциями. Макросы и функцииПо сути и те и другие являются функциями, но - задаваемыми в разных формах. Метод функция, как обычная функция в классическом языке программирования задается в тексте программы в форме параметризованного выражения. То, что возвращает это выражение после вычисления с подставленными параметрами - это и есть результат функции. Макрос же представляет собой произвольный текст на любом языке, или вообще не на языке, который сам по себе и является результатом вычисления, но перед тем как он возвращается должно произойти макрорасширение , то есть вычисление всех макротегов содержащихся внутри текста макроса и подстановки их результатов на их места. Макро-тегиМакротег - это вызов Абрис-выражения внутри макроса. Семантика макротега такова: при макрорасширении выражение вычисляется и его результат подставляется на место макротега. Формат макротеговСинтаксически макротег аналогичен тегу HTML, т.е. это имя с возможными параметрами в угловых скобках <#Name[param=val]...>, но в макротеге, в отличие от простого HTML-тега, после открывающей угловой скобки непосредственно следует знак #. Вообще говоря, в тексте макроса последовательность таких символов: <# здесь может идти что угодно, (но с уравновешенными "кавычками" и (круглыми) или <угловыми> скобками ) > считается макротегом. Если в макротеге что-то неправильно, т.е. например допущена ошибка, без нарушения формата, т.е. не выходящая за границы макротега, то в результате его вычисления получится пустая строка. Макротеги и HTML.С практической точки зрения макротеги Абриса и теги HTML обычно структурно согласованы, но это вообще не обязательно, т.к. с точки зрения Абриса текст HTML, как и любого другого языка, есть просто набор символов. Структура HTML-тегов для Абриса совершенно безразлична: Абрис может генерировать HTML не только целыми тегами, а любыми фрагментами тегов в произвольных комбинациях. Например: макротег может после вычисления выдать результат: строку "><", состоящий из закрывающей скобки одного тега и открывающей скобки последующего. Операторы, закрывающий макротег.Как и теги в HTML, макротеги могут быть сложными, объемлющими часть текста макроса. Сложными в Абрисе являются макротеги, вызывающие некоторые примитивы (примитивные методы), например, операторы цикла (FOR FORALLOBJ) или определения макроса в тексте (MACRO). Сложный макротег включает в себя "тело" т.е. следующий за макросом текст вплоть до и включая соответствующий закрывающий макротег <#/>. Признаком закрывающего макротега является комбинация "<#/" Между знаком "/" и закрывающей скобкой ">" может находиться имя или любой другой текст с уравновешенными скобками и кавычками, который игнорируется. Сложные макротеги могут быть вложены и содержаться внутри других сложных макротегов, создавая структуры с произвольным уровнем вложенности. Как и для простых макротегов, сложные также не обязаны соответствовать структурам вложенности HTML.
Общая структура приложенияПриложение на Языке Абрис представляет собой набор макросов, макросы являются либо текстовыми файлами, либо текстовыми объектами базы данных. Также макрос может быть определен в момент исполнения другого макроса с помощью оператора (составного примитива) MACRO: <#MACRO MacroName> First string of macro Value of 1-st paramether=<#1> Sum of 1-st paramether and number 3='<#SUM (1) 3>' Value of paramether AN='<#AN>' Last string of macro <#/> Результатом вызова данного макроса с помощью макротега <#MacroName 5 AN="Rel\Asp1"> Будет следующий текст: First string of macro Value of 1-st paramether=5 Sum of 1-st paramether and number 3='8' Value of paramether AN='Rel\Asp1' Last string of macro Из примера видно как несколько макротегов внутри текста макроса заменились при вычислении на свои значения. Итак приложение есть множество макросов, каждый из которых представляет собой множество строк текста на произвольном языке, включающих внутри себя макротеги, то есть выражения языка Абрис в специальных теговых скобках <#...>. Внутренность макротега может располагаться в нескольких строчках. Внутри макротега могут быть в качестве аргументов находиться другие выражения. Для этих внутренних выражений могут использоваться скобки трех типов:
Наиболее удобно и естественно использовать для внутренних выражений обычные круглые скобки, что делает синтаксис языка Абрис напоминающим язык Лисп. В следующей таблице видно различие синтаксиса между Си, Лиспом и Абрисом:
Как видим основные отличия синтаксиса Абриса от классических языков (Си) состоят в записи переменных, литералов и вызовов функций.
Подробнее о синтаксисе Абриса см. следующие разделы. Общий принцип организации текстаТекст макросов на в системе языка Абрис состоит из двух четко разделенных частей:
Таким образом, описание синтаксиса Абриса состоит из описания синтаксиса комментариев и синтаксиса выражений. Синтаксис комментариевИмеется четыре разновидности комментариев.
Обратим внимание: комментарии в стиле Си/Си++ (случаи 1,2) полностью игнорируются, как если бы на их месте были пробелы. Но следует учитывать, что REM и XXX все таки являются вызовами выражений, возвращающими пустоту, и будучи вставлены в качестве операнда/аргумента эти примитивы засчитывается, так что вставляя их внутрь выражения мы сдвигаем номера последующих аргументов на единицу. В качестве таких комментариев можно было бы использовать и любую абракадабру, однако это неразумно, т.к. на поиск несуществующих методов может затрачиваться значительное время. Синтаксис выраженийВыражение представляет собой один из следующих вариантов:
ЛитералыЛитералы, т.е. строчные константы в общем виде записываются как строчки в кавычках. Кавычки внутри литерала сдваиваются. Если литерал начался с кавычки и до конца строки не встретилась закрывающая кавычка, конец строки ограничивает литерал. Таким образом переводы строк и другие знаки, отсутствующие на клавиатуре, внутри литералов не имеют представления. Другими словами, литерал не может представлять несколько строк. Но имеется отдельный вариант литерала, содержащий ровно один перевод строки, именно знак "\".
Литералы состоящие только из цифр, латинских букв обоих регистров и знака подчеркивания можно записывать без кавычек, если они не стоят на первом месте внутри скобок. Но если такой литерал стоит следом за открывающей скобкой, (круглой "(" угловой "<" или макросной "<#"), он должен браться в кавычки, чтобы не быть воспринятым как имя функции. Также обратим внимание, что в кавычки нужно брать отрицательные и дробные числовые константы, т.к. они содержат знаки минус и точку. ПеременныеОбращение к переменным выглядит в абрисе так же как к функциям без аргументов: имя переменной заключается в скобки. Обратим внимание, что это же имя без скобок означает литерал т.е. строчную константу. Позиционные и ключевые параметрыК методу (к функции) можно обращаться с позиционными параметрами, аргументами (method aaa bbb ccc) или с ключевыми или атрибутами в стиле HTML : (method k1=value1 k2=value2). Атрибуты (ключевые параметры) внутри вызываемой функции превращаются в обычные локальные переменные, которым при входе в функцию присваиваются значения равные результатам вычисления выражений (value1 value2) стоящих после знака "=". К позиционным параметрам внутри функции можно обращаться по их номеру, взятому в скобки. Например, внутри функции вызванной выражением (method aaa bbb ccc) обращение (2) вернет bbb. Вызовы методовВызов любого, в том числе примитивного метода не отличается от обращения к переменной. Он заключается в скобки и состоит из имени, т.е. идентификатора, за которым через пробелы могут следовать параметры, позиционные и ключевые. Позиционные параметры- это просто любые выражения. Ключевые параметры- это пары Имя=выражение разделенные знаком равенства. (MethodName (positional) Key=(attr_value)) По соглашению имена всех примитивных методов состоят только из больших латинских букв, причем не менее двух. Поэтому для избежания конфликтов имен для переменных или методов разумно использовать либо однобуквенные идентификаторы, либо имена содержащие маленькие буквы или цифры. Вызовы примитивовВызов примитива по форме ничем не отличается от вызова составного метода. Только можно отметить что некоторые примитивы являются сложными, и на уровне макроса требуют закрывающего тега. Например, примитив IF проверяет некоторое условие и весь последующий текст макроса вплоть до закрывающего макротега <#/> (включительно) относится к этому же примитивному оператору: <#IF (condition)> Безымянная операцияНаиболее частые операции в языке две: это конкатенация (склейка из кусков) текста и присваивание значений локальным переменным. В старых версиях языка эти операции исполнялись примитивами с именами, соответственно, TEXT и SET. Теперь эти операции объединены в одну безымянную операцию, для которой имя примитива можно опускать. Впрочем, явные имена TEXT и SET для этой операции могут использоваться как прежде. Действие этой обобщенной операции состоит в сцеплении результирующих значений всех безымянных параметров и выдачи полученного значения в качестве результата операции, а также в последовательном исполнении всех именованных параметров, как присваиваний локальным переменным с именами, соответствующими именам параметров. Все выражения в параметрах вычисляются в порядке их следования, так что если на N-м месте стоит присваивание некоторой переменной, то выражения в параметрах N+1 и далее могут использовать эту переменную с новым значением. Присваивания ничего не возвращают (sic! в отличие от Си, где присваивания возвращают присвоенное значение). Имя операции считается опущенным, если сразу следом за открывающей скобкой или после знака бинарной операции нет латинского идентификатора, а находятся:
В перечисленных случаях эти четыре варианта считаются первым параметром безымянной операции. Обратим внимание, что число не взятое в кавычки, после открывающей скобки обозначает позиционный параметр, а после бинарной операции - литерал. Данное усложнение принято для того чтобы такие часто встречающиеся выражения операции как (X+2) трактовались бы как (X+"2") а не как (X+(2)) что потенциально привело бы к большому числу трудно различимых ошибок. Как вариант безымянной операции может рассматриваться пустая операция, когда вместо ожидаемого имени операции следует признак её конца, в виде:
Пустая операция ничего не возвращает и эквивалентна литералу "". Переменные предикаты.Если после открывающей скобки вместо идентификатора, находится выражение в угловых скобках, это значит что имя или содержание метода вычисляется в процессе исполнения. Рассмотрим оба варианта:
Бинарные операции.Основной недостаток скобочного синтаксиса( а-ля Лисп) - трудность в слежении за числом скобок для уровней вложенности выражений больше двух-трех. Пропуск скобки или лишняя скобка это - трудно находимые ошибки, но они же - наиболее типичные. Из-за этого с текстом нетривиальных программ становится трудно работать. Для устранения этой трудности в язык введены бинарные операции, позволяющие заменять вложение выражений на последовательное исполнение, что сокращает число скобок. Общая идея: в скобках записывается последовательность, разделенных знаками бинарных операций сегментов. Каждый сегмент представляет собой вызов обычной операции, переменной или метода. Сегменты и бинарные операции вычисляются в порядке следования. Каждая бинарная операция в качестве первого (левого) операнда берет всё, что вычислено слева от неё т.е. до этого момента. А правый операнд знака дает выражение, расположенное справа, т.е. непосредственно следом за операцией. Реализованы следующие знаки операций:
Подробнее о порядке исполнения операций.
Использование скобок для выражений.Замечание. Во всех внутренних выражениях кроме самого первого после открытия скобки разрешается использовать любые из трех видов скобок, в этих случаях семантика использования скобок не различается. Таким образом, макротег (но не оператор!) можно перенести в точности 1:1 из текста макроса внутрь какого-нибудь выражения в качестве параметрического выражения. В текущей версии соответствие типа открывающей и закрывающей скобки не проверяется. Даже для закрытия макротега можно использовать круглую скобку. Однако, отсутствие такой проверки в будущих версиях не гарантируется, так что использование разных скобок для открытия и закрытия не рекомендуется из соображений совместимости.
Порядок вычислений
ПеременныеПеременные хранят значения только строчного типа, т.е. строки и тексты или последовательности строк. Размеры значений не ограничены. Есть два вида переменных локальные и глобальные. Локальные переменные образуются и изменяются операцией SET, глобальные - операцией GLOB. (SET n=8 abc="some word") // переменой n присвоено число "8", а переменной abc - строка "some word" Если SET заменить на GLOB, образуются или изменятся глобальные переменные с такими именами. Однако рекомендуется с точки зрения стиля, именовать глобальные переменные с заглавной буквы, а локальные переменные только строчными буквами. Имя операции SET может быть опущено: (n=8 abc="some word") // эквивалентно предыдущему примеру Область действия локальной переменной: только текущий вызов функции; при входе, вызове других функций, локальные переменные становятся недоступными, при выходе из функции - теряются. Именованные (ключевые) параметры вызовов методов превращаются при входе в функцию, реализующую метод, в локальные переменные с теми же именами. Область действия глобальной переменной - от момента её образования, до момента её удаления. В версии Абриаля 2.0 набор глобальных переменных привязан к окну броузера: у разных окон наборы глобальных переменных - разные, при закрытии окна - все набор глобальных переменных уничтожается. Вопрос о способе поддержки глобальных переменных для серверной версии, т.е. где они будут храниться, в куках или еще где-то - пока открыт. Операция удаления глобальных переменных пока в версии 2.0 не реализована. Глобальные переменные могут быть заслонены одноименными локальными переменными. Агрегатные значенияЗначение переменной (как и вообще любое значение, возвращаемое выражением в Абрисе), это либо текстовая строка, либо множество строк (текст). Большинство операций работает с этими значениями, как с единым целым. Однако можно рассматривать текстовые значения как агрегаты, имеющие внутреннюю структуру и работать с элементами этой структуры по отдельности. В Абрисе существует два основных вида агрегатов, а именно: это списки строк с доступом по номеру (обычные массивы), и записи или словари с доступом по ключу (ассоциативные массивы). Т.к. терминология пока не устоялась, в дальнейшем тексте слова внутри нижеследующих групп считаются синонимами:
СпискиЛюбое значение в Абрисе это текст, т.е. строка разделенная внутренними знаками перевода строки на список из строк. Абрис позволяет обращаться к элементам этого списка т.е. к элементарным строкам по их порядковому номеру в списке. Например, если значение переменной (S=("ПЕРВАЯ" \ "ВТОРАЯ" \ "ТРЕТЬЯ" \ "ЧЕТВЕРТАЯ") ) состоит из нескольких строк: ПЕРВАЯ ВТОРАЯ ТРЕТЬЯ ЧЕТВЕРТАЯ то можно обратиться в выражении (S 3) к третьей строке, что вернет результат ТРЕТЬЯ. Заменить третью строку можно операцией: (S 3 PUT="3-я"). ЗаписиЗаписи или ассоциативные массивы состоят из пар Ключ=Значение, упорядоченные по ключу и без повторов ключей. Например, после присваивания: (P=("ИМЯ=ИВАН" \ "ОТЧЕСТВО=ИВАНОВИЧ" \ "ФАМИЛИЯ=ИВАНОВ" ) ) выражение (P "ОТЧЕСТВО") вернет результат ИВАНОВИЧ. Изменить отчество можно операцией (P "ОТЧЕСТВО" PUT="Петрович"). Индексные параметрыОбращаться к структурным частям значений переменных можно с помощью цепочки специальных индексных параметров (аналогичных индексам массивов в традиционных языках). Выражения - индексные параметры должны следовать сразу за именем переменной. Если очередной индексный параметр безымянный, то он, в зависимости от значения, означает либо числовой индекс в обычном массиве (номер в списке, начиная с 1) или идентификатор (ключ) в ассоциативном массиве. Так в приведенных выше примерах, индекс 3 (число) достает третий элемент списка, а индекс "ОТЧЕСТВО", числом не являющийся, используется как ключ в записи (в ассоциативном массиве). Вложенные агрегаты. Внутри строки элемента списка или записи в упакованном виде может храниться другой список или другая запись. Поэтому обычные строки в Абрисе могут использоваться как многомерные массивы или многоуровневые записи. Доступ к глубоким элементам этих структур осуществляется цепочкой индексов, следующей за именем переменной. В разных элементах одного списка данные хранятся независимо, списки, записи и скалярные значения могут произвольно чередоваться. Никакая структурная информация по формату того, что в данный момент лежит в элементе структуры, не сохраняется. Стандартны только методы упаковки/распаковки, но данные, которые кладутся в структуры или извлекаются из них, зависят только от обращения в процессе исполнения. При недостаточном числе индексов будет возвращаться упакованная в строчку структура, а при избыточном числе индексов система будет пытаться распаковать элемент и при неудаче возвратит пустоту. Метод упаковки использует запятые для разделения и двойные "кавычки" для объединения. "Кавычки ""удваиваются"" внутри других кавычек". Для ключей в записях используется знак равенства. Точная спецификация метода упаковки в языке не фиксируется. Программист не должен рассчитывать на её преемственность в следующих версиях, за исключением того, что упакованная в строку структура будет "читабельна". Каждый очередной индекс в цепочке индексных параметров обращается к значению, полученному на предыдущем шаге от предыдущего параметра. Все параметры кроме последнего являются параметрами чтения, последний же может быть параметром чтения или записи/изменения. Тип параметра задается его именем. Индексные параметры перечислены в следующей таблице.
Создание списковКаждое значение в Абрисе фактически представляет собой список строк. Поэтому все функции и операции возвращают списки. Но чтобы создать конкретный заранее известный список можно воспользоваться списком литералов, разделенных литералом новой строки \ например, выражение ( "8" \ 916 \ 555 \ 99 \ 99 ) задает список из пяти членов. Чтобы не вставлять разделителя строк можно для создания списков воспользоваться операцией LIST, которая создает список из упакованных в строки значений своих параметров, например, chequerboard=(LIST (LIST a1 a2 a3 a4 a5 a6 a7 a8) (LIST b1 b2 b3 b4 b5 b6 b7 b8) ... (LIST h1 h2 h3 h4 h5 h6 h7 h8)) создает в переменной chequerboard двумерный массив имен полей шахматной доски. Выражение (chequerboard 2 3) возвращает b3.Создание записей.Записи можно создавать как списки литералов, разделенных знаком новой строки, например: P=("ИМЯ=ИВАН" \ "ОТЧЕСТВО=ИВАНОВИЧ" \ "ФАМИЛИЯ=ИВАНОВ" ) но в этом случае нужно заботиться о правильном порядке ключей и отсутствии дублирования. Более удобна для создания записей операция REC параметры которой группируются парами где первый параметр пары означат ключ (имя) элемента, а второй - значение. REC n1 v1 n2 v2 n3 v3 .... Здесь за правильным порядком и отсутствием дублирования ключей в результирующей записи следит система. Например вышеприведенную запись можно создать с помощью операции REC: P=(REC "ФАМИЛИЯ" "ИВАНОВ" "ИМЯ" "ПЕТР" "ОТЧЕСТВО" "ИВАНОВИЧ" "ИМЯ" "ИВАН") произведет структуру: ИМЯ=ИВАН Элементы вычисляются последовательно и элемент "ИМЯ=ИВАН" заменит элемент "ИМЯ=ПЕТР". ПсевдопеременныеВсё множество локальных переменных может рассматриваться как одна псевдопеременная LOCALS, аналогично для глобальных переменных существует GLOBALS, а для параметров вызова страницы - псевдопеременная ENV (от ENVironment). обращения к псевдопеременным позволяют удалять переменные (присваивание пустой строки этого не делают) и работать с переменными с вычисляемыми именами. (LOCALS DEL=var /* удаляет переменную var */ ; LOCALS (varname) /* возвращает значение переменной, имя которой вычисляет выражение (varname) */ ) Рассмотренные псевдопеременные организованы как записи (ассоциативные массивы) Есть также псевдопеременные RESULT и ERROR организованные как списки (обычные массивы строк, тексты). Например, следующий оператор последовательно обрабатывает все строки (FOR (i=1;n=(RESULT "#")) (LE (i) (n)) (ADD i 1) (val=(RESULT (i); /* обрабатывается строка из RESULT */ ) ) Параметры запросаДля получения любого параметра из главного запроса внутри странички может быть использована операция ENV: (ENV имя-параметра ) На самом верхнем уровне т.е. из главного макроса параметры доступны просто по имени, как локальные переменные. Специальная операция (MACNAME) выдает имя главного макроса, из которого произведена данная страница. Объекты базы данныхИдентификация и строчное представление объектовЯзык Абрис Объектно-Ориентированный (ОО), но в отличие от других ОО-языков, где как правило существуют и активно используются объекты среды исполнения, Абрис работает с постоянными объектами базы данных. Для времени исполнения Абрис допускает только один текстово-строчный тип данных. Следовательно встает вопрос: каким образом объекты представляются в виде строк во время исполнения. Вообще говоря, объект может быть представлен или изображен в следующих текстовых (строчных) формах:
Однако, основным инструментом манипуляций с объектами являются первые две формы, т.е. либо пара имен имя-объекта:имякласса для именованных объектов - сущностей, либо уникальный числовой числовой идентификатор для любых объектов. Итак, однозначно объект определяется:
Идентификатор (ИД) объектаВ системе Абриаль все объекты имеют уникальные в БД числовые идентификаторы, иды, а все системные понятия, т.е. классы, отношения, аспекты, правила и т.д. представляются объектами дескрипторами. Поэтому манипуляции классами и аспектами и т.д. осуществляется через их иды. Следовательно, если функция должна возвращать объект, или должна иметь объект в качестве параметра, то на самом деле возвращается или передается не объект, а ид объекта в строчном виде. Если ид представлен пустой строкой или равен 0, это значит, что объект фактически не задан, или на выходе функции не возвращен (например - не найден). Однако, если объект на входе операции вообще не задан - вместо него, возможно, будет взят по умолчанию текущий объект, но если задан нулевой или пустой ид - умолчание не действует. Таким образом, отсутствие объекта на входе не всегда эквивалентно недействительному или пустому иду объекта. <#REFER M=Disp> -- здесь ссылка на метод Disp, примененный
к текущему объекту текущей БД<BR> Текущие БД, объект, аспектВ каждый момент обработки, в каждой точке исполнения макроса или функции, существует текущая БД и текущий объект, которые используются для тех примитивных операций и операторов, которым требуется объект, но он явно не указан. Текущий объект используется не только для примитивных операций но и при поиске реализаций запрограммированных методов. Аппарат вызова функцийФункции и макросыФункции и макросы могут быть определены в исходном тексте, а не только находятся на диске. Определение функций.Функции определяются операцией FUNC. одна операция FUNC может определить множество функций. <#FUNC Fname1=FunctionBody1 Fname2=FunctionBody2 ... > Например, определим функции максимума и минимума для чисел и для строк. <#FUNC Max=(GT (1) (2) (1) (2)) Min=(IF (GT (1) (2)) (2) (1)) MaxS=(AFT (1) (2) (1) (2)) MinS=(AFT (1) (2) (2) (1)) > Тогда (Max 20 100) вернет 100, а (MaxS 20 100) вернет 20. Параметры операции FUNC это именованные выражения в виде Имя=Выражение, где Имя задает имя определяемой функции, а Выражение - тело функции. В простейшем случае тело, как всякое выражение может быть литералом и это может иметь отнюдь не тривиальную семантику с учетом объектно-ориентированного подхода, как будет показано ниже. Определение макросовМакросы определяются оператором MACRO. Один оператор определяет ровно один макрос. <#MACRO ИмяМакроса> .....Здесь следует текст макроса..... ....... <#/> Обращения к методам, параметры методовПараметры в обращении к методам могут быть именованными, как атрибуты в HTML, или позиционными, как в классических языках программирования. При этом часть параметров может быть позиционными, обычно это первые по порядку параметры, а часть - именованными. Практически, именованные (или ключевые) параметры нужны для представления необязательных параметров и свойств функций и операций. За счет именованных параметров одна и та же реализация метода может обеспечить большое разнообразие поведения, а также - постепенное развитие причем, без необходимости полного знания программистом всех деталей обращения к функции, как это неизбежно для более традиционных позиционных параметров. Так например, в Си и Паскале, чтобы пользоваться функцией, необходимо изучить все её параметры и все варианты их задания. С другой стороны, в HTML почти все теги имеют большое количество параметров, которые чаще всего бывают не нужны, и пользователь HTML чаще всего даже не знает о их существовании, пока в них не возникает надобность. Абрис, позволяя использовать обе разновидности параметров, объединяет достоинства обоих подходов: гибкость HTML и лаконичность Си. Для обращения к позиционным параметрам внутри функции используется нотация - номер параметра в скобках, т.е. (1) для первого (2) для второго и т.д. В тексте макроса скобки должны быть соответственно макросные: <#1>, <#2> и т.д. К именованным (ключевым) параметрам внутри функции нужно обращаться как к локальным переменным по их имени в скобках. Фактически они и реализованы как локальные переменные, инициализируемые при входе в функцию. Для придания имен позиционным параметрам используется операция (PARAM name1 name2 ...) с позиционными параметрами задающими имена для соответствующих позиций. Для присваивания значений по умолчанию именованным параметрам используется операция (PARAM name1=val1 name2=val2 ...) с именованными параметрами, задающими значения для соответствующих имен. <#FUNC Function1=("Значение параметра №1=" (1) ", параметра №2=" (2) "!")) Function2=("Значение параметра Abc=" (Abc) ", параметра Cde=" (Cde) "!")) Function3=((PARAM first second) "Значение параметров: №1=" (first) ", №2=" (second) "!")) Function4=((PARAM x=111 y=222) "Значение параметров: x=" (x) ", y=" (y) "!")) > <# (Function1 qwerty asdfg) // возвращает:Значение параметра №1=qwerty, параметра №2=asdfg! (Function2 Abc=123 Cde=456) // возвращает:Значение параметра Abc=123, параметра Cde=456! (Function3 qwerty asdfg) // возвращает:Значение параметров: №1=qwerty, №2=asdfg! (Function4 x=123) // возвращает:Значение параметров: x=123, y=222! (Function4 y=789) // возвращает:Значение параметров: x=111, y=789! (Function4) // возвращает:Значение параметров: x=111, y=222! > Включения, примитив USEМножества определений функций и макросов, реализующие некоторую обработку, удобно соединять в пакеты и подсоединять к исполняемому макросу во время обработки. Однако эти определения действуют только на том же уровне вызовов функций, на котором они находятся и на более глубоких уровнях, но при выходе из функции, где сделаны определения они отменяются. Следовательно, подсоединить пакет простым вызовом функции не получается. Для того чтобы включить текст некоторого макроса из дисковой библиотеки на том же уровне вызовов функций существует операция включения (USE имя_библиотечного_макроса ) Библиотечный макрос находится также как и вызываемый по имени, но вставляется так, как будто его текст находился бы на месте операции USE. Следовательно, все его операции выполняются внутри текущего вызова функций в пределах одной области видимости. Объектно-ориентированный подход при поиске реализации методаАбрис - объектно-ориентированный язык. Это означает не только то, что здесь используются объекты, но в частности, то, что один и тот же метод может иметь разные реализующие его функции и макросы для разных объектов, или что более привычно, - для разных классов объектов. Это реализуется следующим образом. Допустим, вызывается метод Foo при текущем объекте с именем Nam из класса Cla. Причем, класс Cla происходит от классов Base1 и Base2 а класс Base1 - от класса Super. Тогда, вообще говоря, поиск реализации осуществляется в таком порядке:
Если найдена реализация метода, то она и выполняется, а метод больше не ищется. Т.е. специальная реализация метода для конкретного объекта загораживает более общую реализацию этого метода для класса, а реализация для класса загораживает самую общую (универсальную) реализацию метода. <#FUNC Speak="Silence..." Аnimal_Speak="I don't know how I must Speak" Dog_Speak=Hau_Hau Cat_Speak=Miaou Bird_Speak=Chirik Parrot_Speak=(OR(1) (Bird_Speak)) Cat_Barsik_Speak="Waooooo!" Dog_Mumu_Speak=Bulk > <# // function call // returns (comments) (Speak) // Silence... (ON (OBJ Murka Cat) (Speak)) // Miaou (as all Cats) (ON (OBJ Kuzia Cat) (Speak)) // Miaou (as all Cats) (ON (OBJ Barsik Cat) (Speak)) // Waooooo! (only Barsik can say) (ON (OBJ Popka Parrot) (Speak) ) // Chirik (as all birds, since no question) (ON (OBJ Popka Parrot) (Speak Please)) // Please (ON (OBJ Gena Croc) (Speak)) // I don't know how I must Speak (no special method for crocs) (ON (OBJ Sharik Dog) (Speak)) // Hau_Hau (as normal dog says) (ON (OBJ Mumu Dog) (Speak)) // Bulk (special sound) (ON (OBJ Volga River) (Speak))// Silence... (Volga is not an animal) > Порядок поиска реализации методаОбщий порядок поиска реализации имени foo для выражения (foo ....) или тега <#foo ...> Ищем foo ...
Далее уточняется, как производится поиск внутри перечисленных пунктов. Поиск в динамических определениях (в тексте программы).Используются определения функций и макросов (операторами MACRO и FUNC) выше текущей точки исполнения в текущей и потом - в вызывающих функциях, начиная от самой глубокой, до самого высшего уровня. На одном уровне самое последнее определение с искомым именем имеет силу. Поиск происходит по ОО-процедуре. Сначала реализации для данного объекта, затем для класса объекта, затем для всех старших классов по порядку (каждый из старших классов обрабатывается до конца, т.е. перебор типа "сначала вглубь", затем ищется универсальная реализация метода - для собственно имени метода. Для каждого очередного составного имени поиск производится до самого верху и потом только берется следующее имя. Таким образом, если Cla_Foo будет определена на самом верхнем вызове а Foo - в текущей функции, то будет использоваться реализация с именем Cla_Foo. Если не установлены текущая БД или текущий объект, ищется только само имя метода, без производных имен. Поиск макроса внутри текущей БД.Если не установлены текущая БД или текущий объект, данный вид поиска пропускается. Макросы в БД хранятся в виде объектов класса MACRO, которые имеют текстовый (строковый) атрибут "MACRO\MACRO", значением которого является тело макроса. Таким образом, множество объектов класса MACRO представляют собой библиотеку макросов. Поиск макросов в базе данных по ОО-процедуре будет реализован в полном объеме начиная с версии 2.1. Тогда имена, реализующие методы, будут искаться по той же схеме и в том же порядке, как и для динамических определений макросов и функций в тексте. Поиск реализаций методов в директориях.После неудачи поиска имени и его объектно-ориентированных производных в памяти и в БД - в последнюю очередь метод ищется на диске в нескольких специальных директориях: Допустим, вызывается метод Foo при текущем объекте с именем Nam из класса Cla. Причем, класс Cla происходит от классов Base1 и Base2 а класс Base1 - от класса Super. Порядок полного поиска имени name в директориях (где поочередно name=Cla_Nam_Foo, Cla_Foo, Base1_Foo, Super_Foo, Base2_Foo, Foo): Для каждого варианта name реализация ищется в следующих файлах. currpath\name.HTM currpath\name.TXT ? dbpath\dbname.TEM\name.HTM ? dbpath\dbname.TEM\name.TXT ? dbpath\name.HTM ? dbpath\name.TXT ? dbpath\TEM\dbname.TEM\name.HTM ? dbpath\TEM\dbname.TEM\name.TXT ? dbpath\TEM\name.HTM ? dbpath\TEM\name.TXT ? exepath\dbname.TEM\name.HTM ? exepath\dbname.TEM\name.TXT exepath\name.HTM exepath\name.TXT ? exepath\TEM\dbname.TEM\name.HTM ? exepath\TEM\dbname.TEM\name.TXT exepath\TEM\name.HTM exepath\TEM\name.TXT ? -- поиск только при наличии открытой (текущей) БД где
Глобальные командыСуществует ряд команд, которые вызываются как методы запроса, например так: <#REFER _BACK "Назад" > но не являются ни запрограммированными макросами ни примитивными операциями: эти команды касаются самого интерфейса пользователя и стоят, таким образом, особняком от других примитивов, обращения к которым могут вставляться внутрь генерируемой страницы. Например команду _BACK, приводящую к возврату броузера Абриаля на шаг назад нет смысла вставлять внутрь генерируемого текста. но эта команда может быть в запросе, так что пользователь может её вызвать нажав на определенную кнопку/ссылку на странице. Команды для текущей версии:
Команды, работающие с базой данных следует отличать от одноименных операций: команды не являются примитивами языка, и работают только в запросах, но не в генерируемом тексте. Но в запросах имена команд являются более приоритетными. Поэтому если в запросе встретится _OPEN будет исполняться команда, а не операция.
Операции с базами данныхСпособы обращения к объектам базы данныхСпособы работы с БД варьируются в трех измерениях, содержащих по два варианта каждое:
Все восемь сочетаний этих альтернатив теоретически могут работать, но на практике используются не все комбинации вариантов, а лишь некоторые:
Рассмотрим все эти случаи и варианты по отдельности. Просмотр и навигация по базе данныхДля просмотра базы данных используются следующие операции и операторы:
Изменения в базе данныхОперации, изменяющие базу данных могут вызваться двумя способами:
Например, внутри теста макроса может быть операция связывания двух объектов, задаваемых переменными, (father) (son) связью типа Parent: <#_LINK R="Parent" O1=(father) O2=(son)> Но такую же операцию как цельное действие можно инициировать ссылкой: <#REFER ACT=_LINK R="Parent" O1=(father) O2=(son) ("Make "(NAME(father)) " parent for " (NAME(son)) "!" ) > Ссылка в тексте странички будет выглядеть примерно так: Make Pavel parent for Nikolay! В качестве отдельного действия можно вызывать не все операции, а лишь те, имена которых начинаются с подчеркивания. Параметры этих операций вычисляются энергично, т.е. заранее, как делается и при вызове методов. Но все остальные операции вызывают параметры лениво, т.е. по мере надобности уже во время исполнения. Такие ленивые операции нельзя использовать в качестве действий в запросах, поскольку в момент их исполнения контекст вычисления параметров уже бывает утерян. Основные операции изменяющие базу данных
Обращение к базе данных через HTML-ссылкуСсылки в форме A-тега используются в тех случаях, когда задаваемая в запросе пользователя информация известна заранее, еще при генерации страницы. Ссылочные теги генерируются следующими примитивами: операциями REFER, ASP, оператором HREF. Собственно ссылка без тега генерируется: ROOTREF, URL, или _HREF; структуры, потенциально содержащие много ссылок выдают: ASPECT, OBJFORM. Обращение к базе данных через HTML-формуДанные в HTML-формах используются в тех случаях, когда в запросе пользователя должна быть информация не известная заранее, при генерации страницы. Она задается пользователем либо в виде текста либо выбором из альтернатив или пометкой признаков. Форма для пользователя генерируется в основном на низком уровне за счет HTML-средств, например так для связывания текущего объекта (OBJ) с отношением (relat) с представителем класса Person. Направление связи задается переменными (from) и (to). Если связь прямая, Relname(текущий-объект,выбираемый ), то from=O1 и to=O2 для обратного направления (Relname(выбираемый,текущий-объект ),) наоборот: from=O2 и to=O1. Данная форма для пользователя будет представлена примерно в таком виде: А в тексте макроса задается кодом:
Рассмотрим эту форму по порядку. В первом теге FORM записано HTML-действие (action) в виде макротега <#URL ACT=_LINK R=(relat) > генерирующего ссылку с запросом на действие, содержащее заранее известные параметры действия, т.е. имя действия ACT и имя отношения R. Остальные параметры запроса содержатся внутри формы, а именно: следующая строка содержит тег для скрытого поля <input type=hidden...>, имя которого (from) переменно, т.е равно либо O1 либо O2, а значение - ид текущего объекта. Далее следует сложный тег SELECT, создающий поле выбора значения для имени (to) равному O1 либо O2. Внутри тега выбора находятся несколько тегов опций выбора (OPTION), первая из которых - холостая опция "Выбрать здесь" - которой приписано нулевое (т.е. никакое) значение ида объекта. Остальные опции выбора генерируются оператором цикла, обходящим все представители класса Person, т.е. объекты соответствующие людям. В итоге поле выбора позволяет выбрать элемент связи O2 среди всех "людей" в базе данных. Следующий за тегом SELECT тег <input type=submit...> задает кнопку для запуска запроса. После выбора этой кнопки страница будет обновлена, но перед этим обновлением будет проделано действие Абриса, имя и параметры которого определяются из ссылки в заголовке формы, с добавлением так называемых POST-данных из элементов формы. POST-данные - это множество пар вида Имя=Значение (Name=Value), в которых именам полей формы сопоставляются значения, заданные пользователем в форме или приписанные им по умолчанию в видимых или скрытых полях формы. В данном примере POST-данные для имен O1 и O2 задают теги <input type=hidden...> и <SELECT...>. Они вносят в запрос элементы вида: ...O1=1234&O2=4567.... Полностью параметры запроса складываются из ссылки в заголовке формы и из POST-данных, что для данного примера эквивалентно примитивной операции: <#_LINK R=Parent O1=1234 O2=4567 D=data_base_file > Порядок объединения параметров из ссылки с POST-даными. Когда пользователь выбирает кнопку в форме, запрос образуется сначала из ссылки в заголовке формы, и затем в запрос вливаются POST-данные, это значит что если найдется одноименный параметр в ссылке и в POST-данных, значение последнего заменит значение параметра из ссылки. Навигация или действие?Признаком, отличающим запрос-действия от навигационного запроса является наличие параметра ACT с непустым значением, задающим примитивное действие или метод-действие. Если в запросе есть параметр ACT (неважно откуда - из ссылки или из POST-даных), то сначала выполняется действие и его результат помещается в переменную RESULT, а затем повторяется в точности тот же предыдущий навигационный запрос, что и привел к отображению странички, т.е. страничка для пользователя обновляется. При этом в отображении странички в любом месте может быть предусмотрено отображение содержимого RESULT. Его можно показывать всегда, т.к. при отсутствии действия переменная RESULT бывает пуста. Её содержимое действительно только на данном шаге, перед обработкой очередного запроса RESULT очищается. Операции со всей базой данныхГруппа операций с целой базой данных.
Комбинация CODE+FILESAVE/FILEAPPEND позволяет записывать в файл код базы данных частями. Строчные операцииСтроки в Абрисе - это единственно допустимый тип данных. Строкой мы называем либо простую строка, не содержащая внутри себя никаких невидимых символов кроме пробела, либо множество (последовательность) строк, называемое в данной инструкции текстом. Для обработки строк используются следующие операции
Операция APP стоит особняком, т.к. она работает не как функция, выдающая некое значение, а как процедура, производящая побочный эффект. А именно: она прицепляет к (локальной) переменной, имя которой задано первым аргументом - текст, заданный вторым аргументом. TEXT - это по сути самая главная и важная операция языка, поэтому если операция пропущена именно TEXT подразумевается по умолчанию, операция TEXT выдает объединенное значение сцепленное из своих аргументов. CAT - делает то же что текст, но все переводы строк внутри своего результата преобразует в пробелы, получая таким образом единую строчку, из возможно, нескольких. FIND, LEN, SUBSTR - достаточно типичные операции чтобы на них останавливаться. CONV - операция, проделывающая множество типов преобразования строк/текстов, причем тип преобразования задается именем параметра а исходный текст - значением этого параметра. Важно отметить, что если исходный текст состоит из нескольких строк, преобразование проделывается с каждой из составляющих строк по отдельности. Арифметические операцииАрифметические операции с числами производятся на их строчными представлениями. Если строка не содержит числа то её числовое значение воспринимается как ноль. Целые от дробных (вещественных) чисел отличаются только наличием точек, отделяющим дробную часть. При записи в виде литералов дробные числа лучше брать в кавычки, чтобы они не были спутаны с обращениями к параметрам. Основные арифметические операции:
Операция ADD стоит особняком, т.к. она работает не как функция, выдающая некое значение, а как процедура, производящая побочный эффект. А именно: она прибавляет к значению (локальной) переменной, имя которой задано первым аргументом - число, заданное вторым аргументом. Логические операцииЛогические значения представляются в виде строк следующим образом: пустая строка представляет FALSE (Ложь). Любая непустая строка представляет TRUE (ИСТИНА). Стандартное значение для TRUE - знак пробела. Это позволяет реализовать несколько обобщенное понимание логических операций в Абрисе. Операция OR (ИЛИ) выдает первое истинное, т.е. непустое значение среди всех своих аргументов, или пустоту (ЛОЖЬ) если все аргументы ложны (пусты). Операция AND (И) последовательно проверяет значение своих аргументов и если один из них окажется ложным (пустым) выдает пустоту (ложь). Если же все аргументы не пусты, AND выдает значение самого последнего. Операция NOT выдает пустое значение (ложь) если его аргумент непуст, и стандартную ИСТИНУ т.е. пробел, если аргумента нет или его значение пусто. Таким образом, логическими операциями AND и OR можно пользоваться вместо условных операторов. Операции с целыми файламиОперации с файлами позволяют читать и писать содержание текстовых файлов. Чтение осуществляется только целиком. Записывать данные в файл можно частями.
Операции с файлами (отдельными записями)Кроме операций с целыми файлами в языке предусмотрена операция FILE в разных вариантах позволяющая читать и писать файлы частично, по отдельными записям. Этот вариант доступа похож на аналогичные функции в традиционных языках тем, что сначала требуется открытие файла при котором определяется тип доступа, затем производятся операции чтения записи, и затем файл закрывается. Разновидности файловТип файла указывается в операции открытия именем первого ключевого парамтера:
Идентификатор файлаДля идентификации открытых файлов используются специальные глобально видимые имена, идентификаторы файлов. Идентификатор файла всегда указывается в первом по порядку параметре операции FILE. Т.к. параметр может при необходимости как литерал браться в кавычки, для идентификаторов позволено использовать больший набор символов, чем для переменных, идентификатор не должен включать символа "=" и начинаться или оканчиваться пробелом. Для входных и выходных последовательных файлов в качестве идентификатора может использоваться путь, но с условием, что при всех обращениях к одному файлу этот путь записывается одинаково, включая регистр букв. Входные файлыВходной файл открывается операцией:(FILE IN=fid FROM="filename.ext"). Если путь в FROM не указан, то в качестве имени файла берется его идентификатор fid. Записи входного файла (строки текста) читаются операцией (FILE GET=fid). Конец входного файла проверяется операцией:(FILE EOF=fid), возвращающей непусто, если файл прочитан или чтение невозможно по любой причине. Входные файлы целесообразно закрывать после прочтения операцией: (FILE CLOSE=fid) Выводные файлыВыводной файл открывается на запись операцией: (FILE OUT=fid TO="filename.ext") и на дописывание - операцией (FILE APP=fid TO="filename.ext"). Если путь в TO не указан, то в качестве имени файла берется его идентификатор fid. Очередная строка текста в выводной файла записывается операцией (FILE fid PUT=value). Выводные файлы необходимо закрывать после полного записывания операцией: (FILE CLOSE=fid). Списочные файлыСписочный (текстовый с произвольным доступом) файл открывается операцией: (FILE LIST=fid ...). Если файл нужно взять из уже существующего, то используется параметр открытия FROM=путь Если файл при закрытии необходимо автоматически сохранить, используется параметр открытия TO=путь Если входной и выходной файлы совпадают, вместо двух параметров можно использовать один: PATH=путь. Обращение к i-й строке списочного файла осуществляется операциями: (FILE fid NUM=(i)) для чтения и (FILE fid NUM=(i) PUT=(newvalue)) для записи. Вообще, для списочных файлов применимо обращение (FILE fid индексные-параметры)), где индексные-параметры те же, что используются при доступе к структурным значениям переменных. (см. раздел Индексные параметры). При закрытии файла операцией: (FILE CLOSE=fid) файл автоматически сохраняется, если для него при открытии был указан путь сохранения (параметром PATH или TO). Для сохранения без закрытия используется операция (FILE SAVE=fid) или (FILE fid SAVETO=путь), последнее для записи в файл с новым именем. Для закрытия файла без сохранения используется операция (FILE DEL=fid). Ключевые файлыСловарный (ключевой, состоящий из пар Ключ=Значение с уникальными ключами) файл открывается операцией: (FILE REC=fid ...). Если файл нужно прочесть из уже существующего, то используется параметр открытия FROM=путь. Если файл при закрытии необходимо автоматически сохранить, используется параметр открытия TO=путь Если исходный и результирующий файлы совпадают, вместо двух параметров можно использовать один: PATH=путь. Обращение к записи словарного файла с ключом в переменной key осуществляется операциями: (FILE fid KEY=(key)) для чтения и (FILE fid KEY=(key) PUT=(newvalue)) для записи. Вообще, для этих файлов применимо обращение (FILE fid индексные-параметры)), где индексные-параметры те же, что используются при доступе к структурным значениям переменных. (см. раздел Индексные параметры). При закрытии файла операцией: (FILE CLOSE=fid) файл автоматически сохраняется, если для него при открытии был указан путь сохранения (параметром PATH или TO). Для сохранения без закрытия используется операция (FILE SAVE=fid) или (FILE fid SAVETO=путь), последнее для записи в файл с новым именем. Для закрытия файла без сохранения используется операция (FILE DEL=fid). Индексные файлыИндексные файлы аналогичны описанным в предыдущем разделе ключевым файлам, с тем, однако, отличием, что в ключах допустимы все символы, включая равенство, и значениями могут быть только целые числа, в роли которых обычно выступают идентификаторы объектов базы данных. Эти файлы без значений (т.е. с нулевыми значениями) могут использоваться как множества неповторяющихся строк. В текущей реализации доступ к этим файлам (поиск ключа) работает быстрее, чем для ключевых файлов.
Операции сравнения
Операции сравнения делятся на числовые и строковые. Числовое сравнение "2" < "10" а строковое: "2" > "10". Числовое 100 = 00100 но как строки они различаются. Смысл операции значительно более общий чем для обычных операций сравнения в языках программирования. Семантика операций сравнения зависит от количества аргументов, и только при двух аргументах смысл тот же, что обычно:
Примеры: <# (IS (SUBSTR(X)1 1) Y) // возвращает пробел, если значение переменной Х начинается с Y (IS (opt) Y (func1) N (func2) y (func1) n (func2) "ДА" (func1) "HET" (func2) ) // вызвывет func1 при значениях Y,y,ДА, и func2 - при значениях N,n,НЕТ (LT (p) 0 Negative // разделяет диапазон изменения p на три части: менее 0, 1 Portion // от 0 до 1 Large ) // и больше или равно 1 > Условные операторыКроме операций сравнения, которые как видно выше, обобщены до условных операций, есть более традиционные условные операторы:
Операторы IF и IFNOT проверяют некоторое условие и выполняют (возвращая значение) свое тело и/или второй аргумент при выполнении для IF или невыполнении для IFNOT этого условия (Выполнением считается, когда возвращена Истина, т.е. непустое значение). Когда оператор IF (IFNOT) задается в макроформе, то тело определяется до закрывающего тега <#/>. Внутри тела в этом случае может присутствовать разделительный макротег <#ELSE> который ничего не возвращает, но после него записана альтернативная часть тела оператора, которая выполняется, если не выполняется основная часть тела - до <#ELSE>. <#IF (condition)> Операция COND, в отличие от IF это именно операция, а не оператор, проверяет множество условий задаваемых нечетными аргументами и при успехе одного из них возвращает значение следующего по порядку четного аргумента. В случае неуспеха всех условий может быть возвращено значение последнего нечетного (непарного) аргумента, если таковой имеется. (COND (IsANumber) (ShowNumber) (IsAString) (ShowStr) (IsARef) (REFER) (ErrorMsg)) Операторы циклаОператоры цикла делятся на две группы:
Все операторы цикла имеют внутри себя тело, которое определяется либо закрывающим тегом <#/>, либо является последним (безымянным!) аргументом оператора (заголовка). Порции внутри циклаЧасто возникает потребность расположить результаты, выдаваемые некоторым циклом, в виде таблицы (на языке HTML) или аналогичной регулярной структуры. В этих случаях поток текста, выводимый оператором цикла, делится на порции. Формально оператор порции PORTION вставляется внутрь тела оператора цикла: <#FOR...> заголовок порции <#PORTION размер >тело порции=шаг цикла<#/>завершение порции <#/> Каждая порция с точки зрения логики исполнения представляет собой некоторое фиксированное число шагов цикла, вывод которых имеет собственное общее обрамление, а практически - порция представляет собой чаще всего строку или столбец HTML-таблицы. Если количество шагов цикла не кратно размеру порции, то последняя порция оказывается неполной, но она всё равно исполняется полностью; это связано с тем, что условие выхода из цикла проверяется лишь после выхода из тела порции, избыточные шаги проходятся "вхолостую" и должны изобразить пустые клетки таблицы. Например, если мы имеем класс Месяцы состоящий из 12-ти объектов, то обойти этот класс и изобразить его в виде таблицы из трех столбцов по пять ячеек (мы намерено делаем форму некратной содержанию) можно следующим образом: <TABLE border=2 width="100%"> <#FORALLOBJ "NAME\ITEMS" N="Месяцы" C=CLASS> <TR> <#PORTION 3> <TD valign=top> <TABLE> <#PORTION 5> <TR><TD><#GT (OBJ) 0 (REFER) " "> <#/> </TABLE></TD> <#/> </TR> <#/> </TABLE> В результате должна получиться примерно такая таблица (вместо ссылок - простые имена объектов):
Разбиение длинных цикловСписки объектов или связей сканируемые операторами циклов могут получаться слишком длинными т.е. формирующими слишком большие страницы, что не удобно, т.к. на формирование больших страниц тратится заметное время, и просматривать большие страницы неудобно. Поэтому имеет смысл делить большие страницы на части соответствующие коротким сегментам больших списков и снабжать такие странички средствами листания сегментов вперед и назад. Для поддержки механизма листания в операторы цикла (в версии 2.01 только в FORALLOBJ и FORASP, но в следующих версиях будут во все операторы цикла ) введены параметры POS=позиция и NUM=размер, задающие позицию начала окна просмотра в списке и размер этого окна. Кроме того, имеется операция ROOTREF, выдающая ссылку на текущую страницу с возможным добавлением или заменой этих же параметров (POS=позиция и NUM=размер ). Если первый аргумент ROOTREF указан с именем <#ROOTREF POS= ...>, то позиция в списке абсолютная, т.е. это просто номер первого отображаемого элемента, но если первый аргумент без имени <#ROOTREF nnn ...> , то он указывает положительное или отрицательное приращение позиции по отношению к текущей. Например: 15 означает добавление к позиции числа 15. Таким образом можно сделать такой стандартный элемент - макрос с именем _pagebar для листания страниц. <!-- Листание страницы p=<#p> n=<#n> a=<#a> AspSize=<#(SET asz=(OR (AspSize A=(a)) 0) // переименование функции считающей число связей у аспекта объекта pre=(GT (p) 1) nex=(LE (SUM (p) (n)) (asz) ) ) (asz)> --> <#IF (NEMPTY (a))> <#LT (p) 1 (SET p=1)> <TABLE width="100%"><TR> <TH width="25%"> 1<#IF (pre)><--<#p> <A HREF="<#ROOTREF (NEG (SUB (p) 1) (n))>"> 1-я стр.</A><#/> </TH> <TH width="25%"> <#IF (pre)><A HREF="<#ROOTREF (NEG (n))>">Пред.стр.</A><#/> </TH> <TH width="25%"><#IF (nex)><A HREF="<#ROOTREF (n) (n)>">След.стр.</A><#/> </TH> <TH width="25%"><#IF (nex)><A HREF="<#ROOTREF (SUM (asz) (NEG (p)) (NEG (n)) 1 ) (n)>">Посл.стр.</A> <#SUM (p) (n) "-1">--><#/> <#asz></TH> </TR></TABLE> <#/> Вставка этого элемента в виде макроса с именем _pagebar перед таблицей таким образом: <#SET pos=(OR (POS) 1) seg=48> <HR> <h3>Префиксы для буквы (<#NAME>)</h3> <#_pagebar p=(pos) a="a\a1" n=(seg)> <TABLE border=1 width="100%"> <#FORALLOBJ "a\a1" POS=(pos) NUM=(seg)> <TR> <#PORTION 6> <TD width="16%"><TABLE> <#PORTION 8> <TR><TD><#REFER></TD></TR> <#/> </TABLE></TD> <#/> </TR> <#/> </TABLE> <HR> приведет примерно к такому изображению таблицы (из примера таблица префиксов русского языка на П) Префиксы для буквы (П)
ПриложенияАбриаль в 10 тезисах
Словарик
|
|