青语言开发文档

第三步:语境初始化

创建于 2023-04-27 / 最近更新于 2023-04-28 / 1565
字体: [默认] [大] [更大]

青语言解释器用于执行青语言代码,那么除了记录用户自定义的变量和函数之外,还需要提供基础的程序功能,青语言中主要以内置函数的方式来提供支持。

上一节我们提到了语境用于记录变量,事实上函数的记录方式和变量一致,也是记录在语境中。(本质上变量和函数都是青语言中的Expr,只是我们在语法上要求变量以#开头,而函数以@开头,这主要是为了提高代码的可读性)

内置的原生函数也记录在语境中,只不过记录的位置是一个特殊的语境,也就是我们之前说的只读的库语境。因为这些基础的函数十分重要,所以我们不希望在程序运行期间遭到篡改。

由于程序的执行依赖于这些内置的原生函数,所以在执行青语言代码前,我们还需要为用户准备好库语境。
首先我们来再来看原生函数的定义:

public abstract class Native {
        public Ctx? Ctx { get; set; } = null;
        public abstract string Name { get; set; }
        public abstract string Desc { get; set; }

        /*
         * 原生函数调用时调用的方法
         * 返回值是Expr
         * 参数列表是List<Expr>
         * 函数运行的父语境ctx
         * 对于原生封装的对象,通过obj传入
         */
        public abstract Expr Run(List<Expr> args, Ctx ctx, Obj? obj=null);

    }

所有的原生函数都继承自Native类,其中Name为函数名,Desc为函数描述,调用时执行Run方法,所有的原生函数功能均通过Run方法对接青语言,入参List<Expr> args,返回Expr

青语言内置的原生函数都定义于Std文件夹中,均继承了Native类,函数手册见《青语言使用文档—内置函数》

定义完内置函数后,我们还需要将内置函数添加到语境中,统一的初始化方法位于Std/Init.cs

public class StdInit {
        /*定义好的原生函数,通过初始化方法添加到语句中*/
        public static void InitStd(Ctx ctx) {

            ctx.PutNow("@退出", new Expr(new Quite()));
            ctx.PutNow("@显示", new Expr(new Print()));
            ……

这里的InitStd方法只要传入一个语境,就会将所有的内置原生函数绑定到这个语境中。

对于青语言解释器,我们在Program.cs文件中初始化了库语境

/*创建一个语境作为最顶层的库语境*/
            Ctx libCtx = new Ctx();
            /*在库语境中初始化标准库原生函数*/
            StdInit.InitStd(libCtx);
            /*在库语境中初始化扩展原生函数*/
            ExtInit.InitExt(libCtx);
            /*在库语境中执行初始化脚本*/
            Expr.EvalExprs(new Parser().Parse(InitScript.Script, libCtx), libCtx);
            /*把库语境放入全局Env*/
            Env.LibCtx = libCtx;

            /*创建一个语境作为用户语境,其父语境为库语境*/
            Ctx usrCtx = new Ctx(libCtx);
            /*把用户语境放入全局Env*/
            Env.UsrCtx = usrCtx;

这里我们初始化了libCtx作为库语境,然后另外创建了一个usrCtx用户语境,交给用户使用。


上面的代码中,我们还使用了ExtInit.InitExt(libCtx);初始化扩展原生函数,这是我们为开发者预留的扩展功能。
如果你需要以原生函数的方式扩展青语言的功能,那么请仍然以继承Native的方式,在Ext文件夹中实现你扩展的函数,然后在Ext/Init.cs中添加扩展原生函数的绑定(参照文件中的例子即可)。


除了原生函数的方式,我们在初始化解释器的过程中,还运行了一段青语言脚本,定义在Script/InitScript.cs中,这是从青语言的层面上进行的初始化操作。

0 人点赞过