Syntaxe nového jazyka pro systém KRKAL

  • U deklarace presunot [] pro pole za typ (c# styl). [] s atributy presunout za jmeno. int[] a [Editable, Copy] = {1,2,3}, b = {4,5,6}; OK
  • Neciste operace v jazyku nebudou KrkalC/NecisteOperace. OK
  • Precijenom podporovat operatory , a ?:. Snad to nebude tolik prace a hodi se to. OK, pokud zbude cas
  • moznost deklarovat promennou v prikazech for a foreach (foreach(int i in pole) { }). Otazka k foreach: Bude se dat do pole pres iteracni promennou i zapisovat? Pokud to nebude bitkarina, tak OK
  • u methodname nepsat typ mezi atributy ale psat ho pred jmeno a at je povinny. methodname retadd int m1 [UserName="dd"], void m2, CMyClass[] m3;. OK (Jen asi kvuli sjednoceni stylu nepovolit menit navratovy typ u kazde, carkou oddelene, polozky. Mozna nepouzivat ani klicove slovo methodname, jen povinny typ.)
  • Podporovat nebo nepodporovat public: private: ?? Mozna v pristi verzi
  • Konstanty v teto verzi podporovany nebudou. mozna v budoucnu. NE
  • K polim se hodi pridavat dalsi uzitecne metody: Insert, InsertArray, Delete, Sort, ... OK
  • I direct metody by mohly byt defaultni parametry, ktere by nebylo nutno zadavat. Fungovalo by to stejne jako v C. Kdyz je u volani nezadas, doplni parametry automaticky kompilator podle hlaviocky metody. OK, pokud zbude cas
  • Zamyslet se nad moznosti mit lokalni ret promenne = reference. Kdyz muzou byt ret parametry, proc ne i lokalni prom? (nic jineho uz ale nebude moci byt ret!) Hodily by treba pro foeach cykly. Hned v deklaraci je musim nainicializovat nejakou lvalue. Pokus se tato promenna odkazuje na polozku v poli, musi byt toto pole po dobu existence reference zamceno. Je tohle pouzitelne? Pravdepodobne jsou uzitecne jen pro foreach cykly (promenna musi byt ve foreach deklarovana)
  • Budu potrobovat prisne rozlisit sataticke a nestaticke safe volani. Jak to udelat? Vynutit povinne this-> a static->? OK, jen syntaxe muze byt jina. Metody stejneho KSID jmena se musi shodovat v navratovem typu a v modifikatorech - vcetne static. Pri volani pres promennou typu name se bude rozlisovat podle pritomnosti/nepritomnosti specifikace objektu (this->(m)(), o->(m)() nebo o1->(o2->m)() znamenaji objektove volani. m() ale i o2->m() jsou staticke volani). OK
  • foreach by mohl umet prochazet i pres vice dimenzi. OK, pokud zbude cas.
  • At pole umoznuji rychle pridavani/ubirani jak na konec tak na zacatek (podobne jako deque). Pole je reseno cyklicky, nulty prvek se muze posouvat. Pr. pole ma vyhrazenou velikost max, zacatak je na 0-te pozici. Pokud chci pridat hodnotu pred zacatkem, pridam ji na pozici max-1 a zacatek pole zmenim take na max-1. Buffer pro pole se zvetsuje (a zmensuje???) podle poteby. OK
  • Zrusit atribut noinherit a zavest modifikator override OK
    • V atributech nesmi byt nic, co by ovlivnovalo kompilaci
    • override zavadi do Krkala (temer) klasicke virtualni metody. Pouzitelne jen pro safe. Pokud je metoda override, kazda trida ma maximalne jednu jeji instanci (telo), instance se dedi, potomci mohou zadefinovat nove telo a tim se predchozi telo stava nepristupne (Krkal C nebude obsahovat zadne prostredky jak puvodni telo vyvolat (technicke duvody)). Kompilator vyvola error, pokud diky vicenasobne dedicnosti dojde ke konfliktu.
  • Inmutable (ReadOnly) pole. Zprehledni to praci se stringy. Asi budu potrebovat specialni typ. Budu mit tedy dva druhy poli (stringu) mutovatelny a nemutovatelny -> Do dalsi verze
  • Moznost predavat konstruktoru parametry. Vse funguje jako u bezne safe metody. Nemam zatim zadny mechanizmus jak zabranit konstruovani objektu, kdyz nezadam vsechny potrebne parametry. OK pokud zbude cas.

"Preprocessing"

(pravděpodobně nepůjde o samostatný průchod, ale sloučí se s lexikální analýzou)

  • komentáře – vše za // až do konce řádku bude ignorováno
  • /* … */ - bude nahrazeno white space znakem. Krkal podporuje vnořování těchto komentářů. Pozor: Komentáře neplatí uprostřed stringů "...//..."
  • Původní jazyk podporoval #define, #ifdef, … - tyto věci už ale podporovány nebudou.

Dokument

Každý zdrojový soubor je rozdělen na dvě části. Na začátku je povinná hlavička, která má specifickou syntaxi (pro tento text nezajímavou, může dojít ke změnám). Za hlavičkou následuje program.

Příklad hlavičky:

#head {
    version A1CF_6963_8DA6_D822;
    component;
    include "MenicSvetla_3436_6AFC_3322_FB73.kc" 3436_6AFC_3322_FB73;
    include "SkakavaStena_E3CB_FBA9_E57B_1ECD.kc" F685_E5BE_1BD3_AA2F;
}
#attributes [
    Author = "M.D.",
    Game = "Krkal",
]
#names {
    $Beruska$A1CF_6963_8DA6_D822;
    $SkakavaStena$F685_E5BE_1BD3_AA2F;
    $SkakavaStena$F685_E5BE_1BD3_AA2F.Interval$F685_E5BE_1BD3_AA2F old;
    $SkakavaStena$F685_E5BE_1BD3_AA2F.OtevriSe$E3CB_FBA9_E57B_1ECD;
    $SkakavaStena$F685_E5BE_1BD3_AA2F.Skakej$F685_E5BE_1BD3_AA2F;
    $SkakavaStena$F685_E5BE_1BD3_AA2F.ZavriSe$E3CB_FBA9_E57B_1ECD;
    $Svetlo$3436_6AFC_3322_FB73;
    $Svetlo$3436_6AFC_3322_FB73.ZmenBarvu$3436_6AFC_3322_FB73;
}

