首页 > 开源 > zlang v0.12.14.1 发布,支持中文编程、支持 Web 开发/桌面应用开发的国产全自研编程语言

zlang v0.12.14.1 发布,支持中文编程、支持 Web 开发/桌面应用开发的国产全自研编程语言

OSChina资讯 2026-11-08 10:57 15 阅读 查看原文

0.12.14.1 2026-11-02 calvin

* 完善了文档中的对象函数的异常

* 修正了一些异常的设置错误

* 引入打包成安装程序交付

0.12.14.0 2026-10-29 calvin

* 支持声明变量时非缺省构造+赋值引用

* 修复了定点小数格式化打印的一个BUG

* 修复了定点小数的标准输入输出的一些BUG

0.12.13.1 2026-10-27 calvin

* 修复了database库各数据库驱动的一些BUG

0.12.13.0 2026-10-26 calvin

* VS2019工程集中增加dbdriver_postgresql、dbdriver_sqlite工程

0.12.12.0 2026-10-22 calvin

* database库和相关驱动新增支持tiny、fixed类型

* 修复了database库MySQL驱动的blob类型处理中的BUG

0.12.11.0 2026-10-16 calvin

* 重构数学库math代码以提高性能

* 数学函数支持定点小数了

* 数据库新增函数DegreeToRadian、RadianToDegree

0.12.10.0 2026-10-15 calvin

* fixed、ufixed新增函数FormatString、IsBetween、Rescale,新增四舍五入功能

0.12.9.0 2026-10-13 calvin

* 现在允许声明全局基本变量了

* 基本类型库新增定点小数类型fixed、ufixed,可以派生金额、利率等对象

0.12.8.1 2026-10-12 calvin

* 解决了一些问题


定点小数

定点小数类型

几乎所有业务系统都绕不开金额、费率、计息、对账,而编程语言中的 float/double 二进制浮点数类型天然存在小数无法精确表示的问题,是对账差错的经典来源。

zlang预置了定点小数类型fixed,即固定小数点后位数的小数类型,提供给开发者在需要固定小数位数的场景,比如金融、传感器采集等。

声明(克隆)一个定点小数对象:

fixed fx ;

未设置小数位数的声明对象会自动设置位数为自动(首次赋值数据时会自动根据数据小数位数设置位数)。

声明时直接显式设置小数位数:

fixed fx(2) ;

未设置舍入模式会自动设置为不舍入/截断(fixed.ROUNDMODE_NONE)。

声明时直接显式设置小数位数与舍入模式:

fixed fx(2,fixed.ROUNDMODE_HALF_UP) ;

声明后可以调用void Rescale(int);来后续设置小数位数;声明后可以调用void SetRoundMode(int);来后续设置舍入模式。

对定点小数的四则运算和其它基本类型一样,直接用+、-、*、/、%即可。

  • 示例代码: fixed-point-number.z

import stdtypes stdio ;
function int main( array args )
{
	fixed	fx1(2) = 12.34 ;
	fixed	fx2(2) = 56.78 ;
	fixed	fx3(2) = 34.56 ;
	fixed	fx4(2) = 78.90 ;
	fixed	fx5(2) ;
	fx5 = fx1 - fx2 * fx3 / fx4 ;
	stdout.Println( fx5 );
	return 0;
}

执行

$ zlang fixed-point-number.z
-12.53
  • 示例代码: calc-time-deposit-interest.z,该示例演示了一年期存款利息计算。

  • 根据利息计算公式: 利息 = 本金 * 年利率

import stdtypes stdio ;
fixed amount(2,fixed.ROUNDMODE_HALF_UP);
fixed rate(4);
function int main( array args )
{
	amount	deposit_balance = 5678.00 ;
	rate	deposit_rate = 1.2/100 ;
	amount	deposit_interest ;
	deposit_interest = deposit_balance * deposit_rate ;
	stdout.Println( deposit_interest );
	return 0;
}

执行

$ zlang calc-time-deposit-interest.z
68.14

此外,格式化打印、标准输入输出、数学函数等都直接支持定点小数基础类型,写法和其它基础类型使用无二致。

zlang定点小数类型内部用一个大整数、一个小数位数值来实现。

数据库DDL对应类型及操作

在数据库应用开发中,可以用DECIMAL、NUMERIC等类型定义定点小数类型,比如DECIMAL(12,2),用以存放金额类等数值,zlang语言用fixed基础类型与DDL中的定点小数类型相对应,存取表记录。

  • 示例代码: test_database_insert_1_1.z,该示例附带了建表DDL和插入记录代码操作。

