Cobra
С чего начать
правитьДля Cobra потребуется установить Microsoft .NET 2.0+ для Windows или Novell Mono 2.6+ для любой другой платформы (Mac OS X, Linux, BSD, Solaris и т.к.) Далее нужно скачать исходный код языка на сайте http://cobra-language.com/downloads/ и собрать для соответствующей платформы следуя инструкции в ReadMe
Условные обозначения
правитьПример текста программы обозначается следующим образом:
"""
This is the infamous "Hello, world." example.
And this text you are reading right now is the "doc string" for the whole
program. You can also put doc strings underneath classes, class variables,
methods and properties.
"""
class Hello
def main
print 'Hello, world.'
1. Создаем файл Hello.cobra в любом текстовом редакторе, пишем:
class Hello
def main
print 'Hello, world!'
2. Скомпилируем программу и получим:
C:\>cobra Hello.cobra
Hello, World!
3. Теперь можем запустить полученную программу:
C:\>Hello.exe
Hello World!
CIL
правитьПри компиляции файла Hello.cobra создается двоичный объект называемый сборкой(assembly), в которой содержит CIL-инструкции, метаданные и манифест описывающие подведение класса Hello.
Открыв полученную сборку в ildasm.exe, можно посмотреть что метод main был преобразован в следующие инструкции:
.method public hidebysig newslot virtual instance void Main() cil managed
{
// Размер кода: 36 (0x24)
.maxstack 2
.language '3F5162F8-07C6-11D3-9053-00C04FA302A1', '994B45C4-E6E9-11D2-903F-00C04FA302A1', '5A869D0B-6611-11D3-BD2A-0000F80849BD'
// Source File 'c:_Cobra.cobra'
//000002: def main
.try
{
IL_0000: call void [Cobra.Core]Cobra.Core.CobraCore::RunAllTests()
//000003: print 'Hello, World!'
IL_0005: ldsfld class [Cobra.Core]Cobra.Core.StringMaker [Cobra.Core]Cobra.Core.CobraImp::_printStringMaker
IL_000a: ldstr "Hello, World!"
IL_000f: callvirt instance string [Cobra.Core]Cobra.Core.StringMaker::MakeString(object)
IL_0014: call void [Cobra.Core]Cobra.Core.CobraImp::PrintLine(string)
// Source File 'c:_Cobra.cobra.cs' not found
IL_0019: leave.s IL_0023
// Source File 'c:_Cobra.cobra'
//000003: print 'Hello, World!'
} // end .try
catch [mscorlib]System.Object
{
IL_001b: pop
IL_001c: call void [Cobra.Core]Cobra.Core.CobraCore::PrintDebuggingTips()
IL_0021: rethrow
} // end handler
IL_0023: ret
} // end of method HelloWorld::Main
CIL-инструкции перед исполнением компилируются на лету с оптимизацией для конкретной платформы. За компиляцию CIL-инструкций отвечает JIT(just-in-time)-компилятор.
Рассмотрим метаданные, которые были сгенерированы для метода main:
Method #1 (06000001)
-------------------------------------------------------
MethodName: Main (06000001)
Flags : [Public] [Virtual] [HideBySig] [NewSlot] (000001c6)
RVA : 0x00002050
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: Void
No arguments.
Метаданные описывают тип(например, класс) и всех его членов(например, методов). Заметим, что метод main не имеет аргументов.
Также немаловажным является наличие в сборке манифеста, в которой указаны все внешние сборки требуемые текущей сборке, их версии и т.д. Ниже приведен пример наиболее существенной части манифеста:
.assembly extern /*23000001*/ mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 4:0:0:0
}
.assembly extern /*23000002*/ Cobra.Core
{
.publickeytoken = (0A 47 83 A5 C7 C9 61 6E )
.ver 0:0:2874:1
}
.module HelloWorld.exe
// MVID: 0A9F07C8-CD8B-4238-B42A-850763234F6C
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
Типы данных
правитьПримитивные типы
правитьБазовые:
- bool
- char (одиночные кавычки с предшествующим 'c', например с'A')
- int (= int32)
- uint (= uint32)
- float (= float64)
- decimal
- number
- dynamic
Типы явного размера:
- int8, int16, int32, int64
- uint8, uint16, uint32, uint64
- float32, float64
Примитивных переменных членов:
- PrimitiveTypeMembers
Вариант обозначения в Cobra | Отвечает ли требованиям CLS | Системный тип | Диапазон значений | Описание |
---|---|---|---|---|
bool | Да | System.Boolean | false или true | Представляет признак истинности или ложности |
char | Да | System.Char | от U+0000 до U+ffff | Одиночный 16-битный символ Unicode |
int | Да | System.Int32 | от -2147483648 до 2147483647 | 32-битное число со знаком |
uint | Нет | System.Uint32 | от 0 до 4294967295 | 32-битное число без знаком |
float | Да | System.Double | от -1,79769313486232E+308 до +1,79769313486232E+308 | 64-битное число с плавающей точкой |
decimal | Да | System.Decimal | от -79228162514264337593543950335 до 79228162514264337593543950335 | 96-битное число со знаком |
number | Да | System.Decimal | от -79228162514264337593543950335 до 79228162514264337593543950335 | 96-битное число со знаком |
int8 | Нет | System.SByte | от -128 до 127 | 8-битное число со знаком |
int16 | Да | System.Int16 | от -32768 до 32767 | 16-битное число со знаком |
int32 | Да | System.Int32 | от -2147483648 до 2147483647 | 32-битное число со знаком |
int64 | Да | System.Int64 | от -9223372036854775808 до 9223372036854775807 | 64-битное число со знаком |
uint8 | Да | System.Byte | от 0 до 255 | 8-битное число без знаком |
uint16 | Нет | System.UInt16 | от 0 до 65535 | 16-битное число без знаком |
uint32 | Нет | System.UInt32 | от 0 до 4294967295 | 32-битное число без знаком |
uint64 | Нет | System.UInt64 | от 0 до 18446744073709551615 | 64-битное число без знаком |
float32 | Да | System.Single | от -3,402823E+38 до 3,402823E+38 | 32-битное число с плавающей точкой |
float64 | Да | System.Double | от -1,79769313486232E+308 до +1,79769313486232E+308 | 64-битное число с плавающей точкой |
Абстрактные типы данных
править- Класс
- Структура
- Интерфейс
Nilable тип
правитьПотоки
правитьРабота с типами во время выполнения
правитьМожно узнать тип "х" используя вызов "x.getType" или "x.typeOf". Так же вы можете создавать экземпляры типов во время выполнения
- T = x.typeOf
- obj1 = T ()
- obj2 = T (0, 0)
Общие типы
правитьКлассы, интерфейсы и структуры могут быть обобщенными, аналогично C# и VB.
Например: List<of int>, List<of String>, Dictionary<of String, int>
В общем виде записывается: Name<of T, U...>, где Т обобщенный тип.
Например: class ATag<of T>
Экземпляр встроенного обобщенного типа, используя то же имя с конкретным типом, например, ATag<of String>
Вы можете объявить свой собственный или экземпляр встроенного обобщенного типа.
Возможно перегружать по количеству аргументов: Foo<of T> и Foo<of T, U> два различных типа.
Методы могут быть обобщенными: def foo<of T>(a as T, b as T)
Структура программы
правитьМодуль
правитьМодуль представляет собой последовательность из выражений или директив, заключенных в пространства имен.
Модуль может начать с DocString и/или блока комментариев.
Комментарии как и пробелы — могут быть размещены в любом месте модуля. В отличии от комментариев, DocString может располагаться только в определенных позициях (начало файла, первые строки class/struct/interface/enum, после method/var, ...)
Отдельное выражение выделяется отступами.
К выражениям относятся:
- use — указатель пространства имен, содержимое которого будет использоваться текущим модулем.
- namespace — пространство имен.
- class — пользовательский(ссылка) тип объединяющий переменные других типов, методов и событий.
- struct — пользовательский типа данных, во многом схож с классом.
- interface — обеспечивает определение интерфейса.
- mixin — реализующий какое-либо чётко выделенное поведение, который может быть введен на классы по любой иерархии классов.
- enum — используется для объявления перечисления, на которые могут ссылаться другие элементы.
- extend — расширение существующего типа.
- sig (signature) — описание сигнатуры метода (аналогично делегатам в C#).
Пространство имен может содержать любой из вышеперечисленных пунктов (за исключением namespace). Если пространство имен не указан, код модуля построен как если бы оно было указан в глобальном пространстве имен.
Кроме того, есть два ключа:
- assembly — указывает атрибуты для этой сборки
- '%%' (deprecated) или «@» — директивы компилятора Cobra.
Синтаксис
править
use NAMESPACE_NAME
namespace NAMESPACE_NAME
NAMESPACE_BLOCK
class CLASS_NAME
[inherits CLASS_NAME]
[implements INTERFACE_NAME]
[adds MIXIN_NAME]
[is ISNAMES_LIST]
CLASS_BLOCK
struct STRUCT_NAME
[inherits CLASS_NAME]
[implements INTERFACE_NAME]
[adds MIXIN_NAME]
[is ISNAMES_LIST]
CLASS_BLOCK
interface INTERFACE_NAME
CLASS_BLOCK
mixin MIXIN_NAME
CLASS_BLOCK
enum ENUM_NAME [of TYPE]
ENUM_VALUE [ = IntValue] [, ENUM_VALUE [= IntValue]... ]
extend CLASS_NAME
[ is ISNAMES_LIST]
[ has ATTRIBUTESLIST]
[ where GENERICCONSTRAINTS]
[ inherits CLASS_NAME]
[ implements INTERFACE_NAME]
CLASS_EXTENSION_BLOCK
event NAME as TYPE
[ is ISNAMES_LIST]
[ has ATTRIBUTES]
sig TYPENAME(ARGS)
sig TYPENAME as RETURNTYPE
sig TYPENAME(ARGS) as RETURNTYPE
assembly has ATTRIBUTE_NAME {has ATTRIBUTE_NAME}...
@COMPILER_DIRECTIVE_ID {DIRECTIVE_ARGS}
%%COMPILER_DIRECTIVE_ID {DIRECTIVE_ARGS}
Платформа
правитьНа текущий момент поддерживается трансляция на C#. Эта функция доступна для платформ Windows, с использованием Microsoft CSharp компилятора C# и на других платформах, поддерживаемых Mono и компилятор mono.
Пример
правитьПример программы Hops.cobra показывает применение некоторых языковых конструкций.
#Assembly attributes
assembly has SharedAttribute
use System.Text.RegularExpressions
%%number decimal
namespace Hops
class Example
var counter = 0
def incCount(i as int)
.counter += i
def main is shared
e = Example()
e.incCount(10)
assert e.counter == 10
class AnotherExample
pass
struct Point
var x = 0
var y = 0
enum ColorPart
"""What is the color of magic"""
Red
Green
Blue
Octarine
sig VoidDelegate # method taking no args and having no return type
sig NullStringDelegate(s as String) as String? # method taking String and returning String or null
extend String
def fmt(args as vari Object) as String
"""
Returns the string with any given args applied to it via String.Format
"""
test
s = '{0}is{1}'
assert s.fmt('0', '1') =='0is1'
assert s.fmt(2, 1) == '2is1'
assert s.fmt('One', 'NotTwo') == 'OneisNotTwo'
assert s.fmt(nil, nil) == 'is'
body
return String.format(this, args) to !
Класса простого HTTP-сервера
правитьПример класса HTTP-сервера MyHttpServer.cobra реализующего обработку самых основных возможностей протокола HTTP/1.
Объявления членов
правитьЧлены элементов или выражений в пределах одного типа похожи на объявления (классов, структур, интерфейсов, примеси, тип расширения...).
Они определяют внутреннее состояние, реализацию, внешний вид, содержиание поведение, действия и ответы объявления каждого из вышеперечисленных выражений.
В настоящее время к ним относятся
- инициализаторы — определяют начальное состояние/содержание
- методы — определяют действия
- свойства — предоставляют(опосредованно) доступ к внутреннему состоянию объекта
- индексаторы — включают объекты, которые будут индексироваться аналогично массивам
- события — обеспечить уведомление объектов
- контракты — определяет формальные, точные и верифицируемые спецификации интерфейсов, которые являются частью общего интерфейса из перечисленного
Комментарии
правитьКомментарии в Cobra могут обозначаться предваряющим их символом # и продолжаются до конца строки:
# ANY COMMENT TEXT
code... # TRAILING COMMENT TEXT
Можно использовать тройные кавычки как в Python
"""This is a single line docstring."""
"""
This is a multiline Docstring.
Leading summary line, blank line and descriptive text
Leading and trailing triple-" delimiter each on its own line.
"""
Для многострочных комментариев так же существует конструкция /#... #/:
/#
print '**********************************************'
print source
print '**********************************************'
#/
В документации, указано о возможности использовать данный комментарий внутри выражений. Однако в версии 9.3 это не выполнялось. Конец комментария в соответствии с регулярным выражением COMMENT_BLOCK_STOP класса CobraTokenizer соответствует [^#]*\#\/.*$. Пример взятый из документации не будет работать:
x = /# -1 * #/ z * y
# same as x = z * y
params = .paramDecls(/#skipParen=#/true)
Создание классов
правитьПрограмма, написанная с использованием объектно-ориентированной парадигмы, должна состоять из:
- классов
- объектов
Объект это сущность в адресном пространстве ЭВМ, появляющаяся при создании экземпляра класса. Поэтому, начнем с проектирования и создания классов. Класс — это пользовательский тип. Для создания классов предусмотрена инструкция class.
class ИмяКласса
Создание методов
правитьМетоды создаются как и обычные функции. Методы начинаются со служебного слова def.
def main
Операции
правитьВсе операции в алфавитном порядке
- assert — утверждает условие.
- branch — ветви.
- break — прервать цикл.
- continue — продолжать цикл.
- except — получение исключения.
- lock — блокировка и выполнить код в критической секции.
- for — числовое.
- for — перечисление.
- if-then-else — условное выполнение.
- ignore — удалить обработчики событий.
- listen — указать обработчик события.
- pass — указать пустую операцию.
- post (while) — цикл, пока условие истинно. Условие в конце блока. Аналогично do-while.
- print — вывод.
- raise — вызвать событие.
- return — возвращения из метода.
- throw — генерирует исключение.
- trace — отладочная информация.
- try-catch — блок обработки исключений.
- using — блок с инициализацией и автоматической очистки IDisposable объектов. Построим для поддержки RAII в IDisposables.
- use — указать пространство имен и содержимое, которые будут использоваться в этом модуле.
- while — цикл, пока условие истинно.
- yield — результат от генератора.
- ct_trace
Выражения
править- Coalesce
- For
- If
Литералы
правитьCobra обеспечивает удобный способ представления литералов, инициализации стандартных коллекций и явным указанием типа (размер и знак) для числовых литералов.
Список
правитьГетерогенные структуры данных динамическое размера.
Значения разделяется запятыми и заключаются в квадратные скобки [].
Пример пустого списка: []
names = [ 'mike', 'gary', 'pat', 'bruce', 'paul'] # List<of String>
heads = [3,1,1,1,1] # List<of int>
if name in [ 'fred', 'george', 'bill' ]
myList=[]
myList.add('1th')
Словарь
правитьАссоциативный массив или словарь.
Начинается с открывающей фигурной скобки { и заканчивается закрывающей фигурной скобкой }. Ключ и значение разделяется двоеточием, пары ключ/значение разделяются запятой.
Пример пустого словаря {:}.
nameId = { 'mike':10110, 'gary':21003, 'paul':32289 } # Dictionary<of String, int>
assert nameId['mike'] == 10110
order = { 0:'mike', 1:'bruce', 2:'gary', 3:'pat' } # Dictionary<of int, String>
mmap = {:}
mmap['top'] = 99
Набор
правитьНеупорядоченная коллекция уникальных элементов на основе алгоритма хеширования, оптимизирована для тестирования членов и набора операций.
Значения разделяется запятыми и заключаются в фигурные скобки {}.
Пустое набор {}.
names= {'gary', 'mike', 'bruce', 'paul'}
assert names.intersection({'gary', 'paul'} == {'gary', 'paul'}
assert not names.isSuperSetOf({'paula'})
collisions={}
collisions.add(toyota)
Массив
правитьСтруктуры данных однородного содержания имеющей статический размер.
Значения разделяется запятыми и заключаются в квадратные скобки [] с префиксом '@'.
Пустой массив @[]
names = @[ 'mike', 'gary', 'pat', 'bruce', 'paul'] # String[] or Array<of String>
heads = @[3,1,1,1,1] # int[] or Array <of int>
heads[4] = 3
Списки, проще в использовании и более гибки, но для некоторых целей массивы имеют более высокую производительность.
Число
правитьЧисло с плавающей точкой приводятся к типу Decimal по умолчанию.
Такое поведение может быть переопределено опцией -number компилятора в командной строке или командной строки или директивой @number компилятора.
Явно тип числовых литералов может быть указан путем добавления суффикса с типом и размером (с опционально предшествующим символом '_').
Типы
- u — unsigned int
- i — signed int
- d — decimal
- f — float
Размер
- для int 8, 16, 32, 64
- для float 32, 64
d = 123 # default (Decimal)
d = 123.4d
ii = 123i # integer (default size) 32 bits
# same as
ii = 123 to int
j = 123_i16 # signed 16 bit
k = 32u8 # unsigned 8 bit == Byte
l = 879289992978_i64 # signed 64 bit
f = 1327.3_f # float (default size 64)
f1 = 97.3f32 # or
f1 = 97.3_f32
Ключевые слова
править