Poznámka: viz KrkalC/NecisteOperace

Program

Kompilace bude dvouprůchodová. V prvním kroku se zkompiluje vše až na těla metod, atributy, inicializaci polozek a parametru. V prvnim kroku to bude tedy deklarace KSID jmen a jejich závislostí, struktura objektů, proměnné, hlavičky metod. Takto posbírané sémantické informace jsou potřeba pro druhý průchod, kdy se budou překládat těla metod.
(starý kompilátor se snažil být jednoprůchodový, což vedlo ke zbytečným komplikacím, omezením, no a občas to taky nevyšlo :-))

Na top-level úrovní se může nacházet:

  • deklarace KSID jména
  • definice závislostí mezi jmény
  • popis objektů

Deklarace KSID jmen

Téměř každá identita v krkalovi má své KSID jméno. Existují jména pro objekty, pro metody, pro proměnné, pro zvuky, klávesy, grafiku, … V závislosti na typu jména jsou se jménem spojeny další informace. Například k objektovému jménu je přiřazen popis struktury objektu. Jména typu void jsou zcela obecná a nemají žádný další význam.

Lokalizace her v Krkalovi do různých jazyků je z 90% založena právě na KSID jménech. Každé jméno má dva textové atributy, které je možné překládat: UserName a Comment.

<typ jmena> <deklarace>[,<deklarace>[,…]];
<deklarace> : <novy identifikator> [<atributy>]

