当前位置: 首页 > article >正文

Banana JS,一个严格子集 JavaScript 的解释器

项目地址:https://github.com/shajunxing/banana-js

请添加图片描述

特色

我的目标是剔除我在实践中总结的JavaScript语言的没用的和模棱两可的部分,只保留我喜欢和需要的,创建一个最小的语法解释器。只支持 JSON 兼容的数据类型和函数,函数是第一类值,函数支持闭包。我不喜欢面向对象编程,所以所有与类相关的内容都不支持。没有任何内置不可删除的全局变量、全局函数或对象成员,哪怕解释器初始化的时候加入的内容都可以在任何时候轻松删除,恢复到空空如也的状态。

构建

本项目兼容 C89,没有其他依赖,甚至不需要 make 系统,只需要 C 编译器,目前在 msvc 和 mingw 上测试过。首先,下载我的另一个项目 Banana Make,这是一个单独的文件 make.h,然后打开 make.c,修改 #include 为正确的路径,然后使用 msvc 输入 cl make.c && make.exe release,或者使用 mingw 输入 gcc -o make.exe make.c && ./make.exe release。除了release编译模式之外,还有debugndebug另外两个模式,分别表示保留调试符号并显示日志输出,以及保留调试符号但是隐藏日志输出。可执行文件位于 bin 文件夹中,包括 REPL 环境、脚本执行器、一个有趣的玩具计算器和词法语法解析器测试工具。

语法

数值类型为null、boolean、number、string、array、object、functiontypeof的结果严格对应这些名字。不支持 undefined,因为 null 已经足够。数组和对象是干净的,没有预定义的成员,比如原型。

变量声明使用 let,所有变量都是局部变量。访问未声明的变量会引发错误,访问数组/对象不存在的成员会返回 null。不支持 const,因为它没有意义。例如,一个常量指向一个数组/对象,那么它的成员是否应该不可变?如果不是,那我为什么要使用 const?如果是,那值必须被标记为不可变,但这在垃圾回收器的视角下显得很奇怪,因为所有的值都应该是可清理的。

函数定义支持默认参数 param = value 和剩余参数 ...params。数组字面量和函数调用支持扩展语法 ...,不会跳过null成员。函数中没有 this, arguments

运算符遵循严格规则,没有隐式转换。只有布尔值可以进行逻辑运算。== != 是严格意义上的比较,可以应用于所有类型。字符串支持所有关系运算符和 +。数字支持所有关系和数值运算符。运算符的优先级从低到高为:

  • 三元运算符 ? :
  • && ||
  • == != < <= > >=
  • + -
  • * / %
  • 前缀运算符 + - ! typeof
  • 数组/对象成员访问和函数调用运算符 [] . ?. ()

赋值表达式 = += -= *= /= %= ++ -- 不返回值。不支持逗号表达式 ,

ifwhiledo whilefor 的条件必须是布尔值。for 循环仅支持以下语法,[] 表示可选部分。for infor of 只处理非 null 的成员:

  • for ([[let] variable = expression ] ; [condition] ; [assignment expression])
  • for ([let] variable in array/object)
  • for ([let] variable of array/object)

不支持模块。在解释器的视角中,源码只是一个大的平坦文本。

垃圾回收是手动的,你可以在你需要的任何时候执行。

delete 语义和JavaScript不同,JavaScript删除的是对象成员,但这毫无意义,因为只需要把它们置为null即可。在这里delete可以删除当前堆栈层级的局部变量。比如,可以配合垃圾收集器把执行环境清空得一点不剩。再比如,加入函数闭包的变量是返回之前的所有局部变量,可以在返回之前delete掉用不到变量以减少闭包大小,在REPL环境里执行以下两条语句,可以看到区别。

  • let f = function(a, b){let c = a + b; return function(d){return c + d;};}(1, 2); dump(); print(f(3)); delete f;
  • let f = function(a, b){let c = a + b; delete a; delete b; return function(d){return c + d;};}(1, 2); dump(); print(f(3)); delete f;

标准库以及与C语言的互操作性

所有值都是 struct js_value * 类型,你可以通过 js_xxx_new() 函数创建,xxx 是值类型,你可以直接从这个结构体中读取 C 值,参见 js.h 中的定义。所有创建的值都由此引擎的核心上下文 struct js * 管理,遵循垃圾回收规则。不要自己 free() 它们,也不要直接修改原始类型 null boolean number string,如果你想得到一个不同的值,就创建一个新值。复合类型 array object 可以通过 js_array_xxx() js_object_xxx() 函数进行修改。

C 函数必须是 void (*)(struct js *) 格式,使用 js_cfunction_new() 来创建 C 函数值,是的,当然它们都是值,可以放在任何地方,例如,如果使用 js_variable_declare() 放在堆栈根上,它们就是全局的。在 C 函数中,传入的参数可以通过 js_parameter_length() js_parameter_get() 函数获取,返回值只需放入 struct js *result 成员即可。


http://www.kler.cn/a/528083.html

相关文章:

  • C++ list
  • DBeaver连接MySQL提示Access denied for user ‘‘@‘ip‘ (using password: YES)的解决方法
  • OpenCV:闭运算
  • Teleporters( Educational Codeforces Round 126 (Rated for Div. 2) )
  • 你了解哪些Java限流算法?
  • STM32CubeMX6.13.0打开后不显示界面,但是任务管理器显示该程序正在运行
  • Java小白入门教程:数组(多维数组)
  • 【AI绘画】MidJourney关键词{Prompt}全面整理
  • Java 中线程的使用
  • 独立游戏RPG回顾:高成本
  • hive为什么建表,表存储什么
  • neo4j-community-5.26.0 create new database
  • Kafka SSL(TLS)安全协议
  • LeetCode:322.零钱兑换
  • el-table组件样式如何二次修改?
  • 【Linux】CentOS8虚拟机的基本环境配置
  • python中的if判读
  • C语言基础5
  • javascript-es6(三)
  • vscode script 中间的function import等关键字 先高亮,然后又灰了,并且按ctrl+/ 注释以html的形式,导致报错处理
  • 前端八股CSS:盒模型、CSS权重、+与~选择器、z-index、水平垂直居中、左侧固定,右侧自适应、三栏均分布局
  • 9.2k star!PiliPala一个第三方B站客户端!
  • 【LLM-agent】(task4)搜索引擎Agent
  • 知识管理平台如何实现企业知识共享与创新能力的全面提升
  • 【PHP】基于 PHP 的图片管理系统(源码+论文+数据库+图集)【独一无二】
  • DNS缓存详解(DNS Cache Detailed Explanation)