1 Star 0 Fork 0

onemore / silang

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
BSD-3-Clause

Si 语言

A compiler for silang which is a new language.

Compiler = Flex + Bison + llvm

目标 & 简介

Si 是拍脑袋的产物,试验性的产品,现在仅仅出于最初级阶段。随时会变化。 糅合了 go, Java, C++, Lua 等语言中我觉得“爽”的部分,作为个人兴趣爱好实现,不必太过期待。

它应该有以下特点:

  • 它应该可以和 c 较好的融合 也就是方便的调用 c 语言编译出来的库,并且用它编译的库,也可以被 c 语言较好的调用。 在后端采用 LLVM 的情况下,这个目标似乎不难实现。站在巨人的肩上,也可能让它更好的发展。

  • 它应该可以和 c++ 较好的融合

  • 语法上会比较接近 Java,抛弃所有 C/C++ 中的复杂部分,但引入一些高级特性。

  • 编译型语言,编译的代码应该有较高的效率。所有的类型都是“可决”(在编译期完全确定)的。

  • 简洁&优雅,表现力强,行尾推荐不加 ; 但不强制

  • 原生的支持委托(或者说函数对象?)和闭包

  • 原生的支持协程,多线程

  • 原生支持 utf-8, unicode

  • 支持国际化

  • 可选的 GC

  • 谨慎的支持操作符重载

  • 使用一个简化的异常系统来处理错误。

  • 支持模板

设计思想:

  • 尽量避免对象的复制,凡是复制,都需要明确使用 clone

基础语法

编程风格

  • 变量使用小写开头,驼峰格式
  • 类使用大写开头,驼峰格式(内部类型除外)
  • 行尾不需要分号,而分号可以替代空大括号 {}

变量类型

支持的内置类型:

 名称       描述       符号  位宽 
-----------------
 boolean              无 1 bit 
 byte					无 8 bit 
 char					有 8 bit
 short					有  16 bit 
 ushort                无  16 bit
 int						有  32 bit 
 uint						无  32 bit
 long					有  64 bit 
 ulong					无  64 bit
 float					有  32 bit 
 double				有  64 bit 

 注:内部类型在函数中使用传值方式传递,其他类型传引用

其他类型:

class
interface
singleton			// 单例
TRUE		  真类型(用于推导)
FALSE		  假类型(用于推导)

语言级别支持的内部类

 Tuple			元组
 String			字符串
 Any			可变类型
 Func			函数对象
 Delay			延迟对象
 Delegate		委托(保留)

使用 const 来定义常量:

const pi=3.1415	// 注意:常量不需要类型定义

以及枚举:

enum MyEnum{ red=0, blue=2 }	// 枚举和 int 可以无缝转换

枚举使用时为:

MyEnum.red

变量

Si 语言中除了内置类型(整数和浮点),其他类型都保存在指针中。

定义变量可以用 var 来自动推导,用右值推断类型,甚至允许先定义,使用时再推导。

var i=10
var a
if(..){
	a = 30.0f
}

不过变量的类型是确定不变的。因此以下代码是错误的

var name = "Hei"			// 这里 name 自动成为 String 类型
name = 15			// 而这里会出错,因为 name 不能改变类型

另外,内部变量有初始值。

数组

除 singleton 外都可以定义成数组,数组有固定长度,有个默认打开的编译选项,会让越界访问抛出异常。 数组下标从0开始

int[] a=[ 0, 1 ]			// 数组可以直接初始化
var array2=int[10]          // 初始化一个空的数组  
int v=array2[1]      		// 数组取值

// 通过内置的 size 成员函数来获取数组的长度
var len = a.size()

当数组作为函数参数时,可以指定大小,也可以不指定:

func myFunc( int[20] array ){ ... }
func myFunc( int[] array ){ ... }

另外数组也支持切片

int[] s=arr[startIndex:length]

需要注意的是,切片是引用,因此如果源改变了,切片同样会改。

内部类 Any

Any类型可以保存任何值,并且保存类型信息。