Příklad:

classname Bomba [InMap], Mina [InMap], Spojak;
classname Chocolate [InMap, UserName = “Cokolada”, Comment = “sbirej cokoladu, dostanes hodne bodu!”];
paramname timer, X, Y;
voidname jih, vychod, sever, zapad;
void vybouchni; // methodname
retadd int zjistiPocet;

Jména objektů a top-level jména je povinné deklarovat. (Zrušeno klíčové slovo decl ze starého jazyka.)

Definice závislostí mezi jmény

Nad jmény lze tvořit orientovaný, acyklický, obecně nespojitý graf. Definujeme tak množiny jmen, či závislosti. Můžeme říkat, že jméno A obsahuje jména X,Y,Z. Navíc existují speciální konstanty: everything (množina všeho) nothing (prázdná množina) a object (množina všech objektů a také jejich společný předek). Pomocí závislostí se definuje i objektová dědičnost.

Depend <jmena> <smer> <jmena> [<smer> <jmena>[…]];
<smer> : <<
<smer> : >>
<jmena> : <ksid konstanta>
<jmena> : {<ksid konstanta> [,<ksid konstanta>[,…]]}

Příklad:

depend  smer << {jih, sever, vychod, zapad};
depend  {smer, strana} << {jih, sever, vychod, zapad};
depend  pojem << {smer, strana} << {vychod, zapad};

Popis objektu

V Krkalovi objektová závorka class a {} neznamená deklaraci objektu, objekt vzniká už deklarací jeho KSID jména (classname a;). Jeden objekt může mít více objektových závorek i v různých souborech. Závorka vlastně jen přepíná kontext, je to určitý druh namespacu. Toto opatření je v krkalovi kvůli podpoře rozšiřitelnosti a nezávislého vývoje.

class <KSID konstanta typu objectname> [<atributy>] {
  // nasledujici prvky jsou volitelne, poradi muze byt libovolne
  <deklarace promenne>
  <deklarace safe metody>
  <deklarace direct metody>
  <skupina promennych>
  <ovladaci prvek pro editaci>
}

Příklad:

class MyClass {
  static MyClass MyClass = new MyClass;
  int[][] array [Editable] = {{2,3,4}, null, {1,5}};
  char[] text [Editable, Copy] = “ahoj”;
  separator sep1; // ovladaci prvek
  name direction [Editable, Auto, Is < smery] = sever;
  button tlacitko(ObsluhaTlacitka,5); // ovladaci prvek
  cell3D souradniceObjektu [Editable] { // skupina
    int x, y, z; // souradnice
  }
  int a=0;
  void ObsluhaTlacitka(int @param) {
    if (param == 5) a++;
  }
}

Deklarace proměnné

[static] <typ>[<specifikace poctu dimenzi pole>] <deklarace>[,…];
<deklarace> : <pojmenovani> [<atributy>] [= <konstantni vyraz nebo pro objekty: new <KSID konstanta> >]

Poznámka: V novém jazyku bude podporována inicializace poměných konstantním výrazem. To zjednoduší psaní konstruktorů.

Typy proměnných v krkalovi

Základní typy

  • char – 2B, unsigned, unicodový znakový typ
  • int – 4B, signed
  • double – 8B, floating point
  • name – 4B, do těchto proměnných mohou být přiřazovány KSID konstanty
  • object, <typ objektu> - 4B, pointer na objekt. K této proměnné je vždy přiřazen i typ objektu, tedy KSID konstanta.
  • null, – 0B, null konstanta – mohu ji přiřadit do proměnné libovolného typu. Pole, pointer na objekt i name mohou být null. Poznámka: pole null a prázdné pole se chová identicky.
  • void – 0B, prázdný typ.

Pole

Nad každým typem mohu vytvořit n-rozměrné pole. Toto pole není matice, ale pole polí. Každé jednotlivé pole může nezávisle měnit své rozměry. Pole jsou alokovány na haldě.

Příklad:

int[][] pole = {{1,2,3},null,{3,9}};
pole[0][3] = 4;
pole[0][4] = 5;
// {{1,2,3,4,5},null,{3,9}}
pole[2] += pole[0];
// {{1,2,3,4,5},null,{3,9, 1,2,3,4,5}}
pole[1] = pole[2];
// {{1,2,3,4,5},{3,9, 1,2,3,4,5},{3,9, 1,2,3,4,5}}
pole[2]->SetCount(4); // pozor, pred chvili jsme priradili pointer!
// {{1,2,3,4,5},{3,9, 1,2},{3,9, 1,2}}
pole = null;
// {}
pole[4][4] = 1;
// {{},{},{},{},{0,0,0,0,1}}

Modifikátory

V určitém kontextu je možné k typům ještě přiřadit modifikátory jako static, ret, retor, retand, retadd, safe, override, direct.

Žádné další typy nejsou! Proti původnímu jazyku, který obsahoval ještě pointery, pole C-čkovýho typu, struktury a prokletý typ string je to úžasné zjednodušení!

Deklarace safe metody

Mezi modifikátory u metody mohou být slova: safe, override, static, retand, retor, retadd.\\ u parametru: ret, retand, retor, retadd.

[<modifikatory>] <typ> [<specifikace poctu dimenzi pole>] <pojmenovani> ([<paramentry>]) [<atributy>] <telo>
<parametry> : <parametr> [,…]
<parametr> : [<modifikator>] <typ> [<specifikace poctu dimenzi pole>] <pojmenovani> [<atributy>] [= <konstantni vyraz>]

Příklad:

static name GetType(object o) {
  return typeof(o);
}

int[] FillArray(int size, int value) {
  int[] arr;
  for (int f=0; f<size; f++) arr->Add(value);
  return arr;
}

Deklarace direct metody

direct [static] <typ> [<specifikace poctu dimenzi pole>] <pojmenovani> ([<parametry>]) [<atributy>] <telo>
<parametry> : <parametr> [,…]
<parametr> : [ret] <typ> [<specifikace poctu dimenzi pole>] <pojmenovani> [= <konstantni vyraz>]

Příklad:'

direct int sum(ret int result, int[] pole) {
  result = 0;
  if(!pole->GetCount())
     return 0;
  foreach (int f in pole) result += f;
  return 1;
}

Skupina proměnných

Seskupování proměnných do skupin má význam pro editor levlů. Skupin je několik typů: existuje obecná skupina (group) i řada specifický skupin, s předem daným významem a s omezením na typy a množství proměnných uvnitř.

<klicove slovo> <pojmenovani> [<atributy>] {
  <deklarace promenne>
  <skupina promennych>
  <ovladaci prvek pro editaci>
}

Ovládací prvek pro editaci

Separátor

separator <pojmenovani> [<atributy>];

Tlačítko

button <pojmenovani> (<KSID jmeno obsluhujici metody>[, <paremetr typu int>]) [<atributy>];

Identifikátory

Většina identifikátorů jsou zároveň KSID jména (a ty se dají přiřazovat do proměnných typu name) KSID jména jsou jména objektů, proměnných, metod, parametrů safe metod a jména mnoha dalších entit. Nejsou to jména lokálních proměnných a jména parametrů u direct metod.\\ KSID jména mají globální platnost.

Aby nevznikaly konflikty jmen, jsou tvořena strukturovaným identifikátorem:
Například: $jmeno1.jmeno2.jmeno3

Aby psaní identifikátorů mohlo být stručnější, existují určité kontexty, kde jsou všechny identifikátory lokalizovány k nadřazenému identifikátoru. Například deklarace uvnitř objektu:

class Stena {             // $Stena
  int x;                  // $Stena.x
  void funkce1(int a) {}  // $Stena.funkce1
                          // $Stena.funkce1.a
  void $funkce2() {}      // $funkce2
}