import stdtypes stdio database datetime ;
/* test ddl
MySQL :
CREATE TABLE `mytable` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `my_int8` tinyint(3) DEFAULT NULL,
  `my_int16` smallint(6) DEFAULT NULL,
  `my_int32` int(11) DEFAULT NULL,
  `my_int64` bigint(20) DEFAULT NULL,
  `my_float` float DEFAULT NULL,
  `my_double` double DEFAULT NULL,
  `my_decimal` decimal(12,4) DEFAULT NULL,
  `my_char` char(3) DEFAULT NULL,
  `my_varchar` varchar(30) DEFAULT NULL,
  `my_date` date DEFAULT NULL,
  `my_time` time DEFAULT NULL,
  `my_datetime` datetime DEFAULT NULL,
  `my_timestamp` timestamp NULL DEFAULT NULL,
  `my_null` varchar(45) DEFAULT NULL,
  `my_blob` blob DEFAULT NULL,
  `my_longblob` longblob DEFAULT NULL,
  `my_emptyblob` blob DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`)
) ENGINE=InnoDB ;
PostgreSQL :
CREATE TABLE mytable (
  id int NOT NULL,
  my_int8 smallint DEFAULT NULL,
  my_int16 smallint DEFAULT NULL,
  my_int32 int DEFAULT NULL,
  my_int64 bigint DEFAULT NULL,
  my_float real DEFAULT NULL,
  my_double double precision DEFAULT NULL,
  my_decimal decimal(12,4) DEFAULT NULL,
  my_char char(3) DEFAULT NULL,
  my_varchar varchar(30) DEFAULT NULL,
  my_date date DEFAULT NULL,
  my_time time DEFAULT NULL,
  my_datetime timestamp DEFAULT NULL,
  my_timestamp timestamp NULL DEFAULT NULL,
  my_null varchar(45) DEFAULT NULL,
  my_blob bytea DEFAULT NULL,
  my_longblob bytea DEFAULT NULL,
  my_emptyblob bytea DEFAULT NULL,
  PRIMARY KEY (id)
) ;
Sqlite :
$ sqlite3 /tmp/calvindb.db
CREATE TABLE `mytable` (
  `id` int(11) NOT NULL,
  `my_int8` tinyint(3) DEFAULT NULL,
  `my_int16` smallint(6) DEFAULT NULL,
  `my_int32` int(11) DEFAULT NULL,
  `my_int64` bigint(20) DEFAULT NULL,
  `my_float` float DEFAULT NULL,
  `my_double` double DEFAULT NULL,
  `my_decimal` decimal(12,4) DEFAULT NULL,
  `my_char` char(3) DEFAULT NULL,
  `my_varchar` varchar(30) DEFAULT NULL,
  `my_date` date DEFAULT NULL,
  `my_time` time DEFAULT NULL,
  `my_datetime` datetime DEFAULT NULL,
  `my_timestamp` timestamp NULL DEFAULT NULL,
  `my_null` varchar(45) DEFAULT NULL,
  `my_blob` blob DEFAULT NULL,
  `my_longblob` longblob DEFAULT NULL,
  `my_emptyblob` blob DEFAULT NULL,
  PRIMARY KEY (`id`)
) ;
*/
function int main( array args )
{
	dbsession	dbsess ;
	dbresult	dbres ;
	string		sql ;
	int		nret = 0 ;
	if( args.Get(1) == "PostgreSQL" )
		dbsess = database.Connect( args.Get(1) , "localhost" , 5432 , "calvin" , "calvin" , "calvindb" ) ;
	else if( args.Get(1) == "Sqlite" )
		dbsess = database.Connect( args.Get(1) , "" , 0 , "" , "" , "/tmp/calvindb.db" ) ;
	else
		dbsess = database.Connect( "MySQL" , "localhost" , 3306 , "calvin" , "calvin" , "calvindb" ) ;
	if( dbsess == null )
	{
		stderr.FormatPrintln( "connect db failed[%d]-[%d][%s]-[%s]" , database.GetLastErrno() , database.GetLastNativeErrno() , database.GetLastNativeError() , database.GetLastSqlState() );
		return 1;
	}
	if( args.Get(1) == "PostgreSQL" )
		sql = "INSERT INTO mytable ( id , my_int8 , my_int16 , my_int32 , my_int64 , my_float , my_double , my_decimal , my_char , my_varchar , my_date , my_time , my_datetime , my_timestamp , my_blob , my_longblob , my_emptyblob ) VALUES( " + datetime.GetNow().SecondStamp().ToString() + " , NULL , 23 , 456 , 7890 , 1.2 , 34.56 , 78.90 , 'ABC' , 'calvin' , TO_DATE('2000-01-02','YYYY-MM-DD') , TO_TIMESTAMP('12:34:56','HH24:MI:SS') , TO_TIMESTAMP('2000-01-02 12:34:56','YYYY-MM-DD HH24:MI:SS') , TO_TIMESTAMP('2000-01-02 12:34:56','YYYY-MM-DD HH24:MI:SS') , 'blob' , 'long-blob' , '' );" ;
	else if( args.Get(1) == "Sqlite" )
		sql = "INSERT INTO mytable ( id , my_int8 , my_int16 , my_int32 , my_int64 , my_float , my_double , my_decimal , my_char , my_varchar , my_date , my_time , my_datetime , my_timestamp , my_blob , my_longblob , my_emptyblob ) VALUES( " + datetime.GetNow().SecondStamp().ToString() + " , 1 , 23 , 456 , 7890 , 1.2 , 34.56 , 78.90 , 'ABC' , 'calvin' , '2000-01-02' , '12:34:56' , '2000-01-02 12:34:56' , '2000-01-02 12:34:56' , 'blob' , 'long-blob' , '' )" ;
	else
		sql = "INSERT INTO mytable ( my_int8 , my_int16 , my_int32 , my_int64 , my_float , my_double , my_decimal , my_char , my_varchar , my_date , my_time , my_datetime , my_timestamp , my_blob , my_longblob , my_emptyblob ) VALUES( 1 , 23 , 456 , 7890 , 1.2 , 34.56 , 78.90 , 'ABC' , 'calvin' , STR_TO_DATE('2000-01-02','%Y-%m-%d') , STR_TO_DATE('12:34:56','%H:%i:%S') , STR_TO_DATE('2000-01-02 12:34:56','%Y-%m-%d %H:%i:%S') , STR_TO_DATE('2000-01-02 12:34:56','%Y-%m-%d %H:%i:%S') , 'blob' , 'long-blob' , '' )" ;
	dbres = dbsess.Execute( sql ) ;
	if( dbres == null )
	{
		stderr.FormatPrintln( "execute sql[%s] failed[%d]-[%d][%s]-[%s]" , sql , database.GetLastErrno() , database.GetLastNativeErrno() , database.GetLastNativeError() , database.GetLastSqlState() );
		return 1;
	}
	stdout.FormatPrintln( "records %d affected" , dbres.GetAffectedRows() );
	stdout.FormatPrintln( "insert id %d" , dbres.GetInsertId() );
	dbsess.Disconnect();
	return 0;
}
  • 示例代码: test_database_select_row2entiobj_1.z,该示例演示了读出DECIMAL类型字段自动映射到fixed类型的对象属性中。