Any 类型允许在运行期保存任何对象,可以判断它内部是什么类型。

Any i=20.0f    // 保存一个 float

然后你可以这样用

assert( i is Any )
when(i){   // 用 when 关键字进行运行期类型判断
	int : print(i)	// 在这个分支,i 被自动转换为 int 类型
	
	float : {
		// do float
	}
	default : {
		printf("unknown Type")
	}
}

Type type=i.type	// 获取类型(参见**反射**)
float x=i			// 或者 (float)i 强制获取 float 类型的值

但是,如果取值时,类型不一致,并且不能进行隐含转换,将抛出一个异常,这个过程是运行期的。

判断类型时,如果用 is,就是编译期的,用 when 就是运行期的。

分支

if 采用 c 的语法, 增强 switch。

switch 语法如下,支持多种数据以及多种比较,只要是测试相等就可以。冒号后如果是多行,需要大括号。

switch vegetable {
"celery": vegetableComment = "Add some raisins and make ants on a log."
"cucumber", "watercress": {
	vegetableComment = "That would make a good tea sandwich."
    comm : "多行需要大括号"
}
default: vegetableComment = "Everything tastes good in soup."

也可以使用范围

switch intValue {
	1..10:
		v="1 to 10"
	20..30:
		v="20 to 30"
}

元组

Si 语言中支持元组,替代 C++ 中的 pair, tuple。Si 里的元组用圆括号括起来,必须从明确的值创建,并且创建后 不可修改 元组必须在创建时赋值,并且值不可更改。可以通过 := 来解构,或者使用[]取值,元组可以参与编译期运算。

var a=(1, "second", x)				// 直接创建
print( a[0] )						// 取第一个值(注:[] 操作是编译期的)
if( a[1] is int ) print("yes")		// 通过索引取类型

for( var i : a ){					// 通过 for 循环,在编译期解开元组
	print( i )
}

var b0, b1 := a				// 元组的自动解构,注意复制的是引用,变量数量可以比实际的少,但不能多。
int c0, float c1 := (10, 10.0)

var c=(0)			// 这不是元组,c是 int 类型

另外,元组的成员也可以命名:

var tuple=( key=1, value=2 )
print( tuple.key )

循环

支持 while, for 循环,c 的语法。但不支持逗号多定义,多步进,不支持 do-while。 另外支持 for-each 形式

int[] arrays = {10, 20}
for( var i : arrays ){
	i = 30		// 将改变 arrays 的内容
}

作为一个语法糖,在循环内使用 free 语句释放迭代器,编译器会尝试调用容器的 remove 方法(如果有),将对象从容器中移除。remove 的返回值赋值给 i, 重新开始循环体 (continue)

for( var i : list ){
	free i
}

特别的,如果列表里保存的是元组(比如 map ),可以使用自动解构的语法

for( var k,v : map ){	// 同样,注意复制的是引用,因此改变 v 会改变 map 内的值
	map.remove(k)		// 这里不能用 free 了
}

字符串

在 Si 里的字符串类是个内部类型,String,字符串类内部维护字符串编码,一般情况下内部使用 UCS-4 存放

String eng="Hello world!"			// 纯英文字符串,直接创建为 utf-8 编码
String str="中文"							// 包含非 ascii, 使用 UCS-4 编码
ushort aChar=str[0]					// a='中', 直接取出,为 UCS-4 编码
String str( bytes, Charsets.utf8) )	// 通过 bytes 指定编码来创建
str.bytes()				    // 获取 byte,不指定编码,会默认返回 utf-8

也支持多行字符串:

string str="""Hello
	^ World ^
	! """
print(str)

输出:

Hello
 World
!

需要特别注意的是,多行字符串每行前后的空格将被忽略。 想加入前后空格,需要使用 ^ 标记起始位置。

另外,字符串也支持切片。

String s=str[0:1]	// 注意,这里不会复制内部字符串

字符串允许进行 + 操作,并且可以和整数、浮点数加,结果是字符串。