$ uvozuje úplné, nezkrácené jméno. Absence $ znamená, že se (vždy) provede lokalizace k nadřazenému jménu. Jaké je to nadřazené jméno samozřejmě závisí na kontextu. Rozlišování mezi úplným a lokalizovaným jménem je v Krkalovi na rozdíl od C++ povinné (pozdější rozšiřování by jinak měnilo význam dříve napsaného kódu).

Kontexty

globální kontext :

  • mimo objektovou závorku
  • v deklaraci, pokud se očekává typ
  • za operátorem new
  • v deklaraci, v inicializační části za znakem = (neplatí pro lokální proměnné, tam platí za = kontext objektu)
  • u atributů

kontext objektu :

  • v tělech metod, pokud jiné pravidlo neurčí jinak
  • v deklaraci, kde se očekává jméno deklarované entity (proměnné, metody, skupiny, ovládacího prvku)
  • ve výrazech v závorce () za operátorem new, -> a při pojmenovávání parametrů safe metod

kontext jiného objektu:

  • za operátorem ->

kontext safe metody:

  • v případě pojmenovávání parametrů safe metody

Verze

Pokud spojím pomocí include několik nezávislých zdrojových kódů, může vzniknout konflikt mezi jmény. Proto je každý dílčí identifikátor vybaven ještě verzí souboru, ve kterém vznikl. Unikátní KSID jméno pak může vypadat třeba takto:

$Stena$45A0_447C_C4B9_883F.funkce3$12EA_5641_8A97_EC1A

(Připisovat k identifikátorům verze je povinné jen v případě konfliktů)

Klíčová slova

Dílčí identifikátory se samozřejmě nemůžou shodovat s žádným klíčovým slovem (voidname, class, int, for, while, safe, static, typeof, null, ...)

Známá jména

Známá jména mají svůj vlastní oddělený namespace začínající znakem @. Uživatel normálně nemůže deklarovat jména v tomto namespacu. Je zaručeno, že známé a uživatelské jméno nikdy nebudou v konfliktu.

Známá jména slouží k pojmenování objektů, funkcí, konstant a proměnných v kernelu (různé knihovní funkce a služby).

static direct void @Map.PlaceObjToMap(object obj) // tahle metoda umisti objekt do mapy
static direct int @Math.randInt(int mez) // přirozené náhodné číslo z intervalu <0,mez>

Navíc známá jména může použít uživatel k pojmenování svých objektů, safe metod či proměnných a definovat tak například vstupní body pro příjem událostí.

void @MapPlaced() {} // kernel vola tuto metodu u objektu, ktery prave umistil do mapy.
void @Constructor() {} // volá se při vytvoření nového objektu
int @ObjPosX; // zde má objekt svoji X-ovou souřadnici

Mohou existovat objekty se speciálním významem. Jsou tedy pojmenovány známým jménem (např. @Configuration). Aby uživatel mohl jednoduše pojmenovávat prvky tohoto objektu, je zde udělána výjimka a uživatel může deklarovat nová jména v podstromě @Configuration.

Platnost identifikátorů

KSID identifikátory mají globální platnost. Začínají znakem $ nebo @ a jsou strukturované. V jednom souboru nemohou být deklarována dvě stejná jména. Stejná jména mohou přijít z různých souborů, pak se ale liší verzí.

Je možné definovat více proměnných stejného jména u více objektů. Pak se jedná o tutéž proměnnou a deklarace se musí shodovat. Příkladem je @ObjPosX.

Je zakázáno deklarovat více direct metod, skupin a ovládacích prvků od stejného jména. (Ale teoreticky by se to dalo povolit a řešit to stejně jako proměnné)

Je povoleno deklarovat libovolný počet safe metod stejného jména, pod podmínkou, že metody mají stejný návratový typ. Příkladem může být metoda @Constructor. Samotný objekt jich může mít více, navíc jich mohl spoustu zdědit od předků. Pokud dojde k volání safe metody, zavolají se u objektu všechny tyto metody v nedefinovaném pořadí.

