|
|
This is NOT the latest version, which is available at: current
道语言简明教程傅利民(phoolimin 本文档基于GNU Free Documentation License 许可发布。 道(Dao)语言是一门面向对象的程序设计语言,它支持显式的变量类型申明,和隐式的类型推测, 既可以作为强类型语言使用,也可作为弱类型语言使用。 道支持多种复杂的数据类型。它拥有较强的文本处理能力,支持正则表达式。 它还提供了内置的如复数和数值数组等数值类型,这些类型的操作在道里比较方便。 多线程编程作为一个不可分割的部分集成到了道语言及其虚拟机里。 道语言还实现了函数的异步调用,使得某些类型的并行编程变得很简单。 网络编程和基于消息传递的分布式编程也作为标准库被支持。 道还有比较好的宏机制,可以实现语法扩展。 道语言可以由C/C++以方便透明的方式加以扩展,或者被嵌入到C/C++程序中。
dao [选项] script_source.dao 可使用 dao -h 查看可用选项。
# Hello World例程:
已在例子里提到了, # 用于注释单行,其后的字符将被解释器忽略;一对 #{ #} 用于注释多行。
多数情况下,语句结束符 ; 可省略,例外是 load,return 语句,它们必须由 ; 结束。
stdio.print( "Hello World!" ); #{ 多行注释 多行注释 #}
stdio 是道里面的基本IO库, stdio.print() 将其参数的结果打印到标准输出。 从道语言1.0Beta版开始,道语言里不再有内置的函数,它们都成为了某个库的成员方法。 道里面可用的库包括: stdio , stdlib , math , reflect , coroutine , network , mpi (message passing interface消息传递接口) 和 mtlib (multi-threading library多线程库)。 另外,大部分道数据对象都有内置的成员方法。任何数据对象或库的成员方法均可由 stdlib.listmeth( obj ) 列出来。 参考道语言类型和库函数手册 。
道语言支持以下数据类型:数字,字符串,列表,关联表(字典),类对象 复数和数值数组等。它们可由赋值,枚举或函数调用等方式创建。每个道变量可以有 固定的类型。
注1:在以等差序列创建数值数组时, init 值也可以是一个数值数组, 这种情况下,被创建的多维数值数组中,“第一行”将等同于 init , “第二行”将等同于 init + step ,如此等等:
a = [ [ 0 : 3 ] : 5 ];
stdio.println( a ); a = [ [ 0 : 3 ] : [ 1 : 3 ] : 5 ]; stdio.println( a ); 注2:当不带元素域名的枚举元组时,枚举的元素数目必须不少于二, 因为当数目少于二时,这种枚举会和算术表达式使用括号分组相混淆。 元素数目少于二的元组可从列表或关联表映射得到,
ls = { "abc" };
tp = (tuple<string>) ls; 为了方便,道语言支持用 typedef 来定义类型的别名,
typedef tuple<x:float,y:float,z:float> Point3D;
pt : Point3D = ( 1, 2, 3 ); stdio.println( pt.x );
道语言支持丰富的运算符来增强代码的表达能力。许多运算符可用于多种数据类型。
备注二:对于自增或自减运算符,前缀与后缀无区别,均产生运算后的值。
为了增加可读性,与或非运算符可用 and , or 和 not 代替。 与或运算符运算方式跟Lua里的与或运算符运算方式一样, 也就是,这些运算返回最后求值的运算子的值。 这意味着,如果第一个运算子的值可以决定运算的结果,返回第一个运算子的值; 否则,返回第二个运算子的值。 当运算子的值均为0或1时,这种运算方式跟普通的布尔运算完全等价。 下面的例子给出运算子是任意值的情况,
10 && 0 => 0
在某些情况下适当使用与或运算符的运算方式可以简化代码。0 && 10 => 0 10 && 20 => 20 20 && 10 => 10 10 || 0 => 10 0 || 10 => 10 10 || 20 => 10 20 || 10 => 20
( C, A, B, ... ) = ( A, B, C, ... )
右边的表达式必须产生一个元组或列表,它们中的每个元素被赋给左边相应的变量。
多余的列表元素或被赋值变量将被忽略。( A, B ) = func();
为了完成一项任务,程序经常需要根据某个条件有选择性地或反复地执行一段代码, 这可以使用逻辑与循环控制语句来做到。 道语言目前支持 if-else , while , for , do-until , switch-case , break 和 skip 等控制。
当某条件表达式值为真时,执行一块代码:
if( expr1 ){
block1; }elif( expr2 ){ block2; }else{ block3; } 如果条件表达式 expr1 的值为真, block1 将被执行; 否则如条件 expr2 为真, block2 被执行; 否则执行 block3 。可使用零个或多个 elseif / elif , 和零个或一个 else 。
if( 2 > 1 ) stdio.println("2 is larger than 1.")
当某条件表达式值为真时, 反复 执行一块代码:
while( expr ){
如果条件表达式 expr 值为真,反复执行 block 直到表达式 expr 值为假。block; }
i = 0;
while( i < 5 ){ stdio.println( i ); i ++; }
for( 变量 = 初值 : 步长 : 终值 ){
循环将从 变量=初值 开始执行,然后每次循环后, 变量 的值按 步长
增加,直到 变量 的值变得大于 终值 时终止循环。
这里 步长 可以省略,其缺省值是1。
初值 , 步长 和 终值 总是在循环开始前被计算。代码; } C/C++类型 for 循环:
for( init; condition; step ){
for 语句块的执行顺序是这样的:block; }
一般情况下,C/C++类型 for 循环等价于下面的 while 循环:
init;
但如果 block 包含一个不被其他循环语句包含的 skip 语句,那么上面这个 while 循环
与C/C++类型 for 循环并不完全等价。因在 for 循环体中, skip 只跳过 block
块余下的部分,而在上面的 while 循环中, skip 将同时跳过 step 语句。while( condition ){ block; step; } 道语言也支持Python风格的 for-in 循环:
for( item in list ){
block; } 关联表也可用在for-in循环中,这里 item 将会是一对键与值,
for( item in a_map ){
block; } 在一个for-in循环中可以使用多个in语句,但那些列表或关联表必须含有相同个数的元素, 否则,程序将抛出例外,
for( item1 in list1; item2 in list2; ... ){
block; } 例子,
for( i:=0; i<3; i++ ){
这个例子抛出了一个例外,因为最后那个列表的元素数目比其他第一个列表少一。stdio.println( i ); } hash = { "b" => 11, "a" => 22, "e" => 33, "c" => 44 }; for( a in hash.key(); b in hash.value(); c in {1 : 1 : hash.size()-1 } ){ #if a == "a" break stdio.println( a, "\t", b, "\t", c ); }
do{
block; } until ( condition )
a = 10;
do{ c = 1 stdio.println( "here", a -- ); }until( a == 0 ) 注:当使用单个字符串作为 if,while,for,until 中的条件表达式时, 如果字符串长度大于零,返回真值;否则返回假值。
switch( exprs ){
如果表达式 exprs 的值等于某个 case 语句的 Ci ,代码块 blocki 将被执行。
这里 Ci 必须是常量,可以是不同类型的值。与C/C++不同的是,代码块 blocki 被执行后,
程序执行将跳到 switch 块外,因此这里不需要象C/C++里那样使用 break 语句来显示跳出
switch 块。如果你需要对不同的 case 值都执行同一块代码,你仅需将那些 case
语句放在一起:
case C1 : block1 case C2 : block2 case C3 : block3 ... default: block0 }
switch( value ){
在这种情况下, case 值 C1,C2,C3 将对应于同一代码块 block3 。
case C1 : case C2 : case C3 : block3 ... default: block0 }
a = "a";
switch( a ){ case 1 : case "a" : stdio.print("case 1 or a"); default : stdio.print("case default"); }
for( i=0; i<5; i++ ){
stdio.println( i ); if( i == 3 ) break; }
大多数程序需要处理某种形式的输入与输出(IO, Input / Output)。道语言支持一些基本的IO 功能,它们主要由标准库 stdio 提供。更多信息请参看 道语言库方法参考 例子:
# 打开写文件:
fout = stdio.open( "test1.txt", "w" ); # 写入文件: fout.print( "log(10)=", math.log( 10 ) ); # 打开读文件: fin = stdio.open( "test2.txt", "r" ); # 当还未读到文件末尾: while( ! fin.eof() ){ # 从文件读入一行: line = fin.read(); # line包含行结束符; # 写到标准输出: stdio.print( line ); } # 从标准输入读入一行: d = stdio.read(); stdio.println( d );
函数是一可反复使用的代码块。它由关键字 routine 定义,拥有一个名字。 它可在被使用时接受参数,参数的名称,类型和缺省值需在定义时给定。 它也可在使用结束时返回一个或多个结果。 考虑到一些用户习惯,关键词 function 也可用来定义函数, 其作用跟 routine 完全等同。
routine name( [ param1 [ : type | [:]= const_expr ] [, param2 [...], ... ] ] )
{ [...] }
routine func( a, b )
{ stdio.println( a, b ); a = 10; b = "test"; return a, b; # return more than one results. } r1, r2; ( r1, r2 ) = func( 111, "AAA" ); r3 = func( r1, r2 ); stdio.println( "r1 = ", r1 ); stdio.println( "r2 = ", r2 ); stdio.println( "r3 = ", r3 );
道语言函数的参数可按参数名字传递:
func( b => 123, a => "ABC" );
正如道语言变量可声明为有类型的,道函数的参数也可声明为有类型,并还可声明为有缺省值。
routine MyRout( name : string, index = 0 )
这里参数 name 被声明为字符串,参数 index 被声明为整数,并以零为缺省值。
如果一个函数调用使用错误的参数,或没有数据传递给没有缺省值的参数,
将导致报错,并终止运行。{ stdio.println( "NAME = ", name ) stdio.println( "INDEX = ", index ) } 参数缺省值可指定给参数表中的任意参数,而不管指定缺省值的参数后面的参数是否有缺省值。如,
routine MyRout2( i=0, j ){ stdio.println( i, " ", j ) }
在这种情况下,如果你想用 i 的缺省值,那么你需要将数据按参数名字传给 j 。MyRout2( j => 10 )
道语言里,函数可按参数类型进行重载。也就是可对于拥有不同参数类型的函数 使用同样的名称,函数调用时,道虚拟机根据调用中的参数选择正确的函数来运行。
routine MyRout( index : int, name = "ABC" )
{ stdio.println( "INDEX = ", index ) stdio.println( "NAME = ", name ) } MyRout( "DAO", 123 ) # 调用上例中的MyRout() MyRout( 456, "script" ) # 调用此例中的MyRout()
在道语言里有匿名函数,是基本类型(也就是first-class function), 他们按如下方式定义:
foo = routine( x, y : TYPE, z = DEFAULT )
除了以下三点不同外,这种函数的定义跟普通函数的定义完全一样:
{ codes; }
例子:
a = "ABC";
rout = routine( x, y : string, z = a+a ){ a += "_abc"; stdio.println( "lambda ", a ) stdio.println( "lambda ", y ) stdio.println( "lambda ", z ) } rout( 1, "XXX" );
当一个函数被调用时,如果它函数名前有 @ 符号, 此调用将不执行该函数,而是返回一个发生器或协程。 在这样的函数里,可使用 yield 语句来向调用者返回值。 当 yield 语句被执行时,此函数的运行将被暂停, 并将运行控制权转给其调用者,而当调用者再次重新执行 此函数时,函数将从暂停处继续执行。 yield 语句执行完后,它将会象函数调用一样返回值, 被返回的值就是其调用者作为参数传入的值。 当函数运行至函数末尾或 return 语句后, 函数将终止运行,并且不可续。
# int => tuple<int,int>
routine gen1( a = 0 ) { k = 0; while( k ++ < 3 ) a = yield( k, a ); return 0,0; } routine gen2( a = 0 ) { return gen1( a ); } g = @gen2( 1 ); # 第一次调用时,参数可省略, # 创建时用到的参数将被在第一次调用时使用: stdio.println( 'main1: ', g() ); stdio.println( 'main2: ', g( 100 ) ); stdio.println( 'main3: ', g( 200 ) );
routine foo( a = 0, b = '' )
{ stdio.println( 'foo:', a ); return yield( 2 * a, 'by foo()' ); } routine bar( a = 0, b = '' ) { stdio.println( 'bar:', a, b ); ( r, s ) = foo( a + 1, b ); stdio.println( 'bar:', r, s ); ( r, s ) = yield( a + 100, b ); stdio.println( 'bar:', r, s ); return a, 'ended'; } co = @bar( 1, "a" ); stdio.println( 'main: ', co() ); stdio.println( 'main: ', co( 1, 'x' ) ); stdio.println( 'main: ', co( 2, 'y' ) ); # 协程已运行完,再调用将产生异常: stdio.println( 'main: ', co( 3, 'z' ) ); 发生器和协程也可由标准方法 stdlib.coroutine() 来创建, 不过这种情况下,函数必须同时使用标准方法 stdlib.yield() 来返回值。 另外,这两种方法创建的发生器或协程有个很重要的区别。 使用前缀 @ 创建的发生器或协程支持类型检查, 而使用 stdlib.coroutine() 创建的不支持。
道语言对面向对象编程(object-oriented programming, OOP)有良好的支持。 道语言类使用关键字 class 定义。 一个类就是一组变量与函数的集合的抽象表示,这些变量和函数称为类的成员; 成员变量的值将决定该类的特性,成员函数决定了该类的行为。 类本身是程序员定义的抽象类型,它的值即实例就是一个具体的数据集合,此集合 包含了类定义的成员变量。 类实例可以以函数调用的方式调用类的构造函数创建,也可通过枚举类成员变量来创建。 类成员的访问权限可由修饰词 private (私有), protected (保护) 和 public (公开)来限定,缺省权限为公开。 这些修饰词后可跟也可不跟冒号。 类与类之间可存在继承和包含关系。一个类(子类)可定义为另一个类(基类)的引申。 子类可从基类继承某些特性,在基类的基础上扩充或专门化某些功能。类也可以包含其他类 的实例为成员。
道语言里基类的定义跟函数定义很相似。
class name( [ param1 [ : type | [:]= const_expr ] [, param2 [...], ... ] ] )
在定义形式上与函数的主要不同点在于,类定义体里可使用关键字 my 。有 my 修饰的变量
申明将该变量申明为类的成员。同普通变量类似,类成员变量也可按下面方式申明为有固定类型,
{ [...] }
my variable : type;
这里 type 必须是一常量,这样 variable 的类型将固定为 type 的类型;
或者 variable 必须是 type 的实例,如果 type 也是类的话。类的成员变量还可拥有缺省值。在类创建时,有缺省值的成员变量将被首先以缺省值填充。 类的成员变量的缺省值可按以下方式指定,
my variable := init_value;
这里 init_value 也必须是一常量。在道语言里,类的定义体也是类的构造函数。和其他某些脚本语言里的类构造函数类似, 道语言里的类构造函数并不是真正用来构造类实例,而是用来初始化类的成员数据。 道语言里,类可拥有多个重载的构造函数,用来根据不同的构造函数调用参数以不同的方式初始化类实例。 例子,
class MyNumber( value = 0, name = "NoName" )
{ private my Value := 0; # value缺省值为零 my Name : ""; # name必须是字符串 Value = value; self.Name = name; public routine setValue( value ){ Value = value } routine getValue(){ return Value } routine setValue( value : int ); } routine MyNumber::setValue( value : int ) { Value = value; } 在类的构造函数或成员函数里,可使用一特殊变量 self ,它表示类的当前实例。 与C++里的类成员函数定义类似,类的成员函数可在类定义体内申明,然后在类体外定义。 不过在道语言里,类体外定义的成员函数的参数表必须和申明时的完全一致。 Dao里,虚拟函数也可用关键词 virtual 来申明。 如果一个类成员函数里没使用类成员变量,且没调用其他使用了类成员变量的成员函数, 那么此成员函数可按如下方式调用,
classname.method(...)
新的类实例可以由调用该类的构造函数得到,构造函数的调用方式跟普通函数调用完全一样。
obj1 = MyNumber(1);
类实例也可通过枚举类的成员变量创建,这种实例创建方式主要适合于比较简单的类,因为这种不需要
复杂操作进行初始化。
obj2 = MyNumber{ 2, "enumerated" };
在枚举成员变量时,可指定成员的名称,
obj3 = MyNumber{
Name => "enumerated"; Value => 3; }; 当类实例由枚举创建时,类实例先被成员变量的缺省值填充,然后使用枚举中的数据初始化相应的 成员变量。通过枚举创建类实例比通过调用类构造函数创建类实例要快得多,调用类构造函数有一系列 额外开销,如参数传递,函数运行时数据的分配等。 枚举创建实例很适合于创建大量简单类的实例。
正如上面提到,类的成员变量由关键字 my 在类体内申明。 my 也可和其他关键字如 const 和 global 组合来申明其他形式的类成员数据,
class Klass
这里 aClassConst 被申明为类常量;而 aClassStatic 被申明为类全局变量,
类似于C++类里的静态变量。{ my const aClassConst = "KlassConst"; # or, const my aClassConst=""; my global aClassStatic; # or, global my aClassStatic; }
相对于给私有或保护的成员变量定义 setXyz() 或 getXyz() 方法, 更好的方式是定义所谓的Setters和Getters,定义这样的方法使得从外部环境可以直接 对私有或保护的成员变量进行访问,就像访问公开成员一样。 对于成员变量 _Xyz() 其Setters应被定义为 _SETF_Xyz(), 而 Getters应被定义为 _GETF_Xyz() 。 当Setters被定义后 Xyz 可由 obj.Xyz=abc 设定; 而当Getters被定义后 Xyz 可由 obj.Xyz 获取。
class MyNumber( value = 0 )
{ private my value; self.value = value; public routine _SETF_value( v ){ value = v; stdio.println( "value is set" ) } routine _GETF_value(){ return value } } num = MyNumber( 123 ) stdio.println( num.value ) num.value = 456 stdio.println( num.value ) 你也许已经猜到,通过Setters和Getters对类成员变量的访问会有比较大的运算开销。 因此为了效率起见,需要从外部访问的成员变量应被设为公开。 只有在必要时才用Setters和Getters,比如当你需要在那些成员变量被访问时作些额外工作时。
类的成员方法可以象普通函数那样被重载。类的构造函数也可被重载,给类定义于类同名的 成员方法即可,不过在重载的类构造函数中不可使用关键词 my 来定义成员变量。 如类 MyNumber 可作如下修改使得它只可从数字或该类的实例构造和赋值,
class MyNumber( value = 0 ) # accept builtin number as parameter
{ private my value : int; self.value = value; public # 接受MyNumber实例为参数的构造函数,类似于C++里的复制构造函数: routine MyNumber( value : MyNumber ){ self.value = value.value } routine _SETF_value( v : int ){ value = v } routine _SETF_value( v : MyNumber ){ value = v.value } routine _GETF_value(){ return value } } num1 = MyNumber( 123 ) num1.value = 456 stdio.println( num1.value ) num2 = MyNumber( num1 ) stdio.println( num2.value ) num2.value = 789 stdio.println( num2.value ) num2.value = num1 stdio.println( num2.value )
class ColorRBG( r, g, b )
下面将定义 ColorRBG 的一个派生类,
{ private my Red = r; my Green = g; my Blue = b; public routine setRed( r ){ Red = r; } routine setGreen( g ){ Green = g; } routine setBlue( b ){ Blue = b; } routine getRed(){ return Red; } routine getGreen(){ return Green; } routine getBlue(){ return Blue; } } yellow = ColorRBG( 255, 255, 0 ); # create an instance.
class ColorQuad( r, g, b, a ) : ColorRBG( r, g, b )
{ public my alpha = a; # alpha component for tranparency. } yellow2 = ColorQuad( 255, 255, 0, 0 ); # not tranparent. yellow2 . alpha = 127; # change to half tranparency. 当从已有类派生新类时,基类必须放在派生类的参数列表后,并由 : 隔开。 如果有多个基类,这基类都应被放在 : 后并被 , 隔开。 派生类构造函数的参数可按例子所显示的方式传递给基类的构造函数。
当一个程序变得比较大时,经常有必要将那个程序模块化,这样会使得程序的维护变得更容易。 道语言对程序模块化有相当的支持,道的模块既可静态载入(编译时),也可动态载入(运行时)。 道模块既可以由道语言开发,也可由C/C++语言开发。 如果模块是由道语言开发,当模块被载入时,该模块的主代码 (文件中不被类和函数所包含的代码)将在载入后立即被执行。 如果模块是由C/C++语言开发,当模块被载入时,该模块的入口函数( DaoOnLoad() ) 将在载入后立即被执行。 当该模块被再次载入时,上次载入的模块数据将被使用,如果模块是由道语言开发, 那么该模块的主代码将被再次执行。
编译时模块载入由关键词 load 完成,最简单的方式是:
load MyModule; # 或:load "MyModule";
这样载入时,道虚拟机将先在当前目录里然后在道库目录里寻找 MyModule.dao ,
如果找到则载入,否则再寻找 MyModule.so 或 MyModule.dll 。模块所在的相对路径也可在 load 语句中指定:
load MyPath.MyModule; # 等价于: load "MyPath/MyModule";
这种情况与前面类似,只不过道虚拟机将先在当前目录和道库目录里寻找子目录 MyPatch
然后检查该目录里是否有相应于 MyModule 的模块文件。
模块的绝对路径必须以字符串的形式指定。以上面的方式载入模块,模块中的所有全局常量,变量,函数,类和C/C++类型都将被输入到 当前的命名空间。为了限制被输入的数据对象,可使用 import :
load MyModule import name1, name2;
这样只有名字出现在列表中的全局数据对象被输入到当前命名空间。如果你不希望模块中的全局数据对象被输入到当前命名空间,可以这样作:
load MyModule as MyNS1;
这样名为 MyNS1 和 MyNS2 的命名空间将被创建,
而模块中的全局数据对象将被输入到相应的命名空间。
而后,那些数据对象可被这样访问: MyNS1.xyz 或 MyNS1.xyz(...) 。load MyModule import name1, name2, name3 as MyNS2; 某些情况下,C/C++模块可能依赖于另一些C/C++模块,这些被依赖的模块 可使用 require 指定,
load MyModule require AnotherMod1, AnotherMod2;
require 后面的模块名必须是不带目录和后缀的模块文件名。
如果有多个从不同目录载入的模块拥有同样的模块文件名,
只有最后被载入的那个被 require 使用。
运行时载入模块可使用标准库里的函数 stdlib.load( mod ) , 这个函数的参数 mod 必须是模块名称(可以包含路径)。 那个模块中的全局数据对象将被输入到当前命名空间。
在模块载入时,如果模块的相对目录被给定,那么这个目录将从当前目录 (缺省的当前目录为道虚拟机开始运行时的目录)开始查找,然后在库目录表中查找。 在库目录表中查找时,后加入的目录将先被查找。 当前目录和库目录表可在编译时有 @PATH(+-path) 设定:
缺省情况下,下列目录将被按顺序加入到库目录表里:
道语言里,命令行参数由两个全局变量保存: CMDARG 和 ARGV 。 CMDARG 是一个关联表,将参数名和参数序号映射到参数值; 而 ARGV 是一列表,按顺序保存参数值。 例如,如果由命令行执行 dao cmdarg.dao -arg1 -arg2 abc -arg3=def arg4=10 , 那么 CMDARG 和 ARGV 将包含以下元素:
CMDARG = { arg1 => arg1, arg2 => abc, arg3 => def, arg4 => 10, 1 => cmdarg.dao, 2 => arg1, 3 => abc, 4 => def, 5 => 10 }
命令行参数解析规则,
ARGV = { cmdarg.dao, arg1, abc, def, 10 }
# the main function for script.dao:
对于这个例子,这个程序被执行时,它命令行参数必须有一字符串, 还可有一数字。
因此,它必须按以下方式被执行:
routine main( name : string, index=0 ) #{ main()函数的文档,可包含如何使用此程序的信息: 使用:dao script.dao name=abc [index=0] #} { ... }
dao script.dao xyz
dao script.dao xyz 10 dao script.dao name=xyz index=10 dao script.dao index=10 name=xyz ...
通过类型映射,大部分道基本数据类型可以方便转换为其他数据类型,例如:
num = 123456789;
str = (string) num; ls = (list<int>) str; ar = (array<int>) ls; tup = (tuple<float,float>) ls[0:1]; stdio.println( num ); stdio.println( str ); stdio.println( ls ); stdio.println( ar ); stdio.println( tup ); ar += 'a'[0] - '1'[0]; ls = (list<int>) ar; str = (string) ls; stdio.println( ar ); stdio.println( ls ); stdio.println( str ); ar2 = [ [ 65 : 3] : 5 ]; ls2 = (list<list<int> >) ar2; ls3 = (list<string>) ar2; ls4 = (list<string>) ls2; stdio.println( ar2 ); stdio.println( ls2 ); stdio.println( ls3 ); stdio.println( ls4 );
view count 288 times
created at 2009-09-17, 05:44 GMT |
fu: A little bit game development in Dao! Thanks to ClangDao, it has become very easy to create bindings for C/ C++ libraries. The latest one i ... (May.14,07:08) dao: Dao 1.2 Beta1 is released! After a very long time of development, the first beta release for Dao 1.2 is finally available ( http ... (May.06,23:37) fu: ... Just to mention: a couple of demos (including the 2000 line one) has been successfully ported to IPho ... (May.19,02:43) fu: ... Yes, it is getting mature, and more libraries and modules are coming out, hehe:) For GameKit, unfor ... (May.19,02:38) Pompei2: ... This is cool news and really shows that ClangDao is getting mature, thumbs up. Too bad for this litt ... (May.18,09:17) fu: ... Not completely, but mostly. New revisions will be regularly pushed to the repository on google code ( ... (May.08,22:38) Pompei2: ... If I understand it correctly, you want to completely switch? If so then: (May.08,08:46) |