1.1        NEKO

Scripting ed includibile

Neko è sviluppato ad opera di Nicolas Cannasse presso la Motion-Twin una società bordelese nata nel 2001 e specializzata in giochi in ambiente Internet.  Neko è frutto di un programma di ricerca e sviluppo della Motion-Twin.

Neko è un linguaggio di programmazione dinamicamente tipizzato indirizzato allo scripting ed alla inclusione. È basato su un compilatore che genera codice per una macchina virtuale ed un interprete inoltre un programma di servizio, nekotools.exe, permette di generare degli eseguibili.

Può utilizzare una discreta libreria che comprende, tra l’altro, l’accesso a MySQL, SQLite, la gestione di espressioni regolari, il protocollo XML, la compressione, i threads e i protocolli di rete.  Il linguaggio accetta gli usuali tipi: numeri, stringhe, booleani, ecc… Come aggregazioni sono disponibli gli array indicizzati con numeri interi, la tavole hash e gli oggetti. Quest’ultimi sono realizzati come tavole hash in cui il nome delle proprietà ed i metodi sono la parte chiave; metodi o proprietà sono quindi accessibili o con la notazione nomeoggetto.nomeproprietà-metodo o mediante procedure hash. L’ereditarietà si ottiene clonando un oggetto: nuovo_oggetto = $new(vecchio_oggetto); oppure dichiarando un oggetto prototipo di un altro:

circle = $new(null);

$objset(circle,$hash("pi"),355/113);                    // add property

circle.area = function(r)  {return r * r * this.pi;} // add method

var sphere = $new(null);                                // new object

sphere.volume = function(r) {return 4/3 * r * this.area(r);}

$objsetproto(sphere,circle);                   // inheritance from circle

$print("radius: 3 area: "+sphere.area(3)+" volume: "+sphere.volume(3)+"\n");

D:\neko>neko pr.n

radius: 3 area: 28.27433628 volume: 113.0973451

Lo standard output e realizzato dalla primitiva $print(), con l’utilizzo eventuale della funzione $sprintf() per formattare i risultati , le altre manipolazioni di file sono accessibili in una libreria che contiene anche $sys_getchar() per lo standard input.

E’ supportata la ricorsione, il trattamento delle eccezioni ed il goto. Il numero di funzioni per trattare le stringhe non è particolarmente ricco, la funzione (di libreria) string_split() genera un lista (linked array).

Le strutture di controllo comprendono if else, while ed un rudimentale switch.

// NekoVM 1.5.3 (c)2005-2007 Motion-Twin

// recursive function take n.th elements of list

var rec take = function (n, arr) {   

 if (n == 1) return arr[0];

 if (arr[1] != null) take (n-1,arr[1]);

}

string_split = $loader.loadprim("std@string_split",2);

str = $scopy("El Condor    Informatique   Turin");

i = $sfind(str,0,"  ");

while (i >= 0) {        //drop multiple spaces

  str = $scopy($ssub(str,0,i))+$scopy($ssub(str,i+1,$ssize(str)-i-1));

  i = $sfind(str,0,"  ");

}

words = string_split(str," ");

$print(words+"\n");

$print("take third: "+take(3,words)+"\n");

$print("take third: "+take(13,words)+"\n");

 

Figura 1

D:\neko>nekoc nn.neko

 

D:\neko>neko nn.n

[El,[Condor,[Informatique,[Turin,null]]]]

take third:   Informatique

take outside: false

 

D:\neko>

Qui accanto il risultato dell’esecuzione del programma di Figura 1 .

Neko ha aspetti dei linguaggi funzionali nel trattamento delle funzioni, fra gli strumenti di corredo la possibilità di generare un programma exe e un web server per provare i programmi Neko nella generazione di pagine HTML.

L’esempio che segue è un rudimentale interprete, del sistema Lolita, peraltro liberamente interpretato data la scarsità di documentazione disponibile:

// NekoVM 1.5.3 (c)2005-2007 Motion-Twin