Je povoleno použít stejné jméno safe parametru u mnoha různých těl metod. Zde nejsou kladeny žádné omezující podmínky. Doporučuji, aby se shodoval typ a význam.

Lokální proměnné a parametry

Nejsou to KSID jména a mají pouze lokální platnost v závorce {}, kde byly deklarovány. Lokální proměnné zastiňují KSID jména a jiné lokální proměnné deklarované v nadřazené závorce {}. Lokální proměnné nemohou být strukturované.

U safe metod automaticky vznikají lokální identifikátory parametrů z KSID jmen parametrů. Jako lokální identifikátor se použije poslední část strukturovaného KSID jména.

Zpracování identifikátorů

Identifikátory budou zpracovávány už během lexikální analýzy do jednoho tokenu. Včetně těch strukturovaných se znaky $ a @ a s případnou verzí. (znaky $ a @ jsou rezervovány jen pro identifikátory. Znak . pro identifikátory a reálná čísla).

Poznámka: lexikální analýza ještě neví nic o kontextech.

Tělo metody

{
  // nasledujici prvky jsou volitelne, poradi muze byt libovolne
  <deklarace lokalni promenne>
  <vyraz>;
  <prikaz>
  <slozena zavorka>
}

Deklarace lokální proměnné

<typ> [<specifikace poctu dimenzi pole>] <deklarace>[,…];
<deklarace> : <novy identifikator> [= <vyraz>]

Poznámka: potřebuji rozlišit <deklarace lokalni promenne> a <vyraz>, na to potřebuji LL(2) a preskakovat []

Výrazy

Vyhodnocení identifikátorů

Mimo tělo metody jsou všechny identifikátory překládány na KSID konstanty. Uvnitř metody mám identifikátory lokálních proměnných a parametrů, ty mají vždy význam proměnné daného typu. KSID identifikátory proměnných mohou být přeloženy dvěma způsoby:

-jako proměnná u objektu this či jako statická proměnná – je to tedy LVALUE určitého typu. -jako KSID konstanta

Způsob se rozlišuje kontextem. Defaultní je první možnost. Druhá nastává za operátorem %%->%%, &, new, a při specifikaci safe parametru (v případě 2 ani lokální proměnné nezastiňují KSID identifikátory). Pokud chci použít místo KSID konstanty proměnnou typu name, musím ji uzavřít do závorky ().

Operátor & slouží k získání KSID jména proměnné napravo od operátoru.

Aritmetické výrazy

Dochází k implicitním konverzím char <-> int <-> double. Konverzi z double na int je třeba provést pomocí některé knihovní funkce. Koncverzni funkce budou nadale k dispozici pro vetsi kontrolu.

Operátory porovnání (<, >, <=, >=, ==, != ) se vyhodnotí jako hodnota typu int (buď 0 nebo 1).

Neexistuje typ bool. Operátory && a || fungují nad typem int. 0 znamená false, nenulové číslo je true.

proměnné typu name, object a pole nelze zkonvertovat na číslo, ale je možné použít operátor exists() - testuje nenulovost pointeru.

Unární aritmetické operátory podle priority

++, --  (postfixové operátory)
++, --, +, -, !, ~ (prefixové operátory)

Binární aritmetické operátory podle priority

*, /, %
+, -
<<, >>
<, >, >=, <=
==, !=
&
|
&&
||
=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=  (asociativita zprava doleva)

Přístup k prvku objektu

<vyraz typu pointr na objekt>-><KSID konstanta>
<vyraz typu pointr na objekt>->(<vyraz typu name>)

Tento výraz se vyhodnotí podle typu jména na pravé straně následovně:

-přístup k proměnné objektu (LVALUE). Kompilátor kontroluje, zda proměnná u objektu existuje a za šipkou musí být KSID konstanta. -volání safe metody objektu (následná závorka () s parametry je povinná). Je možné volat i neexistující metodu. -volání direct metody objektu (následná závorka () s parametry je povinná). Existence kontrolována kompilátorem, KSID konstanta povinná. -přístup k ovládacím prvkům a skupinám je zakázán.

