Silentdoer

导航

试着设计一个自己的语言

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编辑  收藏  举报