import stdtypes stdio database datetime ;
object Record
{
	int		id ;
	tiny		my_int8 ;
	short		my_int16 ;
	int		my_int32 ;
	long		my_int64 ;
	float		my_float ;
	double		my_double ;
	fixed		my_decimal ;
	string		my_char ;
	string		my_varchar ;
	string		my_varchar2 ;
	datetime	my_date ;
	datetime	my_time ;
	datetime	my_datetime ;
	datetime	my_timestamp ;
	string		my_null ;
	string		my_blob ;
	string		my_longblob ;
	string		my_emptyblob ;
}
function int main( array args )
{
	try
	{
		if( args.Length() > 0 && args.Get(1) == "PostgreSQL" )
			dbsess = database.Connect( args.Get(1) , "localhost" , 5432 , "calvin" , "calvin" , "calvindb" ) ;
		else if( args.Length() > 0 && args.Get(1) == "Sqlite" )
			dbsess = database.Connect( args.Get(1) , "" , 0 , "" , "" , "/tmp/calvindb.db" ) ;
		else
			dbsess = database.Connect( "MySQL" , "localhost" , 3306 , "calvin" , "calvin" , "calvindb" ) ;
		sql = "SELECT * FROM mytable" ;
		dbres = dbsess.Execute( sql ) ;
		row_count = dbres.GetRowCount() ;
		for( r = 1 ; r <= row_count ; r++ )
		{
			Record		o ;
			b = dbres.RowToEntityObject( r , <object>o ) ;
			if( b != true )
			{
				stdout.Println( "RowToObject failed" );
				break;
			}
			stdout.FormatPrintln( "--- ROW %d ---" , r ) ;
			stdout.FormatPrintln( "          id : %?" , o.id );
			stdout.FormatPrintln( "     my_int8 : %?" , o.my_int8 );
			stdout.FormatPrintln( "    my_int16 : %?" , o.my_int16 );
			stdout.FormatPrintln( "    my_int32 : %?" , o.my_int32 );
			stdout.FormatPrintln( "    my_int64 : %?" , o.my_int64 );
			stdout.FormatPrintln( "    my_float : %?" , o.my_float );
			stdout.FormatPrintln( "   my_double : %?" , o.my_double );
			stdout.FormatPrintln( "  my_decimal : %?" , o.my_decimal );
			stdout.FormatPrintln( "     my_char : %s" , o.my_char );
			stdout.FormatPrintln( "  my_varchar : %s" , o.my_varchar );
			stdout.FormatPrint  ( "     my_date : " ); stdout.Println( o.my_date );
			stdout.FormatPrint  ( "     my_time : " ); stdout.Println( o.my_time );
			stdout.FormatPrint  ( " my_datetime : " ); stdout.Println( o.my_datetime );
			stdout.FormatPrint  ( "my_timestamp : " ); stdout.Println( o.my_timestamp );
			stdout.FormatPrintln( "     my_null : %s" , o.my_null );
			stdout.FormatPrintln( "     my_blob : %s" , o.my_blob );
			stdout.FormatPrintln( " my_longblob : %s" , o.my_longblob );
			stdout.FormatPrintln( "my_emptyblob : %s" , o.my_emptyblob );
		}

		catch
		{
			if( zexception.GetExceptionId() == zexception.START_COMMONPOOL_FAILED )
			{
				stdout.FormatPrintln( "connect database failed[%d]-[%d][%s]-[%s]" , database.GetLastErrno() , database.GetLastNativeErrno() , database.GetLastNativeError() , database.GetLastSqlState() );
			}
			else if( zexception.GetExceptionId() == zexception.EXECUTE_SQL )
			{
				stdout.FormatPrintln( "INSERT INTO failed[%d]-[%d][%s]-[%s]" , database.GetLastErrno() , database.GetLastNativeErrno() , database.GetLastNativeError() , database.GetLastSqlState() );
			}
			else
			{
				stdout.FormatPrintln( "* exception catched" );
				stdout.FormatPrintln( "* exception : [%d][%s]" , zexception.GetExceptionId() , zexception.GetExceptionDesc() );
				stdout.FormatPrintln( "* exception source : %s:%d,%d" , zexception.GetExceptionSourceFilename() , zexception.GetExceptionSourceRow() , zexception.GetExceptionSourceColumn() );
				stdout.FormatPrintln( "* exception function : [%s][%s]" , zexception.GetExceptionObjectName() , zexception.GetExceptionFunctionName() );
				stdout.Print( zexception.GetStackTrace() );
			}
		}
		finally
		{
			dbsess.Disconnect();
			stdout.Println( "Disconnect" );
		}
	}
	return 0;
}