Přístup k poli

<vyraz typu pole>\[<vyraz typu int>\]

Výsledkem tohoto výrazu je pole, které má o jednu dimenzi méně. (0 dimenzionální pole už je lvalue proměnná základního typu.)

Systémové metody pro práci s polem:

<vyraz typu pole>->GetCount()
<vyraz typu pole>->SetCount(<vyraz typu int>)
<vyraz typu pole>->Add(<vyraz>)

Operátor + umožňuje konkatenaci polí.

Práce s pointry

Proměnné typu pole, objekt i name jsou pointry na entity, které jsou vždy alokovány na haldě. Pole polí je de facto pointr na pole pointerů na pole.

Operátor = kopíruje pointr, nikoli objekt, na který pointr ukazuje. Pokud chci kopírovat, vnitřky, musím použít k tomu určené funkce. U polí je nutné, aby se shodoval typ a počet dimenzí. Pointr na objekt mohu přiřadit jen do proměnné která je stejného typu, jako skutečný typ objektu, nebo do proměnné typu libovolného předka. (Tato podmínka je kontrolována za běhu a pokud není splněna, je výsledek přiřazení null)

Do všech pointrových proměnných mohu přiřadit null nebo 0.

Operátorem == a != mohu otestovat shodu pointerů. Nebo shodu s null. Pointry se mohou vyskytovat ve vyrazech, kde se ocekava boolean. Pak se s nimi pracuje jako s cisly.

Objekty je třeba vytvářet operátorem new. Pole se vytváří automaticky, když je potřeba, a prázdné pole se chová stejně jako pole null. KSID jména jsou vytvořeny předem.

Nový Krkal bude využívat garbage collector, to znamená, že pokud pointr není null, tak je vždy platný.

Není možné konvertovat pointry na čísla nebo obráceně. Krome vyrazu, kde se ocekava bool (if(ptr), ptr && ...)

Operatorem exists(ptr) ziskam cislo 0 nebo 1. Stejne tak operatorem !, coz je "notexits". !!ptr muze nahradit exists(ptr) :-)

Práce se jmény

Operátory <, >, >=, <= lze testovat množinové závislosti, či vztahy jmen. Nemusím porovnávat jen výrazy typu name, mohu porovnávat i výrazy typu objekt (či kombinace objekt a name). Na objekty je v tomto případě automaticky uplatněn operátor typeof()

KSID konstanty a proměnné typu name jsou základem skriptovacího jazyka v Krkalovi. Jejich použití je vidět ve veškerém okolním textu.

V kontextu, kde se KSID identifikátory proměnných berou jako ta proměnná nebo pokud jsou zastíněny lokální proměnnou, mohu použít operátor & k získání KSID konstanty.

V kontextu, kde se identifikátory berou jako KSID konstanty, mohu použít závorku a v ní výraz typu name.

Volání metody

<vyraz typu name>([<parametry>]) - vyhodnotí se jako volání metody u objektu this nebo volání statické metody.
<vyraz typu volani metody objektu O>([<parametry>]) - vyhodnotí se jako volání metody u objektu O.

Pokud jde o direct metodu, musi vyraz obsahovat KSID konstantu typu dmethodname. Je nutne aby kompilator mohl zkontrolovat zpravnost parametru a existenci metody u objektu.

Volání direct metody

<parametry> : <parametr>[,...]
<parametr> : <vyraz kompatibilniho typu>

Příklad:

int x = MyDirectMetod(b+1,c[0])->@ObjPosX;

Direct metody připomínají klasické metody v C++. Nemají volitelné parametry a proto při volání musím předat všechny parametry, které metoda vyžaduje. Kompilátor kontroluje, zda metoda u volaného objektu existuje.