String s="" + 16		// 结果是字符串 "16"
s=R("Hello", "zhCN“)	// 从资源文件获取字符串

未来支持字符串模板

注意:字符串内容不能更改。 如果需要可变字符串,使用另一个兼容类 StringBuffer。

操作符

支持大部分 C++ 操作符,但是不支持前置 --, ++。 支持 >>> 运算符(无符号右移)

函数定义

函数这样定义

func first( int a ) : int {
	return a
}

调用时:

var x = first( 10 )

并且为了保证定义的清晰,如果省略返回值的定义,就是表示不返回。 参数允许可变参数,不过必须定义在函数的最后,也只允许一个可变参数.

另外允许多返回值,这时返回值会被包装为一个元组。 多返回值函数定义方式如下,返回值可以匿名也可以命名,命名的返回值在函数内可以直接作为变量操作.

func second( int a, var b, int ... args ) : int retval, int val {
	// 这里 args 被视为数组 array
	if( args.size > 0 )
		val = args[0]
	retval = a + b		// 直接操作返回值
	return	   // 可以省略
}

注意,返回值如果命名,那么在函数开始,就会调用无参数构造函数构造返回值,如果没有无参数构造函数, 编译会失败,可以使用 ? 定义为可空类型。

单行函数(语法糖)

func add(int a, int b) = a + b

单号函数使用推导获取返回值,必定有返回值,因此也不需要 return。

return

  • return 语句必须写在区块的最后,本区块后面不能有其他语句
  • 如果函数返回值都是命名的,那么可以不带后面的返回参数,特别的,没填充的变量会以默认值返回
  • 如果 return 后面带了返回参数,那么必须写全
  • 函数最后的 return 允许省略

可变参数可以是同一个类型的,或者使用 var 让它成为可变模板函数

func varFunc( int a, var ... args ){
	for( var i : args ){    // 这个 For 会在编译期被展开
		run(i)
	}
}

这个 for 循环会在编译时被展开成顺序的多个代码块。

函数可以使用返回元组的形式来返回多个变量,并且你可以用自动解构。

first, second := fun( 10, 20 )

返回值如果有非命名参数,那么必须写在列表的前面

func second( int a, var b ) : int, float, int {
	return 0, 15.0, 2	
}

传参

Si 语言中,传入的参数(包括 int 等内部参数)都被视为指针,因此它的内容可以在函数中可以被更改。

比如:

string old="Hello"
cut2(old)
print(old)	// 输出 "Hell"

另外,如果参数可以为 null, 需要使用 ? 明确指出

func third( int? a ) : int? {
	if(&a){
		return a+1;
	}
	return null;
}

参数中可以使用 var 关键字,这时候它同样被视为模板函数。 返回值也可以使用 var,这时通过 return 来推断返回值

func myFunc( var a, int b ) : var ret{
   return a+b   // 这时推断返回值为 int 类型
}

int x=myFunc( 10, 20 )

函数调用

函数使用比较宽松的调用形式,可以是顺序的,比如:

first, second = fun( 10, 20 )

或者命名的形式:

var v = fun( name="myname", value=20 )

也可以2者组合

fun( 10, 20, name="myname" )

但是有个约束,包括,顺序形式的必须在函数调用的开头。并且所有的参数(除非有默认参数)都必须充满。

下面的写法是非法的(除非第一个参数就是 name):

var v= fun( name="myname", 10, 20 )

函数对象、匿名函数

Si 在语言级别支持函数对象、匿名函数

var add=func(int a, int b) : int{ return a+b }	// 匿名函数
int a=add(10, 20)								// 执行

如果没返回值,没有参数,都可以省略

var my1=func(int a){ ... }		// 无返回值
var my2=func{ ... }					// 无参数、无返回值的函数
var my3=func{ return 10 }			// 返回值类型自动推导
func(int):float itIsAFunctor		// 明确的类型

特别的,操作符 -> 后面可以省略 func, 另外,string 也支持 -> 操作符,并且在定义时就会被调用, 这个特性可以用来写“函数块”

"块的注释"->{
	int a=0
}

推荐这样写函数块,以便让 IDE 实现函数内的块缩进。

同时,匿名函数是闭包的:

int myVal = 10;
var x=func(int a){ return a+myVal; }		// 注意这个 myVal 是引用,在匿名函数调用时取*当前*值

assert( x(20)==30 );

上面的代码演示了简单闭包,不过要注意的是,并行的情况下,myVal 可能被更改、互斥,这时候使用闭包需要特别小心。 另外,匿名函数里包含的是对象引用,因此如果在匿名函数里修改 myVal 的值,当匿名函数被调用时,myVal 就会被更改。 这点也需要注意。

异常

Si 支持的异常。

/// 语言内部异常,所有异常的基类
class Exception(
	string resource;	// 字符串资源 ID,默认会直接使用类名
}

// 定义一个异常
class IOException : Exception("IOException")		// 定义一个新异常
class HttpException : IOException{		// resource="HttpException"
	int code;
}

// 如果函数会抛出异常,那么必须要加 throws 描述
func( int ) : int
	throws CodeException, HttpException {
	if( false )
		throw HttpException{ code=404 }
	return 10
}

try{
	var a=func( 10 )
}catch( HttpException | IOException e ){	// catch 允许多个异常类型
	print( e.message )
}finally{
	// 最后会执行的代码
}

// 简化的异常处理格式,对函数的异常直接处理
var i=func( 10 ) catch (IOException e){
	String m = exception(e)
} catch(Exception e){
	print(e)
}

func(10) catch(Exception);	//明确忽略这个异常, 注意:分号不能省略

如果函数会抛出异常,那么必须处理,或者放函数 throws 签名中再抛出,或者用 try (包括简化语法) 处理。

空指针

某个默认打开的编译参数可以在运行时让空指针抛出 NullPointerException 异常,当然,这会略微的降低执行效率。 对于线程、协程,默认的处理方式就是输出错误日志,并退出线程。

?: 操作符可以在指针值为空时提供默认值

var a = mayNullOrInt() ?: 10

基础

每个文件(.sc)可以定义一个类。 si 中的类类似 Java。成员变量、方法只有公开包内的,公开的可以被包外访问, 否则只允许同名包或者子包内的方法访问。

包 org.first.second 是 org.first 的子包

代码开始

/* File MyCls.sc 开始 *
package org.jadedrip	// 定义包

class MyCls {	// 定义类
	init(){		    	// 无参数的构造函数
	}

	init(int a, int .value){ // 带参数的构造函数,参数前带.可以省略 this.value=value 的代码 
	}

	finalize{           // 析构函数始终是无参数的,不需要括号
	}

	clone{              // 克隆函数
		return MyCls(){
			this.key = clone(key)
			this.value = clone(value);
		};
	}

	int key = 1	// 创建时初始化(先于构造函数)
	int value			// 创建时默认为0

	func do_something(){
		this.key++  // this 是自己
	}
protected:	// 类中有且仅能有一个 protected 分割线,分割线上部的是公开的变量、方法,下部是
			// 保护的,只有在同一个类、子类或继承类内可以访问
	int? privateValue	// 可为 null 的变量
}

class MyDataClass( int a, int b ){	// 这里直接定义了主构造函数、内部变量为 a, b
	init(){	 // 主构造函数不包含函数体,因此无参数构造函数仍然会被调用(赋值后)
	
	}
}

继承&重载

继承和重载的概念被简化,类可以单一继承,并且不允许重载方法,当你需要一个可以重载的类、或者虚函数时,需要把它定义成函数对象。

class Base{
	func cantOverload(){	// 普通函数不可以重载

	}

	func( int v ) virtualFunction	// 定义一个函数对象,可以实现纯虚函数的功能

	var canOverload = func(int v){	// 以函数对象的语法定义函数,可以通过替换函数对象的方法达到重载的目的
		print(v)
		virtualFunction(v)	// 调用虚函数
	}
}

class Second : Base{        // 类可以继承,但只能单继承
	func cantOverload(){	  // 这会是个全新函数

	}

	virtualFunction=func(int v){	// 实例之
		print(v);
	}

	canOverload =  func(int v){
		canOverload(v)		// 这可以视为调用基类函数
	}
}

类的构造

对象构造使用构造函数的形式,括号不可省略。

var a=MyCls(10, 20)	// 通过构造函数构造,参数表使用逗号分割,当然可以 var 推断
var c=MyCls(){     		// 在构造时,后面直接接大括号,将在构造后,直接执行语句块
	key=0						// 在构造函数执行后执行
	val=20

}

对象不构造时,可以认为是一个指针:

MyCls? a;       // 这时 a 可以认为是指针,? 不可省略,表示对象被初始化为 null
a.var = 10      // 编译错误,构造前赋值

对象的传递,都是浅copy,除非明确指明复制

MyCls a=clone(b)	// clone 会调用复制函数进行深 copy。

对象可以被理解为都保存在智能指针中, 指针的赋值需要使用等号,并且指针不能进行任何运算,包括比较。 而操作符重载不能重载等号。 除了 &, = 等指针专用符号,其他一切符号,都是对对象的操作(操作符重载)。

if( &x ){			// 指针判断是否为存在
	x=Cs()          // 这里会改变 x 指向的对象
}

if( x == null ){    // 注意这种写法并非判断x是否为空,而是内部对象和 null 比对(或重载的 == 方法)
}

var a = Cs()
Cs b = a    // b 指向 a
b.val = 1   // 这里同时会改变 a 指向的对象值

Set 和 Get

类的成员变量支持 Set & Get 方法。

class MyClass{
	int a

	set a( int nv ){		// set, a=x 时调用
		print("New value:" + nv)
		a=nv
	}

	get a{          // 使用 var a=myClass.a 的代码时被调用
		return a		// 返回
	}
}

MyClass x
x.a = 10	// 这里就会调用 set a

循环解偶

两个类互相引用对方的情况是被禁止的(即使是间接引用)。但可以定义子类。 子类只允许在类内被构造,并且可以访问父类的变量。

class MyCls3{
	int var=0
	class SubCls{
		int subVar=2

		func incVar(){
			var+=subVar // 子类可以访问父类的成员变量
			super.print()  // super 是父类的指针
		}
	}

	SubCls cls=SubCls()

	func print(){
		Console.print(cls.subVar)
	}
}

垃圾收集、引用计数

默认情况下,类通过垃圾收集器/引用计数来管理内存。类可以包含析构函数,这时会使用引用计数的管理方式。 对于没有析构函数的类,默认使用 GC 来管理。

另外,支持手工管理,使用 new 关键字,new 生成的对象,必须使用 free 来释放

MyClass a=new MyClass()
free a				// 析构、删除对象,并清空指针
assert( !&a )

a.name = "Hello"	// 这里编译就会报错(使用未初始化的对象)

语法糖:对象作用区

通过在对象后直接挂接代码块,可以以这个对象为“基准”来执行代码。区块中的所有函数、变量会先在这个 对象内部查找。

var i=a{
	doSomething()
	name = "hello"
}

这相当于:

var i=a
a.doSomething()
a.name = "hello"

显式类型转换

除了默认类型转换,还可以使用下面的显式转换.

var a=(MyClass)b			// 尝试将 b 转换为 a
(MyClass)b.funcInMyClass()	// 先转换在调用
(MyClass)b{					// 转换在调用对象作用区
	funcInMyclass()
}

但显式转换也是有限制的,比如你并不能吧 int 转为一个不兼容对象。

单例

单例受到语言级别的支持。它的声明类似 class, 仅仅是把关键字 class 改为 singleton

////// 文件开始 ////////
package org.silang;
singleton MySingleton{	// 单例的公开定义部分
	void AstCallit(){}
}

单例会在首次被使用时,被线程安全的初始化,并且直到程序关闭时被析构。

MySingleton.AstCallit()

类型空指针

当一样参数为可空的,那么就可以通过 null 来初始化。

var? k = int	// 可以理解为 var? k = (int)null
k = 10
k = null
k = 20

模板

可以通过把类中的成员函数,定义为 var 来创建模板类,模板类必须在构造时,能推导所有模板成员的类型。

class MyMap(var? k, var? v){		// 允许使用空指针来初始化
	func templateFunc( var a ){		// 函数直接使用 var 来定义模板函数
		if( a is int ){		        // 这里的 is 是编译期的操作符,因此这里的 if 也是编译期的
									// 只有 a 的类型是 int 类型的,这个代码块才会编译
			a++
		}

		typeof(a) b?	            // b 定义为 a 相同的类型

		Type c=typeof(a)		 // Type 是种描述类型的特殊类型
		when( a ){				 // 用 when 判断类型
			int : {

			}
			float : {

			}
			default : {

			}
		}
	}
}

var my = MyMap("Hello",9) // 构造函数必须可以推导所有类型 var you = MyMap(1.0, 9) // 注意:typeof(my)!=typeof(you) var my2 = MyMap(int, string) // 使用类型空指针来初始化

类型定义 def

可以使用 def 来复制类型,可以认为是继承了一个新类

def AFun = func(int, int):int
def MapClass = MyMap(int, string)		// 定义模板函数(会虚拟的调用构造函数,以推断类中的模板参数)

var m = MyMap( 10, "Hi" )
def IntMap = m						// 可以理解为 def IntMap typeof(m) 的语法糖

def StringList = List(string)		// 其实是 def StringList typeof(List(string))
StringList myList				// 注意,myList 是 StringList 类型,而不是 List

需要注意的是,def 定义的类型是一个新类型,可以视为从原类型继承的类。

常量推导

如果常量传入模板函数,那么函数在编译器,就会被计算

func myTemp( var a ) : var c{
	if( a == 1 ){
		return a+10
	}else if(a=="Hello"){	// 传入 常量整数时,这分支都不会被编译
		return "World"
	}
}

myTemp( 10 )	// 在编译时不会生成函数,直接替换为 a+10

var x = 10
myTemp( x )		// 编译错误,传入的是变量,参数固定为 int

const y = "Hello"
myTems( y )		// 传入的是常量,按模板编译

类型操作符

Si 将支持一些类型操作符,结合模板,可以实现编译期编程。因此特别定义了两个内置类型·TRUE·和·FALSE·。

操作符 is

在编译期判断类型可以使用 is,语法是

A is B

结果将是内置类型 TRUE 或 FALSE。A 可以是变量,或者模板参数,B 为类型或接口。需要注意的是,这里并非要求 A,B 是完全一致的类型,当 B 是从 A 继承,或A实现了接口B,也将返回 TRUE。 但相对的,如果 A 和 B 都是模板类型,那么模板参数不一致(即使他们有继承关系),那也返回 FALSE

操作符 ===

在编译期判断类型是否相等

A === B

B 必须为类型或接口,A 可以是变量,或者模板参数,和 is 相近,但 === 要求类型完全相等。

操作符 if

当 if 后的括号内,是一个类型,那么它就成为一个编译期的类型操作符,仅当类型为 FALSE 时,编译 else 语句块, 其他任何类型都编译 then 语句块。

if(a == int){	// 当 a 类型为 int 时被编译
	int b = a+10
}else{
	a = "Hello"	// 虽然类型错误,但这里没编译,因此不会报错
}

操作符 `(反引号)

反引号将尝试从类型中按名称取出成员,如果成员不存在返回 FALSE,存在返回成员的类型。 这可以在编译期判断类是否包含某个成员。

 if( a`name` ) ...
 if( a`myfunc` && a`myfunc` is func(int, string):string ) ...

操作符 for

for 可以用来解开通过 ... 传入的多个参数等,也可以解开元组,这个过程是编译期的。

func my( var ... attrs ){
	for( var i: attrs ){
		// 这里 i 的类型会按输入变化
	}

	var x=( 10, 20, "Hello")
	for( var i: x ){
		print i
	}
}

操作符 ==,!=,||,&&

当两个常量进行布尔运算,他们也会在编译期运算为 TRUE 或 FALSE。

var a=(1==1)		// TRUE

接口

Si 可以通过 interface 关键字定义接口,接口所有的方法、变量都是公开的。 接口内的函数可以有默认实现。

接口可以直接用在函数、方法的参数上,它可以用来约束函数、方法的参数, 它实现了部分需要模板的功能,只要类实现了接口里的所有方法和变量,并且他们是公开的,那么就视为他实现了该接口,可以传送给接受该接口的方法。

比如

interface MyInterface{
	int a
	func getSome():int	// 这是个函数定义
}

void aFunc( MyInterface inc ){	// aFunc 实际上是一个模板函数。
	// 这样,任何对象,只要包含 int a 的成员变量,以及 getSome 这样一个方法,
	// 就可以被传入这个函数
}

需要注意的是,这是编译期的动作,接口被视为有约束的模板参数。 另外,比较简单的接口可以直接在参数中定义(匿名接口)

void aFunc( {int a; func getSome():int} inc ){
}

接口也可以用来明确的强制一个类去符合某种契约:

class MyCalss : Base, MyInterface{

}

模板推导函数

由于函数的返回值可以通过 return 来推导,因此可以通过写一个完全静态的函数,来实现计算类型的模板函数。

func TplFunc( var? a, var? b ) : var{
	if( a is int && b is int)
		return TRUE()		// 真类型,if( TRUE ) 永远真,并且在编译期就处理
	else
		return FALSE()
}

var a = 10, b=10
if( TplFunc(a,b) ){	// 静态语句,在编译期展开
	int c = 10
}

延迟优化

si 的函数参数,允许使用延迟生成的技术以优化效率。它让参数仅在被首次使用的时候,才会被生成它。 比如:

trans_data( get_data(), x)

而 trans_data 的代码如下:

func trans_data( var v, bool x ){
	if(x) print(v)
}

这段代码里,v 通过 get_data() 获取值,但在 trans_data 中,如果 x=false,v根本不会被使用。这个时候 get_data() 的调用 是完全没有必要的。而通过延迟生成技术,只有在v参数实际被使用时才会尝试“构造”它,因此,如果 x=false,get_data() 会被直接 放弃,生成的代码类似下面的

void trans_data( bool x ){
	if(x) print( get_data() )
}

要启用延迟优化,调用代码写成如下

trans_data( *[get_data()], x)

但需要注意,延迟优化只用于模板函数,因为编译器实际上是生成了一个 Delay 内部模板对象,传参如果类型是定的,Delay 对象会立刻解开,不会延迟。

其实也不一定用在函数里

Delay x=*[get_data()]		// 这时 get_date() 其实没有被执行
var k=x						// 这时才会执行,并且只会执行一次
var k2=x					// 注意,这里不会重复执行

线程

创建线程由线程库支持,类似 Java

Thread thread(daemon=true, level=3)
thread->{       // 运行线程
	aFunc()
}
thread.join()	 // 等待结束

而同时,Si 包含一个小的语言库,直接支持并行任务,并且尽可能自动维护。 在一个函数、区块调用前加上 go 关键字,这次调用就会在一个新的并行任务中并发执行。 当被调用的函数返回时,这个并行任务也自动结束。需要注意的是,如果这个函数有返回值, 那么这个返回值会被包装为 Chan。

go{	// 通过go来创建一个并行任务
	print( "go" )
}

go dosomthing()		// 并行执行函数

Barrier()->{					    // 通过一个内存栅栏,保证并行项都执行完毕后才进行下一步
	for( int i; i<10; ++i ) go{	// 并行任务
		dosomething(i)				// 这个函数会被并行执行(OpenMP)
	}
}

Si 通过库来支持管道(Chan),以便实现异步数据交换。 管道可以输入输出多次,并且可取消。

Chan s=Chan(int)
go{				 // 并行执行语句块
	s <- i		 // 写入管道,这里会阻塞,直到值被取出
}

go{
	sleep(1000)
	if( s.cancel() ){	// 交换器可以取消,取消成功返回 true, 而如果管道已经被使用,那么返回 false
		// 超时代码
	}
}

可以明确的“等待异步线程事件”完成

var a = *s       // 从管道取出值,这里会被阻塞,直到有值

或者异步等待

s->int a{		 // 异步输出,回调函数会在有输入时被调用。另外,这是缩写(语法糖),完整的写法是 s->func(int a)
	print a;
}

使用 go 调用的函数,如果有返回值,会自动包装为 Chan,并且返回值自动输入

func inThread( int a, int b ) : int s {
	...
	return a;   //
}

Chan x=go inThread(10, 20);
x->var a{		// 异步返回的值写入 a 并执行后面的代码块
	...			// 需要特别注意的是,管道输出后执行的代码块,
				// 是在**异步线程**内执行的
}

另外,管道输出只能选择一种,同时使用同步和异步取,会导致编译错误。

如果需要锁,代码如下

Mutex myMutex=Mutex()			// 定义一个锁
myMutex -> {
	// 锁内
}													// 这里解锁

原子操作由库来支持:

var a=Atomic(10)	// 原子的 int
int v=a++           // 原子的 +1 并返回新值
int cur=a.compareAndSet( 11, newValue );

import

Si 通过 import 导入包

import org.silang.net import ( // 导入多个 org.silang.math.sin org.silang.io.print )

注意:import 只能写在文件头部,package 定义之下

和其他语言协作

可以引入 c 或其他语言写的库会被编译成包,以便被 Si 调用。Si 语言可以输出标准 c 函数,以便被其他语言调用。 lib 文件、需要对应的头文件及适配文件等需要的东西,会被某个处理软件打成一个包,并放在编译程序能找到的地方。 而 Si 可以编译成 c lib, 函数会按约定转换成 c 的格式。

备选(思考中)

交叉类型

交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一 起成为一种类型,它包含了所需的所有类型的特性。

var a = (MyClass & Second)()	// 实际类型为 Intersection<MyClass, Second>

a 可以直接使用 MyClass 和 Second 内的属性,方法,特别的,如果 MyClass 和 Second 中有重复的属性或方法,可以这样使用:

(MyClass)a.funcInMyclass()
var b = (MyClass)a

操作符重载

Si 支持有限的操作符重载。对于类内的操作符,可以通过一个函数重载

class MyClass{
	operator + ( int right ){	// 二元操作符的函数重载(默认的返回 MyClass 类型)
		return this
	}

	operator ++{					// 自增在后
		// return this 可省略
	}
}

operator + ( int left, MyClass cls ) : MyClass{	// MyClass 在操作符的右边
}

注解、反射

si 支持注解及反射。(抄 Java)

class MyClass{
	@ReflectName( name="value", idx=12 )	// 使用注解对象来进行注解
	int a ;

	void doFun(){
	}
}

Package pkg=Reflect.packages["org.example"];		// 获取包
Type cls=typeof(MyClass);						      // Type 描述类型

Type cls=Reflect.classes["org.example.MyClass"];	// 通过全名获取

Type cls=pkg.classes["MyClass"];					           // 通过包获取对象

for( string name, field v : cls.fields ){
	var annotation=v.annotations;				// 获取注解
}

注:Reflect 其实是一个语言支持的单例,因此如果程序中没有使用到它,那么它并不会初始化。

C 对象定义

@Clang("my_c_object")
class MyCObject
{
    func at( int idx ) : char;  // int my_c_object_at( my_c_object* me, int idx );

    @Clang("add")
    operator + ( MyCObject other ) : MyCObject // my_c_object* my_c_object_add(my_c_object* me, my_c_object* other);
}
Copyright (c) 2014, jadedrip All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the {organization} nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

简介

git://git.coding.net/jadedrip/Silang.git 展开 收起
C++
BSD-3-Clause
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
C++
1
https://gitee.com/treert/silang.git
git@gitee.com:treert/silang.git
treert
silang
silang
om_learn

搜索帮助