执行

$ zlang test_database_select_row2entiobj_1.z
--- ROW 1 ---
          id : 1
     my_int8 : 1
    my_int16 : 23
    my_int32 : 456
    my_int64 : 7890
    my_float : 1.200000
   my_double : 34.560000
  my_decimal : 78.9000
     my_char : ABC
  my_varchar : calvin
     my_date : 2000-01-02 00:00:00
     my_time : 0000-00-00 00:00:00
 my_datetime : 2000-01-02 12:34:56
my_timestamp : 2000-01-02 12:34:56
     my_null : (null)
     my_blob : blob
 my_longblob : long-blob
my_emptyblob :
Disconnect
  • 示例代码: test_database_select_row2obj_1.z,或者根据表字段类型自动构造记录对象。

import stdtypes stdio database datetime ;
function int main( array args )
{
	try
	{
		if( args.Length() > 0 && args.Get(1) == "PostgreSQL" )
			dbsess = database.Connect( args.Get(1) , "localhost" , 5432 , "calvin" , "calvin" , "calvindb" ) ;
		else if( args.Length() > 0 && args.Get(1) == "Sqlite" )
			dbsess = database.Connect( args.Get(1) , "" , 0 , "" , "" , "/tmp/calvindb.db" ) ;
		else
			dbsess = database.Connect( "MySQL" , "localhost" , 3306 , "calvin" , "calvin" , "calvindb" ) ;
		sql = "SELECT * FROM mytable" ;
		dbres = dbsess.Execute( sql ) ;
		row_count = dbres.GetRowCount() ;
		for( r = 1 ; r <= row_count ; r++ )
		{
			o = dbres.RowToObject(r) ;
			if( o == null )
			{
				stdout.Println( "RowToObject failed" );
				break;
			}
			stdout.FormatPrintln( "--- ROW %d ---" , r ) ;
			stdout.FormatPrintln( "          id : %?" , o.id );
			stdout.FormatPrintln( "     my_int8 : %?" , o.my_int8 );
			stdout.FormatPrintln( "    my_int16 : %?" , o.my_int16 );
			stdout.FormatPrintln( "    my_int32 : %?" , o.my_int32 );
			stdout.FormatPrintln( "    my_int64 : %?" , o.my_int64 );
			stdout.FormatPrintln( "    my_float : %?" , o.my_float );
			stdout.FormatPrintln( "   my_double : %?" , o.my_double );
			stdout.FormatPrintln( "  my_decimal : %?" , o.my_decimal );
			stdout.FormatPrintln( "     my_char : %s" , o.my_char );
			stdout.FormatPrintln( "  my_varchar : %s" , o.my_varchar );
			stdout.FormatPrint  ( "     my_date : " ); stdout.Println( o.my_date );
			stdout.FormatPrint  ( "     my_time : " ); stdout.Println( o.my_time );
			stdout.FormatPrint  ( " my_datetime : " ); stdout.Println( o.my_datetime );
			stdout.FormatPrint  ( "my_timestamp : " ); stdout.Println( o.my_timestamp );
			stdout.FormatPrintln( "     my_null : %s" , o.my_null );
			stdout.FormatPrintln( "     my_blob : %s" , o.my_blob );
			stdout.FormatPrintln( " my_longblob : %s" , o.my_longblob );
			stdout.FormatPrintln( "my_emptyblob : %s" , o.my_emptyblob );
		}

		catch
		{
			if( zexception.GetExceptionId() == zexception.START_COMMONPOOL_FAILED )
			{
				stdout.FormatPrintln( "connect database failed[%d]-[%d][%s]-[%s]" , database.GetLastErrno() , database.GetLastNativeErrno() , database.GetLastNativeError() , database.GetLastSqlState() );
			}
			else if( zexception.GetExceptionId() == zexception.EXECUTE_SQL )
			{
				stdout.FormatPrintln( "INSERT INTO failed[%d]-[%d][%s]-[%s]" , database.GetLastErrno() , database.GetLastNativeErrno() , database.GetLastNativeError() , database.GetLastSqlState() );
			}
			else
			{
				stdout.FormatPrintln( "* exception catched" );
				stdout.FormatPrintln( "* exception : [%d][%s]" , zexception.GetExceptionId() , zexception.GetExceptionDesc() );
				stdout.FormatPrintln( "* exception source : %s:%d,%d" , zexception.GetExceptionSourceFilename() , zexception.GetExceptionSourceRow() , zexception.GetExceptionSourceColumn() );
				stdout.FormatPrintln( "* exception function : [%s][%s]" , zexception.GetExceptionObjectName() , zexception.GetExceptionFunctionName() );
				stdout.Print( zexception.GetStackTrace() );
			}
		}
		finally
		{
			dbsess.Disconnect();
			stdout.Println( "Disconnect" );
		}
	}
	return 0;
}

执行

$ zlang test_database_select_row2obj_1.z
--- ROW 1 ---
          id : 1
     my_int8 : 1
    my_int16 : 23
    my_int32 : 456
    my_int64 : 7890
    my_float : 1.200000
   my_double : 34.560000
  my_decimal : 78.9000
     my_char : ABC
  my_varchar : calvin
     my_date : 2000-01-02 00:00:00
     my_time : 1900-01-01 12:34:56
 my_datetime : 2000-01-02 12:34:56
my_timestamp : 2000-01-02 12:34:56
     my_null : (null)
     my_blob : blob
 my_longblob : long-blob
my_emptyblob :
Disconnect