V deklaraci se modifikátorem ret označuje parametr, který je předáván referencí.

Direct volání je rychlejší, proto direct metody by měly být různé pomocné rutiny s úzce specializovaným použitím, které se často volají během nějakého náročnějšího výpočtu.

Volání safe metody

Safe metody by měly být používány v co nejhojnější míře, hlavně pro komunikaci mezi objekty. Safe metody zaručují rozšiřitelnost a umožňují posílání zpráv. Můžu vyvolat metodu u objektu, který neznám a nevím, zda tuto metodu má. Můžu metodě předat libovolné parametry. Tělo, které volání přijímá si pak vybere ty parametry, které potřebuje, ty ostatní si vyplní defaultními hodnotami.

U objektu může být pod jedním jménem více safe metod. V tom případě se zavolají všechny tyto metody v nedefinovaném pořadí.

Více o safe volání a zprávách je v dokumentaci „Jak psát skripty“

<...>([<parametry>]) [<typ zpravy>]
<parametry> : <parametr>[,...]
<parametr> : [ret] <KSID konstanta identifikujici parametr nebo v zavorce vyraz typu name> = <vyraz libovolneho typu, pokud je pouzit ret, musi byt LVALUE>
<typ zpravy> může být: message, end, nextturn, nextend, timed(<vyraz typu int>), callend(<vyraz typu objekt>)

Pokud je typ zprávy zadán, tak se metoda neprovádí ihned, ale volání je uloženo do některé fronty zpráv. K vyvolání metody dojde později, až na zprávu přijde řada. Mezitím se pokračuje v běžném výpočtu.

Pokud je safe metoda zavolána jako zpráva, nemůže nic vracet a výraz se vyhodnotí jako typ void.

Příklad:

a = $MyDialog(text = “Chces opravdu zformatovat disk?”, flags = $OK | $Cancel, picture = exclamation);
if (a) $disk->Format() timed(440);

Build-in operátory, funkce, konstanty a proměnné

Funkce se chovají syntakticky stejně jako volání direct metod až na některé výjimky: některé se mohou vyskytovat i v konstantních výrazech, jiné přijímají argumenty proměnných typů. Jména těchto operátorů jsou klíčivá slova.

pointrovytyp copy(pointrovytyp dest, pointrovytyp source)
pointrovytyp dup(pointrovytyp source)
int compare(pointrovytyp a, pointrovytyp b)
int writevariable(object o, name var, libovolnytyp value)
int readvariable(object o, name var, ret libovolnytyp value)
char[] comment(name n)
char[] username(name n)
name typeof(object o)
int exists(object o)
int lives(object o)
void kill(object o)
int ismissing(safeparametr p)
null = 0
int true = 1
int false = 0
object this
object sender

Příkazy

<prikaz2> : <prikaz>
<prikaz2> : <vyraz>;
<prikaz2> : <slozena zavorka>
<slozena zavorka> : { [<prikazy, vyrazy, deklarace lokalnich promennych, slozene zavorky>] }

if, else

if (<vyraz typu int>) <prikaz2> [else <prikaz2>]

while

while (<vyraz typu int>) <prikaz2>

do

do <prikaz2> while (<vyraz typu int>);

for

for (<vyraz>; <vyraz typu int>; <vyraz>) <prikaz2>

foreach

foreach(<lvalue zakladniho typu> in <vyraz typu pole>[; <vyraz typu int>]) <prikaz2>

switch

switch (<vyraz>) {
  case <konstantni vyraz> : [<prikaz2>][,…]
  ...
  [default : [<prikaz2>][,…]]
}

Příkazy skoků

break;
continue;
return [<vyraz>];

Nespecifikováno

  • Budu podporovat operátory ? : a , ?
  • Poznámka: při safe volání, pokud je jméno metody zadáno proměnnou typu name, nevím návratový typ. Ten musím určit automaticky podle okolního výrazu. (Je to možné, protože typ si určuje volající.) Pěkná bitkařina :-)