Перейти к содержанию

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!

C:\>_


3. Теперь можем запустить полученную программу:

C:\>Hello.exe
Hello World!

C:\>_


При компиляции файла 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

Ключевые слова

[править]


Cobra Ключевые слова
abstract adds all and any
as assert base be body
bool branch break callable catch
char class const continue cue
decimal def do dynamic each
else end ensure enum
event every except expect extend
extern fake false finally float
for from get has if
ignore implements implies import in
inherits inlined inout int interface
internal invariant is listen
lock mixin must namespace new
nil nonvirtual not number objc
of off old on or
out override par partial pass
passthrough post print private pro
protected public raise ref require
return same set shared sig
stop struct success test this
throw to to? trace true
try uint use using var
vari virtual where while yield