试着设计一个自己的语言
1.最重要的一点是一致性(初版本先用自然语言的形式设计语法)
2.优雅(先实现一版,后续改进)
3.静态类型
4.自然语言的语法,且容易转换为中文表述
5.可扩展,即初期肯定不会实现很多功能,后面要加的功能不能加上来和现有的设计不一致
大概设想:
注释和java的保持一致,但是支持
/*
* 这种方式的注释,即非方法/字段/类上的文档注释,是方法里面的多行描述的注释
*/
变量和方法都用小驼峰;
类名/接口名用大驼峰
还支持一个any关键字用于联合任意类型(因为这里不准备设计为一切皆对象),但是any类型不是动态类型,必须主动as转换后使用;
关键字如果是多个单词构成用-来连接;至于a-b即a变量减去b变量不用担心,一来是一开始要求中间必须有空格,即a - b,所以不会和关键字有冲突;二来
如果用户定义了end变量和loop变量,也确实要执行它们的减法,语法检查也是能检查它到底是关键字还是两个变量相减;
而且它们编译成字节码后,是会变成其他的形式从而加速ast的构建,比如next-round可能会变成##next_round##【感觉我应该先设计字节码。。】
var和final和const分别对应变量,只读变量和常量(“字面量”,注意复杂类型对象也可以有字面量,参考dart)
类型/泛型/接口名必须是大驼峰,不符合条件的不允许通过编译;
一:循环(类似java的for循环,如果涉及变量定义,则这里必须是var不能是final和const因为没有意义)
loop var a = 1, when a > outList.length, ne\
xt-round a++
// logic code
// 支持break和continue
end-loop
描述:上面的ne\的\和C++里的换行拼接一样,这里要求\后面不能有任意字符,
然后\的下一行以行首第一个字符拼接到上一行\前面一个字符的后面,这个是编译期间的事情
这里var表示在loop所在的作用域里定义了一个a变量初始化为1(如果没有var而是直接a = 1则会往上面的作用域找a变量),类型是Int(自动整型)
,如果要手动指出是什么类型可以用var a I32 = 1
when就是如果/当 的意思,在loop里表示循环成立的条件,而next-round下一轮;
二:循环2(类似java的while循环)
loop when outVar > 0
end-loop
三:循环3(类似do-while)
loop
end-loop when a > 9
四:开启作用域(类似java的{。。。})
scope
end-scope
五:如果定义的变量或方法和关键字冲突,可以用#开头
var #loop UInt = 9【但是如果后面支持反射,反射获取字段名#loop是只需要类似type.getField("loop"),因为#loop只是编译层面的处理】
六:if条件
if a > 9
...
end-if
if a > 9
...
else-if a < 6
...
else
...
end-if
七:case when条件(类似switch)
case outVal
when 3:
do3()
// 注意,这里会自动break,和java不同,如果要延续到下一轮,
手动写明continue【所以循环和case-when在一块时会有想continue到外层的循环却做不到的情况,得需要支持label】
when 4:
do4()
continue
when 5:
do5()
default:
doDefault()
end-case
case opt【会先进行类型判断,然后再进行匹配这个Duration的构造方法的inDays参数的判断】
when Duration(inDays: 1):
doSome1()
when Duration(inDays: 2):
doSome2()
when Duration(inDays: var tmp):【可以主动写明类型,即var tmp Int】
doSomeTmp(tmp)
default:
doNone()
end-case
八:空安全,支持Foo?表示某个变量可以承载Foo对象和null,且Foo?声明的变量或字段可以不初始化默认是null,null有类型且只有一个值
,它的值toString()后是null做特殊化;
九:泛型(暂时先不提供原始类型,即都是类,包括Int32,Int,UInt,UInt32【但要实现享元模式】
除了可空字段,其他字段都必须要通过构造方法初始化
define class Foo<T1, T2>
// static的字段必须在定义时初始化,static的字段是在初始化Foo这个类型后立刻初始化的,所以必须快,不支持做复杂业务的初始化
private static name String = 'fff'
public age Int32?
public aa T1
private bb T2【先不支持继承,所以暂时不需要有受保护访问权限】
// 如果构造方法是私有的,则Foo必须在里面提供一个静态方法来创建Foo对象返回出去
private new(aa T1, bb T2)
self.aa = aa
self.bb = bb
end-new
// 不是static的方法能通过self关键字拿到对象的实例属性
private function instanceMethod(aa T1): String
var f = 9
f++
if self.age != null
f += self.age
end-if
return f.toString()
end-function
public static function staticMethod(): String
return name
end-function
end-define
define class Bar extends Foo<Int32, UInt32>
private age Int32
public constructor()
// 所以父类其实可以理解为在子类里自动加了一个super的字段,它指向了父类的那块空间,因此如果和父类有相同字段是不会合并的
// 因为继承并不是对结构的一个扩展;当然程序会记录父类和子类的关系,然后可以将父类赋值给子类变量;这个是和go不一样的
super(-4, 88)
self.age = 33
end-constructor
end-define
十:接口interface
提供一个空协议,所有类型都实现了这个协议(像go的interface{}),用它类实现类似any的效果,
但是它只能用于承载赋值,不能用于业务处理,业务处理前需要as强转某种类型
空协议为interface{},如define func fff(kk interface{})
// 协议暂时只支持实例方法,且必须是public的,所以没有必要写访问限定符
define interface IFly
function fly(aa interface{}): Int32
end-define
后面可以考虑支持静态接口方法,这样mm(obj: Fly)如果里面要调用静态协议方法则必须obj.class.staticMethodInFly()
即对象是不能直接调用对象类型的静态方法的,但是可以通过obj.class.staticMethod来调用
十一:当前由于Int等都是类,所以可以认为所有的类都extends Object(extends是扩展,implements是实现)
,所有的类型都实现了空协议(空接口)interface{}
十二:抽象类
抽象类不能实例化,且可以拥有protected/public的抽象方法,但是注意,抽象类如果实现了接口,这个接口方法只能是public的不能改成更小的访问权限;
define abstract class Foo implements IFly【类型要不Int是平台相关,然后Int32,Int8,UInt8,Float,Double,这样就不会和接口命名规范重合了】
// static的字段必须在定义时初始化,static的字段是在初始化Foo这个类型后立刻初始化的,所以必须快,不支持做复杂业务的初始化
private static name String = 'fff'
public age Int32?
// 如果构造方法是私有的,则Foo必须在里面提供一个静态方法来创建Foo对象返回出去
private new(age: Int32)
self.age = age
end-new
// 为了能实现模板方法模式,抽象类的抽象方法要能支持受保护的类型,当然也可以public,private是不行的。
protected abstract function staticMethod(): String
// 必须是public,且抽象类要么不出现fly方法,要么就必须实现它,这点和java一样就行;而实例类则必须实现
// 然后不允许写一个和fly同名的非override方法
public override function fly(): void
println("发生激烈")
end-function
end-define
本质上不存在所谓实例方法,所有的实例方法其实都是增加了一个隐藏的Self类型的参数而已,而Self类型则是这个方法定义所在的类;比如
Foo.test(fooObj, realArg),Bar.test(barObj, realArg),所以IFly fly = new Foo();fly.fly(realArg)其实是Foo会判断它确实实现了IFly接口
,然后从上往下找fly(realArg)的实现类,发现Foo自己就实现了fly方法,然后就执行Foo.fly(foo, realArg)方法;
所以注意不存在所谓方法覆盖,只是选择方法优先级不同
函数参数支持默认值和命名参数
posted on 2023-12-02 11:14 Silentdoer 阅读(4) 评论(0) 编辑 收藏 举报