var insert = function (arr,indx,symb) {

  var arr2 =$amake($asize(arr)+1);

  arr2[indx] = symb;

  if (indx != 0) $ablit(arr2,0,arr,0,indx);

  if (indx != $asize(arr)) $ablit(arr2,indx+1,arr,0,$asize(arr)-indx)

  return arr2;

}

var explode = function (str,split) {

  var rrow =$amake(0); // splitted data

  row = string_split(str,split);

  while (row != null)  {

    if (row[0] != "") rrow = insert(rrow,$asize(rrow),row[0]);

    row = row[1];

  }

  return rrow;

}

var getstring = function () {

$print ("insert expression (e.g. 3x5 or x2)\nenter for end ");

count = 0;

str = $smake(255);

  while (true)  {

    ch = getch(true);

    if (ch == 13) break;

    if (ch == 120) {

      $sblit(str,count," x ",0,3);

      count ++= 2;

    } else $sset(str,count,ch);

    count ++= 1;

  }

return $ssub(str,0,count);

}

var delete = function (arr,indx) {

  var arr2 =$amake($asize(arr)-1);

  $ablit(arr2,0,arr,0,indx);

  if (indx < $asize(arr2)) $ablit(arr2,indx,arr,arr,$asize(arr)-indx);

  return arr2;

}

var lomem = $hnew(100);               // hash table for symbols

var rec interp = function (cmd) {     // interpreter while(true) {

  if (cmd[0] == "DSYM") {$hadd(lomem,cmd[1],cmd[2]); return 1;}

  if (cmd[0] == "BRANCH") return $int(cmd[1]);

  if (cmd[0] == "STORE") {$hadd(lomem,cmd[1],SA.data); return 1;}

  if (cmd[0] == "LS") {SA.index = 0; SA.data = $hget(lomem,cmd[1],strcmp);

    return 1;}

  if (cmd[0] == "DISPLAY") {$print("SA: "+SA.data+"\n"); return 1;}

  if (cmd[0] == "SI") {SA.index = $int(cmd[1]); return 1;}

  if (cmd[0] == "IF")  {      

    if ((cmd[1] == "TOP" && SA.index >= ($asize(SA.data)-1)) ||

      (cmd[1] == "E" && $hget(lomem,cmd[2],strcmp) == SA.data[SA.index]) ||

      (cmd[1] == "NE" && $hget(lomem,cmd[2],strcmp) != SA.data[SA.index]))

        return interp($asub(cmd,3,$asize(cmd)-3));

    return 1;}

  if (cmd[0] == "SSB")                 // Insert Symbol Before

    {SA.data = insert(SA.data,SA.index,$hget(lomem,cmd[1],strcmp));

    SA.index=SA.index+1;

    return 1;}

  if (cmd[0] == "SSA")                 // Insert Symbol After

    {SA.data = insert(SA.data,SA.index+1,$hget(lomem,cmd[1],strcmp));

    return 1;}

  if (cmd[0] == "ES") {SA.data = delete(SA.data,SA.index); return 1;}

  if (cmd[0] == "CON")

    {SA.data = insert(SA.data,$asize(SA.data),$hget(lomem,cmd[1],strcmp));

    return 1;}

  if (cmd[0] == "DIFFER") {

    SA.data[0] = $string($int(SA.data[0]) * $int(SA.data[2]));

    SA.data[2] = $string($int(SA.data[2]) -1);

    return 1;}

  return 1;

}

// library access

file_contents = $loader.loadprim("std@file_contents",1);

string_split = $loader.loadprim("std@string_split",2);

getch = $loader.loadprim("std@sys_getch",1);

SA = $new(null);        // obj Symbol accumulator

while (true) {                  // main loop

  str = getstring();

  if (str == "") break;

  SA.data=explode(str," ");

  $print("\n");

  src = explode(file_contents("differ.txt"),"\r\n");

  var PC = 0;

  while (PC < $asize(src))  {

    PC = PC + interp(explode(src[PC]," "));

  }

}

1.1.1             NekoML

NekoML è una derivazione di Neko in forma di linguaggio funzionale, simile a OCAML.